diff --git a/jdk/src/share/classes/java/util/logging/LogManager.java b/jdk/src/share/classes/java/util/logging/LogManager.java index 717e52990e1..8596cbeb8fe 100644 --- a/jdk/src/share/classes/java/util/logging/LogManager.java +++ b/jdk/src/share/classes/java/util/logging/LogManager.java @@ -144,7 +144,7 @@ import sun.misc.SharedSecrets; public class LogManager { // The global LogManager object - private static LogManager manager; + private static final LogManager manager; private Properties props = new Properties(); private final static Level defaultLevel = Level.INFO; @@ -156,8 +156,10 @@ public class LogManager { // LoggerContext for system loggers and user loggers private final LoggerContext systemContext = new SystemLoggerContext(); private final LoggerContext userContext = new LoggerContext(); - private Logger rootLogger; - + // non final field - make it volatile to make sure that other threads + // will see the new value once ensureLogManagerInitialized() has finished + // executing. + private volatile Logger rootLogger; // Have we done the primordial reading of the configuration file? // (Must be done after a suitable amount of java.lang.System // initialization has been done) @@ -169,58 +171,35 @@ public class LogManager { private boolean deathImminent; static { - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - String cname = null; - try { - cname = System.getProperty("java.util.logging.manager"); - if (cname != null) { - try { - Class clz = ClassLoader.getSystemClassLoader().loadClass(cname); - manager = (LogManager) clz.newInstance(); - } catch (ClassNotFoundException ex) { - Class clz = Thread.currentThread().getContextClassLoader().loadClass(cname); - manager = (LogManager) clz.newInstance(); - } + manager = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public LogManager run() { + LogManager mgr = null; + String cname = null; + try { + cname = System.getProperty("java.util.logging.manager"); + if (cname != null) { + try { + Class clz = ClassLoader.getSystemClassLoader() + .loadClass(cname); + mgr = (LogManager) clz.newInstance(); + } catch (ClassNotFoundException ex) { + Class clz = Thread.currentThread() + .getContextClassLoader().loadClass(cname); + mgr = (LogManager) clz.newInstance(); } - } catch (Exception ex) { - System.err.println("Could not load Logmanager \"" + cname + "\""); - ex.printStackTrace(); } - if (manager == null) { - manager = new LogManager(); - } - - // Create and retain Logger for the root of the namespace. - manager.rootLogger = manager.new RootLogger(); - // since by design the global manager's userContext and - // systemContext don't have their requiresDefaultLoggers - // flag set - we make sure to add the root logger to - // the global manager's default contexts here. - manager.addLogger(manager.rootLogger); - manager.systemContext.addLocalLogger(manager.rootLogger, false); - manager.userContext.addLocalLogger(manager.rootLogger, false); - - // Adding the global Logger. Doing so in the Logger. - // would deadlock with the LogManager.. - // Do not call Logger.getGlobal() here as this might trigger - // the deadlock too. - @SuppressWarnings("deprecation") - final Logger global = Logger.global; - global.setLogManager(manager); - - // Make sure the global logger will be registered in the - // global manager's default contexts. - manager.addLogger(global); - manager.systemContext.addLocalLogger(global, false); - manager.userContext.addLocalLogger(global, false); - - // We don't call readConfiguration() here, as we may be running - // very early in the JVM startup sequence. Instead readConfiguration - // will be called lazily in getLogManager(). - return null; + } catch (Exception ex) { + System.err.println("Could not load Logmanager \"" + cname + "\""); + ex.printStackTrace(); } - }); + if (mgr == null) { + mgr = new LogManager(); + } + return mgr; + + } + }); } @@ -235,6 +214,7 @@ public class LogManager { this.setContextClassLoader(null); } + @Override public void run() { // This is to ensure the LogManager. is completed // before synchronized block. Otherwise deadlocks are possible. @@ -270,13 +250,104 @@ public class LogManager { } } + /** + * Lazy initialization: if this instance of manager is the global + * manager then this method will read the initial configuration and + * add the root logger and global logger by calling addLogger(). + * + * Note that it is subtly different from what we do in LoggerContext. + * In LoggerContext we're patching up the logger context tree in order to add + * the root and global logger *to the context tree*. + * + * For this to work, addLogger() must have already have been called + * once on the LogManager instance for the default logger being + * added. + * + * This is why ensureLogManagerInitialized() needs to be called before + * any logger is added to any logger context. + * + */ + private boolean initializedCalled = false; + private volatile boolean initializationDone = false; + final void ensureLogManagerInitialized() { + final LogManager owner = this; + if (initializationDone || owner != manager) { + // we don't want to do this twice, and we don't want to do + // this on private manager instances. + return; + } + + // Maybe another thread has called ensureLogManagerInitialized() + // before us and is still executing it. If so we will block until + // the log manager has finished initialized, then acquire the monitor, + // notice that initializationDone is now true and return. + // Otherwise - we have come here first! We will acquire the monitor, + // see that initializationDone is still false, and perform the + // initialization. + // + synchronized(this) { + // If initializedCalled is true it means that we're already in + // the process of initializing the LogManager in this thread. + // There has been a recursive call to ensureLogManagerInitialized(). + final boolean isRecursiveInitialization = (initializedCalled == true); + + assert initializedCalled || !initializationDone + : "Initialization can't be done if initialized has not been called!"; + + if (isRecursiveInitialization || initializationDone) { + // If isRecursiveInitialization is true it means that we're + // already in the process of initializing the LogManager in + // this thread. There has been a recursive call to + // ensureLogManagerInitialized(). We should not proceed as + // it would lead to infinite recursion. + // + // If initializationDone is true then it means the manager + // has finished initializing; just return: we're done. + return; + } + // Calling addLogger below will in turn call requiresDefaultLogger() + // which will call ensureLogManagerInitialized(). + // We use initializedCalled to break the recursion. + initializedCalled = true; + try { + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Object run() { + assert rootLogger == null; + assert initializedCalled && !initializationDone; + + // Read configuration. + owner.readPrimordialConfiguration(); + + // Create and retain Logger for the root of the namespace. + owner.rootLogger = owner.new RootLogger(); + owner.addLogger(owner.rootLogger); + + // Adding the global Logger. + // Do not call Logger.getGlobal() here as this might trigger + // subtle inter-dependency issues. + @SuppressWarnings("deprecation") + final Logger global = Logger.global; + + // Make sure the global logger will be registered in the + // global manager + owner.addLogger(global); + return null; + } + }); + } finally { + initializationDone = true; + } + } + } + /** * Returns the global LogManager object. * @return the global LogManager object */ public static LogManager getLogManager() { if (manager != null) { - manager.readPrimordialConfiguration(); + manager.ensureLogManagerInitialized(); } return manager; } @@ -295,6 +366,7 @@ public class LogManager { try { AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override public Void run() throws Exception { readConfiguration(); @@ -304,8 +376,7 @@ public class LogManager { } }); } catch (Exception ex) { - // System.err.println("Can't read logging configuration:"); - // ex.printStackTrace(); + assert false : "Exception raised while reading logging configuration: " + ex; } } } @@ -392,7 +463,7 @@ public class LogManager { } // LoggerContext maps from AppContext - private static WeakHashMap contextsMap = null; + private WeakHashMap contextsMap = null; // Returns the LoggerContext for the user code (i.e. application or AppContext). // Loggers are isolated from each AppContext. @@ -414,10 +485,7 @@ public class LogManager { context = contextsMap.get(ecx); if (context == null) { // Create a new LoggerContext for the applet. - // The new logger context has its requiresDefaultLoggers - // flag set to true - so that these loggers will be - // lazily added when the context is firt accessed. - context = new LoggerContext(true); + context = new LoggerContext(); contextsMap.put(ecx, context); } } @@ -427,9 +495,14 @@ public class LogManager { return context != null ? context : userContext; } + // The system context. + final LoggerContext getSystemContext() { + return systemContext; + } + private List contexts() { List cxs = new ArrayList<>(); - cxs.add(systemContext); + cxs.add(getSystemContext()); cxs.add(getUserContext()); return cxs; } @@ -450,7 +523,7 @@ public class LogManager { Logger result = getLogger(name); if (result == null) { // only allocate the new logger once - Logger newLogger = new Logger(name, resourceBundleName, caller); + Logger newLogger = new Logger(name, resourceBundleName, caller, this); do { if (addLogger(newLogger)) { // We successfully added the new Logger that we @@ -477,7 +550,7 @@ public class LogManager { Logger demandSystemLogger(String name, String resourceBundleName) { // Add a system logger in the system context's namespace - final Logger sysLogger = systemContext.demandLogger(name, resourceBundleName); + final Logger sysLogger = getSystemContext().demandLogger(name, resourceBundleName); // Add the system logger to the LogManager's namespace if not exist // so that there is only one single logger of the given name. @@ -501,6 +574,7 @@ public class LogManager { // if logger already exists but handlers not set final Logger l = logger; AccessController.doPrivileged(new PrivilegedAction() { + @Override public Void run() { for (Handler hdl : l.getHandlers()) { sysLogger.addHandler(hdl); @@ -519,24 +593,52 @@ public class LogManager { // 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 { + class LoggerContext { // Table of named Loggers that maps names to Loggers. private final Hashtable namedLoggers = new Hashtable<>(); // Tree of named Loggers private final LogNode root; - private final boolean requiresDefaultLoggers; private LoggerContext() { - this(false); - } - private LoggerContext(boolean requiresDefaultLoggers) { this.root = new LogNode(null, this); - this.requiresDefaultLoggers = requiresDefaultLoggers; + } + + + // Tells whether default loggers are required in this context. + // If true, the default loggers will be lazily added. + final boolean requiresDefaultLoggers() { + final boolean requiresDefaultLoggers = (getOwner() == manager); + if (requiresDefaultLoggers) { + getOwner().ensureLogManagerInitialized(); + } + return requiresDefaultLoggers; + } + + // This context's LogManager. + final LogManager getOwner() { + return LogManager.this; + } + + // This context owner's root logger, which if not null, and if + // the context requires default loggers, will be added to the context + // logger's tree. + final Logger getRootLogger() { + return getOwner().rootLogger; + } + + // The global logger, which if not null, and if + // the context requires default loggers, will be added to the context + // logger's tree. + final Logger getGlobalLogger() { + @SuppressWarnings("deprecated") // avoids initialization cycles. + final Logger global = Logger.global; + return global; } 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, null); + final LogManager owner = getOwner(); + return owner.demandLogger(name, resourceBundleName, null); } @@ -548,10 +650,10 @@ public class LogManager { // or getLoggerNames() // private void ensureInitialized() { - if (requiresDefaultLoggers) { + if (requiresDefaultLoggers()) { // Ensure that the root and global loggers are set. - ensureDefaultLogger(manager.rootLogger); - ensureDefaultLogger(Logger.global); + ensureDefaultLogger(getRootLogger()); + ensureDefaultLogger(getGlobalLogger()); } } @@ -580,13 +682,13 @@ public class LogManager { // before adding 'logger'. // private void ensureAllDefaultLoggers(Logger logger) { - if (requiresDefaultLoggers) { + if (requiresDefaultLoggers()) { final String name = logger.getName(); if (!name.isEmpty()) { - ensureDefaultLogger(manager.rootLogger); - } - if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) { - ensureDefaultLogger(Logger.global); + ensureDefaultLogger(getRootLogger()); + if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) { + ensureDefaultLogger(getGlobalLogger()); + } } } } @@ -598,8 +700,8 @@ public class LogManager { // This check is simple sanity: we do not want that this // method be called for anything else than Logger.global // or owner.rootLogger. - if (!requiresDefaultLoggers || logger == null - || logger != Logger.global && logger != manager.rootLogger) { + if (!requiresDefaultLoggers() || logger == null + || logger != Logger.global && logger != LogManager.this.rootLogger) { // the case where we have a non null logger which is neither // Logger.global nor manager.rootLogger indicates a serious @@ -625,7 +727,7 @@ public class LogManager { boolean addLocalLogger(Logger logger) { // no need to add default loggers if it's not required - return addLocalLogger(logger, requiresDefaultLoggers); + return addLocalLogger(logger, requiresDefaultLoggers()); } // Add a logger to this context. This method will only set its level @@ -663,11 +765,13 @@ public class LogManager { // We're adding a new logger. // Note that we are creating a weak reference here. - ref = manager.new LoggerWeakRef(logger); + final LogManager owner = getOwner(); + logger.setLogManager(owner); + ref = owner.new LoggerWeakRef(logger); namedLoggers.put(name, ref); // Apply any initial level defined for the new logger. - Level level = manager.getLevelProperty(name + ".level", null); + Level level = owner.getLevelProperty(name + ".level", null); if (level != null) { doSetLevel(logger, level); } @@ -719,10 +823,12 @@ public class LogManager { // 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(final Logger logger, final String name) { + final LogManager owner = getOwner(); AccessController.doPrivileged(new PrivilegedAction() { + @Override public Void run() { - if (logger != manager.rootLogger) { - boolean useParent = manager.getBooleanProperty(name + ".useParentHandlers", true); + if (logger != owner.rootLogger) { + boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true); if (!useParent) { logger.setUseParentHandlers(false); } @@ -738,8 +844,8 @@ public class LogManager { break; } String pname = name.substring(0, ix2); - if (manager.getProperty(pname + ".level") != null || - manager.getProperty(pname + ".handlers") != null) { + if (owner.getProperty(pname + ".level") != null || + owner.getProperty(pname + ".handlers") != null) { // This pname has a level/handlers definition. // Make sure it exists. demandLogger(pname, null); @@ -779,16 +885,17 @@ public class LogManager { } } - static class SystemLoggerContext extends LoggerContext { + final class SystemLoggerContext extends LoggerContext { // 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. + @Override Logger demandLogger(String name, String resourceBundleName) { Logger result = findLogger(name); if (result == null) { // only allocate the new system logger once - Logger newLogger = new Logger(name, resourceBundleName); + Logger newLogger = new Logger(name, resourceBundleName, null, getOwner()); do { if (addLocalLogger(newLogger)) { // We successfully added the new Logger that we @@ -822,6 +929,7 @@ public class LogManager { final String handlersPropertyName) { AccessController.doPrivileged(new PrivilegedAction() { + @Override public Object run() { String names[] = parseClassNames(handlersPropertyName); for (int i = 0; i < names.length; i++) { @@ -1014,6 +1122,7 @@ public class LogManager { // There is a security manager. Raise privilege before // calling setLevel. AccessController.doPrivileged(new PrivilegedAction() { + @Override public Object run() { logger.setLevel(level); return null; @@ -1032,6 +1141,7 @@ public class LogManager { // There is a security manager. Raise privilege before // calling setParent. AccessController.doPrivileged(new PrivilegedAction() { + @Override public Object run() { logger.setParent(parent); return null; @@ -1129,14 +1239,9 @@ public class LogManager { f = new File(f, "logging.properties"); fname = f.getCanonicalPath(); } - InputStream in = new FileInputStream(fname); - BufferedInputStream bin = new BufferedInputStream(in); - try { + try (final InputStream in = new FileInputStream(fname)) { + final BufferedInputStream bin = new BufferedInputStream(in); readConfiguration(bin); - } finally { - if (in != null) { - in.close(); - } } } @@ -1201,7 +1306,7 @@ public class LogManager { } hands = hands.trim(); int ix = 0; - Vector result = new Vector<>(); + final List result = new ArrayList<>(); while (ix < hands.length()) { int end = ix; while (end < hands.length()) { @@ -1471,28 +1576,35 @@ public class LogManager { // We use a subclass of Logger for the root logger, so // that we only instantiate the global handlers when they // are first needed. - private class RootLogger extends Logger { + private final class RootLogger extends Logger { private RootLogger() { - super("", null); + // We do not call the protected Logger two args constructor here, + // to avoid calling LogManager.getLogManager() from within the + // RootLogger constructor. + super("", null, null, LogManager.this); setLevel(defaultLevel); } + @Override public void log(LogRecord record) { // Make sure that the global handlers have been instantiated. initializeGlobalHandlers(); super.log(record); } + @Override public void addHandler(Handler h) { initializeGlobalHandlers(); super.addHandler(h); } + @Override public void removeHandler(Handler h) { initializeGlobalHandlers(); super.removeHandler(h); } + @Override public Handler[] getHandlers() { initializeGlobalHandlers(); return super.getHandlers(); diff --git a/jdk/src/share/classes/java/util/logging/Logger.java b/jdk/src/share/classes/java/util/logging/Logger.java index a7f0cc2cd4a..1393ba2aa0d 100644 --- a/jdk/src/share/classes/java/util/logging/Logger.java +++ b/jdk/src/share/classes/java/util/logging/Logger.java @@ -245,14 +245,26 @@ public class Logger { // In order to finish the initialization of the global logger, we // will therefore call LogManager.getLogManager() here. // - // Care must be taken *not* to call Logger.getGlobal() in - // LogManager static initializers in order to avoid such - // deadlocks. - // - if (global != null && global.manager == null) { - // Complete initialization of the global Logger. - global.manager = LogManager.getLogManager(); - } + // To prevent race conditions we also need to call + // LogManager.getLogManager() unconditionally here. + // Indeed we cannot rely on the observed value of global.manager, + // because global.manager will become not null somewhere during + // the initialization of LogManager. + // If two threads are calling getGlobal() concurrently, one thread + // will see global.manager null and call LogManager.getLogManager(), + // but the other thread could come in at a time when global.manager + // is already set although ensureLogManagerInitialized is not finished + // yet... + // Calling LogManager.getLogManager() unconditionally will fix that. + + LogManager.getLogManager(); + + // Now the global LogManager should be initialized, + // and the global logger should have been added to + // it, unless we were called within the constructor of a LogManager + // subclass installed as LogManager, in which case global.manager + // would still be null, and global will be lazily initialized later on. + return global; } @@ -298,11 +310,11 @@ public class Logger { * no corresponding resource can be found. */ protected Logger(String name, String resourceBundleName) { - this(name, resourceBundleName, null); + this(name, resourceBundleName, null, LogManager.getLogManager()); } - Logger(String name, String resourceBundleName, Class caller) { - this.manager = LogManager.getLogManager(); + Logger(String name, String resourceBundleName, Class caller, LogManager manager) { + this.manager = manager; setupResourceInfo(resourceBundleName, caller); this.name = name; levelValue = Level.INFO.intValue(); @@ -332,8 +344,8 @@ public class Logger { levelValue = Level.INFO.intValue(); } - // It is called from the LogManager. to complete - // initialization of the global Logger. + // It is called from LoggerContext.addLocalLogger() when the logger + // is actually added to a LogManager. void setLogManager(LogManager manager) { this.manager = manager; } @@ -558,7 +570,7 @@ public class Logger { // cleanup some Loggers that have been GC'ed manager.drainLoggerRefQueueBounded(); Logger result = new Logger(null, resourceBundleName, - Reflection.getCallerClass()); + Reflection.getCallerClass(), manager); result.anonymous = true; Logger root = manager.getLogger(""); result.doSetParent(root); @@ -1798,7 +1810,7 @@ public class Logger { if (parent == null) { throw new NullPointerException(); } - manager.checkPermission(); + checkPermission(); doSetParent(parent); } diff --git a/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobal.java b/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobal.java index dd901ed5f92..4c6b39b0acd 100644 --- a/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobal.java +++ b/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobal.java @@ -57,6 +57,12 @@ public class TestGetGlobal { } public static void main(String... args) { + final String manager = System.getProperty("java.util.logging.manager", null); + + final String description = "TestGetGlobal" + + (System.getSecurityManager() == null ? " " : + " -Djava.security.manager ") + + (manager == null ? "" : "-Djava.util.logging.manager=" + manager); Logger.global.info(messages[0]); // at this point LogManager is not // initialized yet, so this message should not appear. @@ -67,7 +73,9 @@ public class TestGetGlobal { final List expected = Arrays.asList(Arrays.copyOfRange(messages, 1, messages.length)); if (!testgetglobal.HandlerImpl.received.equals(expected)) { - throw new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected); + System.err.println("Test case failed: " + description); + throw new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected + + "\n\t"+description); } } } diff --git a/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobalConcurrent.java b/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobalConcurrent.java index 4ef38ce3611..e3f9d1d8872 100644 --- a/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobalConcurrent.java +++ b/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobalConcurrent.java @@ -22,17 +22,18 @@ */ import java.util.Arrays; import java.util.List; +import java.util.logging.Level; import java.util.logging.Logger; /** * @test - * @bug 7184195 - * @summary checks that java.util.logging.Logger.getGlobal().info() logs without configuration + * @bug 7184195 8021003 + * @summary Test that the global logger can log with no configuration when accessed from multiple threads. * @build TestGetGlobalConcurrent testgetglobal.HandlerImpl testgetglobal.LogManagerImpl1 testgetglobal.LogManagerImpl2 testgetglobal.LogManagerImpl3 testgetglobal.BadLogManagerImpl testgetglobal.DummyLogManagerImpl * @run main/othervm/timeout=10 TestGetGlobalConcurrent * @run main/othervm/timeout=10/policy=policy -Djava.security.manager TestGetGlobalConcurrent - * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl TestGetGlobalConcurrent - * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl TestGetGlobalConcurrent + * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl1 TestGetGlobalConcurrent + * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl1 TestGetGlobalConcurrent * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl2 TestGetGlobalConcurrent * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl2 TestGetGlobalConcurrent * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl3 TestGetGlobalConcurrent @@ -69,7 +70,6 @@ public class TestGetGlobalConcurrent { // initialize the LogManager - and thus this message should appear. Logger.global.info(messages[i+1]); // Now that the LogManager is // initialized, this message should appear too. - final List expected = Arrays.asList(Arrays.copyOfRange(messages, i, i+2)); if (!testgetglobal.HandlerImpl.received.containsAll(expected)) { fail(new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected)); @@ -82,7 +82,6 @@ public class TestGetGlobalConcurrent { // initialize the LogManager - and thus this message should appear. Logger.global.info(messages[i+1]); // Now that the LogManager is // initialized, this message should appear too. - final List expected = Arrays.asList(Arrays.copyOfRange(messages, i, i+2)); if (!testgetglobal.HandlerImpl.received.containsAll(expected)) { fail(new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected)); @@ -96,7 +95,6 @@ public class TestGetGlobalConcurrent { // initialize the LogManager - and thus this message should appear. Logger.global.info(messages[i+1]); // Now that the LogManager is // initialized, this message should appear too. - final List expected = Arrays.asList(Arrays.copyOfRange(messages, i, i+2)); if (!testgetglobal.HandlerImpl.received.containsAll(expected)) { fail(new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected)); @@ -150,8 +148,17 @@ public class TestGetGlobalConcurrent { public void run() { test4(); } } + static String description = "Unknown"; + public static void main(String... args) throws Exception { + final String manager = System.getProperty("java.util.logging.manager", null); + + description = "TestGetGlobalConcurrent" + + (System.getSecurityManager() == null ? " " : + " -Djava.security.manager ") + + (manager == null ? "" : "-Djava.util.logging.manager=" + manager); + final Thread t1 = new Thread(new WaitAndRun(new Run1()), "test1"); final Thread t2 = new Thread(new WaitAndRun(new Run2()), "test2"); final Thread t3 = new Thread(new WaitAndRun(new Run3()), "test3"); @@ -169,14 +176,13 @@ public class TestGetGlobalConcurrent { final List expected = Arrays.asList(Arrays.copyOfRange(messages, 1, 3)); if (!testgetglobal.HandlerImpl.received.containsAll(expected)) { - throw new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected); + fail(new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected)); } - t1.join(); t2.join(); t3.join(); t4.join(); if (failed != null) { - throw new Error("Test failed.", failed); + throw new Error("Test failed: "+description, failed); } System.out.println("Test passed"); diff --git a/jdk/test/java/util/logging/Logger/getGlobal/policy b/jdk/test/java/util/logging/Logger/getGlobal/policy index bcb7cde0da3..fad24d0b814 100644 --- a/jdk/test/java/util/logging/Logger/getGlobal/policy +++ b/jdk/test/java/util/logging/Logger/getGlobal/policy @@ -1,6 +1,7 @@ grant { permission java.util.PropertyPermission "java.util.logging.config.file", "write"; permission java.util.PropertyPermission "test.src", "read"; + permission java.util.PropertyPermission "java.util.logging.manager", "read"; permission java.lang.RuntimePermission "setContextClassLoader"; permission java.lang.RuntimePermission "shutdownHooks"; permission java.util.logging.LoggingPermission "control"; diff --git a/jdk/test/java/util/logging/ParentLoggersTest.java b/jdk/test/java/util/logging/ParentLoggersTest.java index 72d5ddadc0f..a5070a375e3 100644 --- a/jdk/test/java/util/logging/ParentLoggersTest.java +++ b/jdk/test/java/util/logging/ParentLoggersTest.java @@ -29,7 +29,7 @@ * @author ss45998 * * @build ParentLoggersTest - * @run main/othervm ParentLoggersTest + * @run main ParentLoggersTest */ /* diff --git a/jdk/test/java/util/logging/TestAppletLoggerContext.java b/jdk/test/java/util/logging/TestAppletLoggerContext.java index 82c39381fe8..3db67543245 100644 --- a/jdk/test/java/util/logging/TestAppletLoggerContext.java +++ b/jdk/test/java/util/logging/TestAppletLoggerContext.java @@ -38,7 +38,7 @@ import sun.misc.SharedSecrets; /* * @test - * @bug 8017174 8010727 + * @bug 8017174 8010727 8019945 * @summary NPE when using Logger.getAnonymousLogger or * LogManager.getLogManager().getLogger * @@ -432,45 +432,36 @@ public class TestAppletLoggerContext { assertNull(manager.getLogger("")); assertNull(manager.getLogger("")); - Bridge.changeContext(); + for (int j = 0; j<3; j++) { + Bridge.changeContext(); - // this is not a supported configuration: - // We are in an applet context with several log managers. - // We however need to check our assumptions... + // this is not a supported configuration: + // We are in an applet context with several log managers. + // We however need to check our assumptions... - // Applet context => root logger and global logger are not null. - // root == LogManager.getLogManager().rootLogger - // global == Logger.global + // Applet context => root logger and global logger should also be null. - Logger logger3 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); - Logger logger3b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); - assertNotNull(logger3); - assertNotNull(logger3b); - Logger expected = (System.getSecurityManager() != null - ? Logger.getGlobal() - : global); - assertEquals(logger3, expected); // in applet context, we will not see - // the LogManager's custom global logger added above... - assertEquals(logger3b, expected); // in applet context, we will not see - // the LogManager's custom global logger added above... - Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME); - manager.addLogger(global2); // adding a global logger will not work in applet context - // we will always get back the global logger. - // this could be considered as a bug... - Logger logger4 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); - Logger logger4b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); - assertNotNull(logger4); - assertNotNull(logger4b); - assertEquals(logger4, expected); // adding a global logger will not work in applet context - assertEquals(logger4b, expected); // adding a global logger will not work in applet context + Logger expected = (System.getSecurityManager() == null ? global : null); + Logger logger3 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); + Logger logger3b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); + assertEquals(expected, logger3); + assertEquals(expected, logger3b); + Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME); + manager.addLogger(global2); + Logger logger4 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); + Logger logger4b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); + assertNotNull(logger4); + assertNotNull(logger4b); + expected = (System.getSecurityManager() == null ? global : global2);; + assertEquals(logger4, expected); + assertEquals(logger4b, expected); - Logger logger5 = manager.getLogger(""); - Logger logger5b = manager.getLogger(""); - Logger expectedRoot = (System.getSecurityManager() != null - ? LogManager.getLogManager().getLogger("") - : null); - assertEquals(logger5, expectedRoot); - assertEquals(logger5b, expectedRoot); + Logger logger5 = manager.getLogger(""); + Logger logger5b = manager.getLogger(""); + Logger expectedRoot = null; + assertEquals(logger5, expectedRoot); + assertEquals(logger5b, expectedRoot); + } } } @@ -511,57 +502,53 @@ public class TestAppletLoggerContext { assertEquals(logger4, root); assertEquals(logger4b, root); - Bridge.changeContext(); + for (int j = 0 ; j < 3 ; j++) { + Bridge.changeContext(); - // this is not a supported configuration: - // We are in an applet context with several log managers. - // We haowever need to check our assumptions... + // this is not a supported configuration: + // We are in an applet context with several log managers. + // We however need to check our assumptions... - // Applet context => root logger and global logger are not null. - // root == LogManager.getLogManager().rootLogger - // global == Logger.global + // Applet context => root logger and global logger should also be null. - Logger logger5 = manager.getLogger(""); - Logger logger5b = manager.getLogger(""); - Logger expectedRoot = (System.getSecurityManager() != null - ? LogManager.getLogManager().getLogger("") - : root); + Logger logger5 = manager.getLogger(""); + Logger logger5b = manager.getLogger(""); + Logger expectedRoot = (System.getSecurityManager() == null ? root : null); + assertEquals(logger5, expectedRoot); + assertEquals(logger5b, expectedRoot); - assertNotNull(logger5); - assertNotNull(logger5b); - assertEquals(logger5, expectedRoot); - assertEquals(logger5b, expectedRoot); - if (System.getSecurityManager() != null) { - assertNotEquals(logger5, root); - assertNotEquals(logger5b, root); + if (System.getSecurityManager() != null) { + assertNull(manager.getLogger(Logger.GLOBAL_LOGGER_NAME)); + } else { + assertEquals(global, manager.getLogger(Logger.GLOBAL_LOGGER_NAME)); + } + + Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME); + manager.addLogger(global2); + Logger logger6 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); + Logger logger6b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); + Logger expectedGlobal = (System.getSecurityManager() == null ? global : global2); + + assertNotNull(logger6); + assertNotNull(logger6b); + assertEquals(logger6, expectedGlobal); + assertEquals(logger6b, expectedGlobal); + if (System.getSecurityManager() != null) { + assertNull(manager.getLogger("")); + } else { + assertEquals(root, manager.getLogger("")); + } + + Logger root2 = new Bridge.CustomLogger(""); + manager.addLogger(root2); + expectedRoot = (System.getSecurityManager() == null ? root : root2); + Logger logger7 = manager.getLogger(""); + Logger logger7b = manager.getLogger(""); + assertNotNull(logger7); + assertNotNull(logger7b); + assertEquals(logger7, expectedRoot); + assertEquals(logger7b, expectedRoot); } - - Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME); - manager.addLogger(global2); // adding a global logger will not work in applet context - // we will always get back the global logger. - // this could be considered as a bug... - Logger logger6 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); - Logger logger6b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); - Logger expectedGlobal = (System.getSecurityManager() != null - ? Logger.getGlobal() - : global); - assertNotNull(logger6); - assertNotNull(logger6b); - assertEquals(logger6, expectedGlobal); // adding a global logger will not work in applet context - assertEquals(logger6b, expectedGlobal); // adding a global logger will not work in applet context - - Logger root2 = new Bridge.CustomLogger(""); - manager.addLogger(root2); // adding a root logger will not work in applet context - // we will always get back the default manager's root logger. - // this could be considered as a bug... - Logger logger7 = manager.getLogger(""); - Logger logger7b = manager.getLogger(""); - assertNotNull(logger7); - assertNotNull(logger7b); - assertEquals(logger7, expectedRoot); // adding a global logger will not work in applet context - assertEquals(logger7b, expectedRoot); // adding a global logger will not work in applet context - assertNotEquals(logger7, root2); - assertNotEquals(logger7b, root2); } }