7184195: java.util.logging.Logger.getGlobal().info() doesn't log without configuration
authordfuchs
Tue, 02 Jul 2013 19:47:58 +0200
changeset 18595 c6f81d76027a
parent 18594 b6a3c9f71ac8
child 18596 bd8d7e04dc69
child 18766 28c62f5e9a47
7184195: java.util.logging.Logger.getGlobal().info() doesn't log without configuration Summary: Due to subtle synchronization issues between LogManager & Logger class initialization the global logger doesn't have its 'manager' field initialized until the LogManager is initialized. This fix will ensure that the global logger has its 'manager' field set when getGlobal() is called. Reviewed-by: mchung, plevart
jdk/src/share/classes/java/util/logging/LogManager.java
jdk/src/share/classes/java/util/logging/Logger.java
jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobal.java
jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobalByName.java
jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobalConcurrent.java
jdk/test/java/util/logging/Logger/getGlobal/logging.properties
jdk/test/java/util/logging/Logger/getGlobal/policy
jdk/test/java/util/logging/Logger/getGlobal/testgetglobal/BadLogManagerImpl.java
jdk/test/java/util/logging/Logger/getGlobal/testgetglobal/DummyLogManagerImpl.java
jdk/test/java/util/logging/Logger/getGlobal/testgetglobal/HandlerImpl.java
jdk/test/java/util/logging/Logger/getGlobal/testgetglobal/LogManagerImpl1.java
jdk/test/java/util/logging/Logger/getGlobal/testgetglobal/LogManagerImpl2.java
jdk/test/java/util/logging/Logger/getGlobal/testgetglobal/LogManagerImpl3.java
--- a/jdk/src/share/classes/java/util/logging/LogManager.java	Tue Jul 02 05:28:31 2013 -0700
+++ b/jdk/src/share/classes/java/util/logging/LogManager.java	Tue Jul 02 19:47:58 2013 +0200
@@ -203,12 +203,17 @@
 
                     // Adding the global Logger. Doing so in the Logger.<clinit>
                     // would deadlock with the LogManager.<clinit>.
-                    Logger.global.setLogManager(manager);
+                    // 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(Logger.global);
-                    manager.systemContext.addLocalLogger(Logger.global, false);
-                    manager.userContext.addLocalLogger(Logger.global, false);
+                    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
--- a/jdk/src/share/classes/java/util/logging/Logger.java	Tue Jul 02 05:28:31 2013 -0700
+++ b/jdk/src/share/classes/java/util/logging/Logger.java	Tue Jul 02 19:47:58 2013 +0200
@@ -232,6 +232,27 @@
      * @since 1.7
      */
     public static final Logger getGlobal() {
+        // In order to break a cyclic dependence between the LogManager
+        // and Logger static initializers causing deadlocks, the global
+        // logger is created with a special constructor that does not
+        // initialize its log manager.
+        //
+        // If an application calls Logger.getGlobal() before any logger
+        // has been initialized, it is therefore possible that the
+        // LogManager class has not been initialized yet, and therefore
+        // Logger.global.manager will be null.
+        //
+        // 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();
+        }
         return global;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobal.java	Tue Jul 02 19:47:58 2013 +0200
@@ -0,0 +1,73 @@
+/*
+ * 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.Arrays;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * @test
+ * @bug 7184195
+ * @summary checks that java.util.logging.Logger.getGlobal().info() logs without configuration
+ * @build TestGetGlobal testgetglobal.HandlerImpl testgetglobal.LogManagerImpl1 testgetglobal.LogManagerImpl2 testgetglobal.LogManagerImpl3 testgetglobal.BadLogManagerImpl testgetglobal.DummyLogManagerImpl
+ * @run main/othervm/timeout=10 TestGetGlobal
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager TestGetGlobal
+ * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl1 TestGetGlobal
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl1 TestGetGlobal
+ * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl2 TestGetGlobal
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl2 TestGetGlobal
+ * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl3 TestGetGlobal
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl3 TestGetGlobal
+ * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.BadLogManagerImpl TestGetGlobal
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.BadLogManagerImpl TestGetGlobal
+ * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.DummyLogManagerImpl TestGetGlobal
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.DummyLogManagerImpl TestGetGlobal
+ * @author danielfuchs
+ */
+public class TestGetGlobal {
+
+    final static String[] messages = {
+        "1. This message should not appear on the console.",
+        "2. This message should appear on the console.",
+        "3. This message should now appear on the console too."
+    };
+
+    static {
+        System.setProperty("java.util.logging.config.file",
+            System.getProperty("test.src", ".") + java.io.File.separator + "logging.properties");
+    }
+
+    public static void main(String... args) {
+
+        Logger.global.info(messages[0]); // at this point LogManager is not
+             // initialized yet, so this message should not appear.
+        Logger.getGlobal().info(messages[1]); // calling getGlobal() will
+             // initialize the LogManager - and thus this message should appear.
+        Logger.global.info(messages[2]); // Now that the LogManager is
+             // initialized, this message should appear too.
+
+        final List<String> 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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobalByName.java	Tue Jul 02 19:47:58 2013 +0200
@@ -0,0 +1,73 @@
+/*
+ * 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.Arrays;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * @test
+ * @bug 7184195
+ * @summary checks that java.util.logging.Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info() logs without configuration
+ * @build TestGetGlobalByName testgetglobal.HandlerImpl testgetglobal.LogManagerImpl1 testgetglobal.LogManagerImpl2 testgetglobal.LogManagerImpl3 testgetglobal.BadLogManagerImpl testgetglobal.DummyLogManagerImpl
+ * @run main/othervm/timeout=10 TestGetGlobalByName
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager TestGetGlobalByName
+ * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl1 TestGetGlobalByName
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl TestGetGlobalByName
+ * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl2 TestGetGlobalByName
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl2 TestGetGlobalByName
+ * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl3 TestGetGlobalByName
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl3 TestGetGlobalByName
+ * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.BadLogManagerImpl TestGetGlobalByName
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.BadLogManagerImpl TestGetGlobalByName
+ * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.DummyLogManagerImpl TestGetGlobalByName
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.DummyLogManagerImpl TestGetGlobalByName
+ * @author danielfuchs
+ */
+public class TestGetGlobalByName {
+
+    final static String[] messages = {
+        "1. This message should not appear on the console.",
+        "2. This message should appear on the console.",
+        "3. This message should now appear on the console too."
+    };
+
+    static {
+        System.setProperty("java.util.logging.config.file",
+            System.getProperty("test.src", ".") + java.io.File.separator + "logging.properties");
+    }
+
+    public static void main(String... args) {
+
+        Logger.global.info(messages[0]); // at this point LogManager is not
+             // initialized yet, so this message should not appear.
+        Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info(messages[1]); // calling getLogger() will
+             // initialize the LogManager - and thus this message should appear.
+        Logger.global.info(messages[2]); // Now that the LogManager is
+             // initialized, this message should appear too.
+
+        final List<String> 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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobalConcurrent.java	Tue Jul 02 19:47:58 2013 +0200
@@ -0,0 +1,184 @@
+/*
+ * 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.Arrays;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * @test
+ * @bug 7184195
+ * @summary checks that java.util.logging.Logger.getGlobal().info() logs without configuration
+ * @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.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
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl3 TestGetGlobalConcurrent
+ * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.BadLogManagerImpl TestGetGlobalConcurrent
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.BadLogManagerImpl TestGetGlobalConcurrent
+ * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.DummyLogManagerImpl TestGetGlobalConcurrent
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.DummyLogManagerImpl TestGetGlobalConcurrent
+ * @author danielfuchs
+ */
+public class TestGetGlobalConcurrent {
+
+    final static String[] messages = {
+        "1. This message should not appear on the console.",
+        "2. This message should appear on the console.",
+        "3. This message should now appear on the console too.",
+        "4. This message should appear on the console.",
+        "5. This message should now appear on the console too.",
+        "6. This message should appear on the console.",
+        "7. This message should now appear on the console too.",
+        "8. This message should appear on the console.",
+        "9. This message should now appear on the console too."
+    };
+
+    static {
+        System.setProperty("java.util.logging.config.file",
+            System.getProperty("test.src", ".") + java.io.File.separator + "logging.properties");
+    }
+
+    public static void test1() {
+        final int nb = 1;
+        final int i = 2*nb + 1;
+        Logger.getGlobal().info(messages[i]); // calling getGlobal() will
+             // 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<String> 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));
+        }
+    }
+    public static void test2() {
+        final int nb = 2;
+        final int i = 2*nb + 1;
+        Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info(messages[i]); // calling getGlobal() will
+             // 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<String> 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));
+        }
+    }
+    public static void test3() {
+        final int nb = 3;
+        final int i = 2*nb + 1;
+        java.util.logging.LogManager.getLogManager();
+        Logger.getGlobal().info(messages[i]); // calling getGlobal() will
+             // 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<String> 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));
+        }
+    }
+    public static void test4() {
+        log = new MyLogger("foo.bar");
+        java.util.logging.LogManager.getLogManager().addLogger(log);
+    }
+
+
+    private static volatile Throwable failed = null;
+    private static volatile Logger log = null;
+
+    public static class MyLogger extends Logger {
+        public MyLogger(String name) {
+            super(name, null);
+        }
+    }
+
+    public static void fail(Throwable failure) {
+        failure.printStackTrace();
+        if (failed == null) failed = failure;
+    }
+
+    public static class WaitAndRun implements Runnable {
+          private final Runnable run;
+          public WaitAndRun(Runnable run) {
+              this.run = run;
+          }
+          public void run() {
+              try {
+                 Thread.sleep(10);
+                 run.run();
+              } catch (Exception | Error x) {
+                 fail(x);
+              }
+          }
+    }
+
+    final static class Run1 implements Runnable {
+        public void run() { test1(); }
+    }
+    final static class Run2 implements Runnable {
+        public void run() { test2(); }
+    }
+    final static class Run3 implements Runnable {
+        public void run() { test3(); }
+    }
+    final static class Run4 implements Runnable {
+        public void run() { test4(); }
+    }
+
+    public static void main(String... args) throws Exception {
+
+        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");
+        final Thread t4 = new Thread(new WaitAndRun(new Run4()), "test4");
+
+        t1.setDaemon(true); t2.setDaemon(true); t3.setDaemon(true); t4.setDaemon(true);
+        t1.start(); t2.start(); t3.start(); t4.start();
+
+        Thread.sleep(10);
+
+        Logger.getGlobal().info(messages[1]); // calling getGlobal() will
+             // initialize the LogManager - and thus this message should appear.
+        Logger.global.info(messages[2]); // Now that the LogManager is
+             // initialized, this message should appear too.
+
+        final List<String> 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);
+        }
+
+
+        t1.join(); t2.join(); t3.join(); t4.join();
+
+        if (failed != null) {
+             throw new Error("Test failed.", failed);
+        }
+
+        System.out.println("Test passed");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/Logger/getGlobal/logging.properties	Tue Jul 02 19:47:58 2013 +0200
@@ -0,0 +1,2 @@
+.level=INFO
+handlers=testgetglobal.HandlerImpl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/Logger/getGlobal/policy	Tue Jul 02 19:47:58 2013 +0200
@@ -0,0 +1,7 @@
+grant {
+    permission java.util.PropertyPermission "java.util.logging.config.file", "write";
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.lang.RuntimePermission "setContextClassLoader";
+    permission java.lang.RuntimePermission "shutdownHooks";
+    permission java.util.logging.LoggingPermission "control";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/Logger/getGlobal/testgetglobal/BadLogManagerImpl.java	Tue Jul 02 19:47:58 2013 +0200
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+package testgetglobal;
+
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+
+/**
+ * This class is used to verify that calling Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)
+ * in the constructor of a LogManager subclass installed as default
+ * LogManager does not cause issues beyond throwing the expected NPE.
+ * In that case the default LogManager class will simply be used.
+ * @author danielfuchs
+ */
+public class BadLogManagerImpl extends LogManager {
+
+    final Logger globalLogger;
+    public BadLogManagerImpl() {
+        // The call below should generate an NPE, which will be
+        // catched in LogManager initializer.
+        globalLogger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
+        System.err.println("Global is: " + globalLogger);
+        throw new Error("Should not have reached here");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/Logger/getGlobal/testgetglobal/DummyLogManagerImpl.java	Tue Jul 02 19:47:58 2013 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+package testgetglobal;
+
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+
+/**
+ * A dummy LogManager subclass that does nothing beyond extending LogManager.
+ * @author danielfuchs
+ */
+public class DummyLogManagerImpl extends LogManager {
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/Logger/getGlobal/testgetglobal/HandlerImpl.java	Tue Jul 02 19:47:58 2013 +0200
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+package testgetglobal;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.List;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.LogRecord;
+
+/**
+ *
+ * @author danielfuchs
+ */
+public class HandlerImpl extends ConsoleHandler {
+
+    public final static List<String> received = new CopyOnWriteArrayList<>();
+
+    public HandlerImpl() {
+    }
+
+    @Override
+    public void publish(LogRecord record) {
+        received.add(record.getMessage());
+        super.publish(record);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/Logger/getGlobal/testgetglobal/LogManagerImpl1.java	Tue Jul 02 19:47:58 2013 +0200
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+package testgetglobal;
+
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+
+/**
+ * This class is used to verify that calling Logger.getGlobal() in the static
+ * initializer of a LogManager subclass installed as default LogManager
+ * does not cause issues.
+ * @author danielfuchs
+ */
+public class LogManagerImpl1 extends LogManager {
+
+    static final Logger global;
+    static {
+        global = Logger.getGlobal();
+        System.err.println("Global is: " + global);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/Logger/getGlobal/testgetglobal/LogManagerImpl2.java	Tue Jul 02 19:47:58 2013 +0200
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+package testgetglobal;
+
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+
+/**
+ * This class is used to verify that calling Logger.getGlobal() in the constructor
+ * initializer of a LogManager subclass installed as default LogManager
+ * does not cause issues.
+ * @author danielfuchs
+ */
+public class LogManagerImpl2 extends LogManager {
+
+    final Logger globalLogger;
+    public LogManagerImpl2() {
+        globalLogger = Logger.getGlobal();
+        System.err.println("Global is: " + globalLogger);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/Logger/getGlobal/testgetglobal/LogManagerImpl3.java	Tue Jul 02 19:47:58 2013 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+package testgetglobal;
+
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+
+/**
+ * This class is used to verify that calling Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)
+ * in the static initializer of a LogManager subclass installed as default
+ * LogManager does not cause issues beyond throwing the expected NPE.
+ * @author danielfuchs
+ */
+public class LogManagerImpl3 extends LogManager {
+
+    static final Logger global;
+    static {
+        Logger g = null;
+        try {
+            g = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
+            throw new Error("Should not have reached here");
+        } catch (Exception x) {
+            // This is to be expected: Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)
+            // will call LogManager.getLogManager() which will return null, since
+            // we haven't manage to do new LogManagerImpl3() yet.
+            //
+            System.err.println("Got expected exception - you cannot call"
+                   + " Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)"
+                   + " in LogManager subclass static initializer: " + x);
+            x.printStackTrace();
+        }
+        if (g == null) {
+            g = Logger.getGlobal();
+        }
+        global = g;
+        System.err.println("Global is: " + global);
+    }
+
+}