1 /*
   2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.security.CodeSource;
  25 import java.security.Permission;
  26 import java.security.PermissionCollection;
  27 import java.security.Permissions;
  28 import java.security.Policy;
  29 import java.security.ProtectionDomain;
  30 import java.util.EnumSet;
  31 import java.util.HashMap;
  32 import java.util.Map;
  33 import java.util.logging.LogManager;
  34 import java.util.logging.Logger;
  35 import java.util.logging.LoggingPermission;
  36 import sun.misc.JavaAWTAccess;
  37 import sun.misc.SharedSecrets;
  38 
  39 /*
  40  * @test
  41  * @bug 8017174 8010727
  42  * @summary  NPE when using Logger.getAnonymousLogger or
  43  *           LogManager.getLogManager().getLogger
  44  *
  45  * @run main/othervm -Dtest.security=off TestAppletLoggerContext LoadingApplet
  46  * @run main/othervm -Dtest.security=on TestAppletLoggerContext  LoadingApplet
  47  * @run main/othervm -Dtest.security=off TestAppletLoggerContext LoadingMain
  48  * @run main/othervm -Dtest.security=on TestAppletLoggerContext  LoadingMain
  49  * @run main/othervm -Dtest.security=off TestAppletLoggerContext One
  50  * @run main/othervm -Dtest.security=on TestAppletLoggerContext  One
  51  * @run main/othervm -Dtest.security=off TestAppletLoggerContext Two
  52  * @run main/othervm -Dtest.security=on TestAppletLoggerContext  Two
  53  * @run main/othervm -Dtest.security=off TestAppletLoggerContext Three
  54  * @run main/othervm -Dtest.security=on TestAppletLoggerContext  Three
  55  * @run main/othervm -Dtest.security=off TestAppletLoggerContext Four
  56  * @run main/othervm -Dtest.security=on TestAppletLoggerContext  Four
  57  * @run main/othervm -Dtest.security=off TestAppletLoggerContext Five
  58  * @run main/othervm -Dtest.security=on TestAppletLoggerContext  Five
  59  * @run main/othervm -Dtest.security=off TestAppletLoggerContext Six
  60  * @run main/othervm -Dtest.security=on TestAppletLoggerContext  Six
  61  * @run main/othervm -Dtest.security=off TestAppletLoggerContext Seven
  62  * @run main/othervm -Dtest.security=on TestAppletLoggerContext  Seven
  63  * @run main/othervm -Dtest.security=off TestAppletLoggerContext
  64  * @run main/othervm -Dtest.security=on TestAppletLoggerContext
  65  */
  66 
  67 // NOTE: We run in other VM in order to 1. switch security manager and 2. cause
  68 // LogManager class to be loaded anew.
  69 public class TestAppletLoggerContext {
  70 
  71     // Avoids the hassle of dealing with files and system props...
  72     static class SimplePolicy extends Policy {
  73         private final Permissions perms;
  74         public SimplePolicy(Permission... permissions) {
  75             perms = new Permissions();
  76             for (Permission permission : permissions) {
  77                 perms.add(permission);
  78             }
  79         }
  80         @Override
  81         public PermissionCollection getPermissions(CodeSource cs) {
  82             return perms;
  83         }
  84         @Override
  85         public PermissionCollection getPermissions(ProtectionDomain pd) {
  86             return perms;
  87         }
  88         @Override
  89         public boolean implies(ProtectionDomain pd, Permission p) {
  90            return perms.implies(p);
  91         }
  92     }
  93 
  94     // The bridge class initializes the logging system.
  95     // It stubs the applet context in order to simulate context changes.
  96     //
  97     public static class Bridge {
  98 
  99         private static class JavaAWTAccessStub implements JavaAWTAccess {
 100             boolean active = true;
 101 
 102             private static class TestExc {
 103                 private final Map<Object, Object> map = new HashMap<>();
 104                 void put(Object key, Object v) { map.put(key, v); }
 105                 Object get(Object key) { return map.get(key); }
 106                 void remove(Object o) { map.remove(o); }
 107                 public static TestExc exc(Object o) {
 108                     return TestExc.class.cast(o);
 109                 }
 110             }
 111 
 112             TestExc exc;
 113             TestExc global = new TestExc();
 114 
 115             @Override
 116             public Object getContext() { return active ? global : null; }
 117             @Override
 118             public Object getExecutionContext() { return active ? exc : null; }
 119             @Override
 120             public Object get(Object o, Object o1) { return TestExc.exc(o).get(o1); }
 121             @Override
 122             public void put(Object o, Object o1, Object o2) { TestExc.exc(o).put(o1, o2); }
 123             @Override
 124             public void remove(Object o, Object o1) { TestExc.exc(o).remove(o1); }
 125             @Override
 126             public Object get(Object o) { return global.get(o); }
 127             @Override
 128             public void put(Object o, Object o1) { global.put(o, o1); }
 129             @Override
 130             public void remove(Object o) { global.remove(o); }
 131             @Override
 132             public boolean isDisposed() { return false; }
 133             @Override
 134             public boolean isMainAppContext() { return exc == null; }
 135         }
 136 
 137         final static JavaAWTAccessStub javaAwtAccess = new JavaAWTAccessStub();
 138         public static void init() {
 139             SharedSecrets.setJavaAWTAccess(javaAwtAccess);
 140             if (System.getProperty("test.security", "on").equals("on")) {
 141                 Policy p = new SimplePolicy(new LoggingPermission("control", null),
 142                     new RuntimePermission("setContextClassLoader"),
 143                     new RuntimePermission("shutdownHooks"));
 144                 Policy.setPolicy(p);
 145                 System.setSecurityManager(new SecurityManager());
 146             }
 147         }
 148 
 149         public static void changeContext() {
 150             System.out.println("... Switching to a new applet context ...");
 151             javaAwtAccess.active = true;
 152             javaAwtAccess.exc = new JavaAWTAccessStub.TestExc();
 153         }
 154 
 155         public static void desactivate() {
 156             System.out.println("... Running with no applet context ...");
 157             javaAwtAccess.exc = null;
 158             javaAwtAccess.active = false;
 159         }
 160 
 161         public static class CustomAnonymousLogger extends Logger {
 162             public CustomAnonymousLogger() {
 163                 this("");
 164             }
 165             public CustomAnonymousLogger(String name) {
 166                 super(null, null);
 167                 System.out.println( " LogManager: " +LogManager.getLogManager());
 168                 System.out.println( " getLogger: " +LogManager.getLogManager().getLogger(name));
 169                 setParent(LogManager.getLogManager().getLogger(name));
 170             }
 171         }
 172 
 173         public static class CustomLogger extends Logger {
 174             CustomLogger(String name) {
 175                 super(name, null);
 176             }
 177         }
 178     }
 179 
 180     public static enum TestCase {
 181         LoadingApplet, LoadingMain, One, Two, Three, Four, Five, Six, Seven;
 182         public void test() {
 183             switch(this) {
 184                 // When run - each of these two tests must be
 185                 // run before any other tests and before each other.
 186                 case LoadingApplet: testLoadingApplet(); break;
 187                 case LoadingMain:   testLoadingMain(); break;
 188                 case One:   testOne(); break;
 189                 case Two:   testTwo(); break;
 190                 case Three: testThree(); break;
 191                 case Four:  testFour(); break;
 192                 case Five:  testFive(); break;
 193                 case Six:   testSix(); break;
 194                 case Seven: testSeven(); break;
 195             }
 196         }
 197         public String describe() {
 198             switch(this) {
 199                 case LoadingApplet:
 200                     return "Test that when the LogManager class is"
 201                         + " loaded in  an applet thread first,"
 202                         + "\n all LoggerContexts are correctly initialized";
 203                 case LoadingMain:
 204                     return "Test that when the LogManager class is"
 205                         + " loaded in  the main thread first,"
 206                         + "\n all LoggerContexts are correctly initialized";
 207                 case One:
 208                     return "Test that Logger.getAnonymousLogger()"
 209                         + " and new CustomAnonymousLogger() don't throw NPE";
 210                 case Two:
 211                     return "Test that Logger.getLogger(\"\")"
 212                             + " does not return null nor throws NPE";
 213                 case Three:
 214                     return "Test that LogManager.getLogManager().getLogger(\"\")"
 215                             + " does not return null nor throws NPE";
 216                 case Four:
 217                     return "Test that Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)"
 218                             + " does not return null,\n and that"
 219                             + " new CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME)"
 220                             + " does not throw NPE";
 221                 case Five:
 222                     return "Test that LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME)"
 223                             + "\n does not return null nor throws NPE";
 224                 case Six:
 225                     return "Test that manager.getLogger(Logger.GLOBAL_LOGGER_NAME)"
 226                             + " returns null\n when manager is not the default"
 227                             + " LogManager instance.\n"
 228                             + "Test adding a new logger named \"global\" in that"
 229                             + " non default instance.";
 230                 case Seven: return "Test that manager.getLogger(\"\")"
 231                             + " returns null\n when manager is not the default"
 232                             + " LogManager instance.\n"
 233                             + "Test adding a new logger named \"\" in that"
 234                             + " non default instance.";
 235                 default: return "Undefined";
 236             }
 237         }
 238     };
 239 
 240     /**
 241      * @param args the command line arguments
 242      */
 243     public static void main(String[] args) {
 244         Bridge.init();
 245         EnumSet<TestCase> tests = EnumSet.noneOf(TestCase.class);
 246         for (String arg : args) {
 247             tests.add(TestCase.valueOf(arg));
 248         }
 249         if (args.length == 0) {
 250             tests = EnumSet.complementOf(EnumSet.of(TestCase.LoadingMain));
 251         }
 252         final EnumSet<TestCase> loadingTests =
 253             EnumSet.of(TestCase.LoadingApplet, TestCase.LoadingMain);
 254         int testrun = 0;
 255         for (TestCase test : tests) {
 256             if (loadingTests.contains(test)) {
 257                 if (testrun > 0) {
 258                     throw new UnsupportedOperationException("Test case "
 259                           + test + " must be executed first!");
 260                 }
 261             }
 262             System.out.println("Testing "+ test+": ");
 263             System.out.println(test.describe());
 264             try {
 265                 test.test();
 266             } catch (Exception x) {
 267                throw new Error(String.valueOf(test)
 268                    + (System.getSecurityManager() == null ? " without " : " with ")
 269                    + "security failed: "+x+"\n "+"FAILED: "+test.describe()+"\n", x);
 270             } finally {
 271                 testrun++;
 272             }
 273             Bridge.changeContext();
 274             System.out.println("PASSED: "+ test);
 275         }
 276     }
 277 
 278     public static void testLoadingApplet() {
 279         Bridge.changeContext();
 280 
 281         Logger bar = new Bridge.CustomLogger("com.foo.Bar");
 282         LogManager.getLogManager().addLogger(bar);
 283         assertNotNull(bar.getParent());
 284         testParent(bar);
 285         testParent(LogManager.getLogManager().getLogger("global"));
 286         testParent(LogManager.getLogManager().getLogger(bar.getName()));
 287 
 288         Bridge.desactivate();
 289 
 290         Logger foo = new Bridge.CustomLogger("com.foo.Foo");
 291         boolean b = LogManager.getLogManager().addLogger(foo);
 292         assertEquals(Boolean.TRUE, Boolean.valueOf(b));
 293         assertNotNull(foo.getParent());
 294         testParent(foo);
 295         testParent(LogManager.getLogManager().getLogger("global"));
 296         testParent(LogManager.getLogManager().getLogger(foo.getName()));
 297     }
 298 
 299     public static void testLoadingMain() {
 300         Bridge.desactivate();
 301 
 302         Logger bar = new Bridge.CustomLogger("com.foo.Bar");
 303         LogManager.getLogManager().addLogger(bar);
 304         assertNotNull(bar.getParent());
 305         testParent(bar);
 306         testParent(LogManager.getLogManager().getLogger("global"));
 307         testParent(LogManager.getLogManager().getLogger(bar.getName()));
 308 
 309         Bridge.changeContext();
 310 
 311         Logger foo = new Bridge.CustomLogger("com.foo.Foo");
 312         boolean b = LogManager.getLogManager().addLogger(foo);
 313         assertEquals(Boolean.TRUE, Boolean.valueOf(b));
 314         assertNotNull(foo.getParent());
 315         testParent(foo);
 316         testParent(LogManager.getLogManager().getLogger("global"));
 317         testParent(LogManager.getLogManager().getLogger(foo.getName()));
 318 
 319     }
 320 
 321     public static void testOne() {
 322         for (int i=0; i<3 ; i++) {
 323             Logger logger1 = Logger.getAnonymousLogger();
 324             Logger logger1b = Logger.getAnonymousLogger();
 325             Bridge.changeContext();
 326             Logger logger2 = Logger.getAnonymousLogger();
 327             Logger logger2b = Logger.getAnonymousLogger();
 328             Bridge.changeContext();
 329             Logger logger3 = new Bridge.CustomAnonymousLogger();
 330             Logger logger3b = new Bridge.CustomAnonymousLogger();
 331             Bridge.changeContext();
 332             Logger logger4 = new Bridge.CustomAnonymousLogger();
 333             Logger logger4b = new Bridge.CustomAnonymousLogger();
 334         }
 335     }
 336 
 337 
 338     public static void testTwo() {
 339         for (int i=0; i<3 ; i++) {
 340             Logger logger1 = Logger.getLogger("");
 341             Logger logger1b = Logger.getLogger("");
 342             assertNotNull(logger1);
 343             assertNotNull(logger1b);
 344             assertEquals(logger1, logger1b);
 345             Bridge.changeContext();
 346             Logger logger2 = Logger.getLogger("");
 347             Logger logger2b = Logger.getLogger("");
 348             assertNotNull(logger2);
 349             assertNotNull(logger2b);
 350             assertEquals(logger2, logger2b);
 351             assertEquals(logger1, logger2);
 352         }
 353     }
 354 
 355     public static void testThree() {
 356         for (int i=0; i<3 ; i++) {
 357             Logger logger1 = LogManager.getLogManager().getLogger("");
 358             Logger logger1b = LogManager.getLogManager().getLogger("");
 359             assertNotNull(logger1);
 360             assertNotNull(logger1b);
 361             assertEquals(logger1, logger1b);
 362             Bridge.changeContext();
 363             Logger logger2 = LogManager.getLogManager().getLogger("");
 364             Logger logger2b = LogManager.getLogManager().getLogger("");
 365             assertNotNull(logger2);
 366             assertNotNull(logger2b);
 367             assertEquals(logger2, logger2b);
 368             assertEquals(logger1, logger2);
 369         }
 370     }
 371 
 372     public static void testFour() {
 373         for (int i=0; i<3 ; i++) {
 374             Logger logger1 = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
 375             Logger logger1b = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
 376             assertNotNull(logger1);
 377             assertNotNull(logger1b);
 378             assertEquals(logger1, logger1b);
 379             Bridge.changeContext();
 380 
 381             Logger logger2 = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
 382             Logger logger2b = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
 383             assertNotNull(logger2);
 384             assertNotNull(logger2b);
 385             assertEquals(logger2, logger2b);
 386 
 387             assertEquals(logger1, logger2);
 388 
 389             Bridge.changeContext();
 390             Logger logger3 = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME);
 391             Logger logger3b = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME);
 392             Bridge.changeContext();
 393             Logger logger4 = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME);
 394             Logger logger4b = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME);
 395         }
 396     }
 397 
 398     public static void testFive() {
 399         for (int i=0; i<3 ; i++) {
 400             Logger logger1 = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME);
 401             Logger logger1b = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME);
 402             assertNotNull(logger1);
 403             assertNotNull(logger1b);
 404             assertEquals(logger1, logger1b);
 405 
 406             Bridge.changeContext();
 407 
 408             Logger logger2 = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME);
 409             Logger logger2b = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME);
 410             assertNotNull(logger2);
 411             assertNotNull(logger2b);
 412             assertEquals(logger2, logger2b);
 413 
 414             assertEquals(logger1, logger2);
 415         }
 416     }
 417 
 418     /**
 419      * This test is designed to test the behavior of additional LogManager instances.
 420      * It must be noted that if the security manager is off, then calling
 421      * Bridge.changeContext() has actually no effect - which explains why we have
 422      * some differences between the cases security manager on & security manager
 423      * off.
 424      **/
 425     public static void testSix() {
 426         for (int i=0; i<3 ; i++) {
 427             Bridge.desactivate();
 428             LogManager manager = new LogManager() {};
 429             Logger logger1 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
 430             Logger logger1b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
 431             assertNull(logger1);
 432             assertNull(logger1b);
 433             Logger global = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
 434             manager.addLogger(global);
 435             Logger logger2 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
 436             Logger logger2b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
 437             assertNotNull(logger2);
 438             assertNotNull(logger2b);
 439             assertEquals(logger2, global);
 440             assertEquals(logger2b, global);
 441             assertNull(manager.getLogger(""));
 442             assertNull(manager.getLogger(""));
 443 
 444             Bridge.changeContext();
 445 
 446             // this is not a supported configuration:
 447             // We are in an applet context with several log managers.
 448             // We however need to check our assumptions...
 449 
 450             // Applet context => root logger and global logger are not null.
 451             //   root == LogManager.getLogManager().rootLogger
 452             //   global == Logger.global
 453 
 454             Logger logger3 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
 455             Logger logger3b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
 456             assertNotNull(logger3);
 457             assertNotNull(logger3b);
 458             Logger expected = (System.getSecurityManager() != null
 459                   ? Logger.getGlobal()
 460                   : global);
 461             assertEquals(logger3, expected); // in applet context, we will not see
 462                   // the LogManager's custom global logger added above...
 463             assertEquals(logger3b, expected); // in applet context, we will not see
 464                   // the LogManager's custom global logger added above...
 465             Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
 466             manager.addLogger(global2); // adding a global logger will not work in applet context
 467                // we will always get back the global logger.
 468                // this could be considered as a bug...
 469             Logger logger4 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
 470             Logger logger4b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
 471             assertNotNull(logger4);
 472             assertNotNull(logger4b);
 473             assertEquals(logger4,  expected); // adding a global logger will not work in applet context
 474             assertEquals(logger4b, expected); // adding a global logger will not work in applet context
 475 
 476             Logger logger5 = manager.getLogger("");
 477             Logger logger5b = manager.getLogger("");
 478             Logger expectedRoot = (System.getSecurityManager() != null
 479                   ? LogManager.getLogManager().getLogger("")
 480                   : null);
 481             assertEquals(logger5, expectedRoot);
 482             assertEquals(logger5b, expectedRoot);
 483 
 484         }
 485     }
 486 
 487     /**
 488      * This test is designed to test the behavior of additional LogManager instances.
 489      * It must be noted that if the security manager is off, then calling
 490      * Bridge.changeContext() has actually no effect - which explains why we have
 491      * some differences between the cases security manager on & security manager
 492      * off.
 493      **/
 494     public static void testSeven() {
 495         for (int i=0; i<3 ; i++) {
 496             Bridge.desactivate();
 497             LogManager manager = new LogManager() {};
 498             Logger logger1 = manager.getLogger("");
 499             Logger logger1b = manager.getLogger("");
 500             assertNull(logger1);
 501             assertNull(logger1b);
 502             Logger global = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
 503             manager.addLogger(global);
 504             Logger logger2 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
 505             Logger logger2b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
 506             assertNotNull(logger2);
 507             assertNotNull(logger2b);
 508             assertEquals(logger2, global);
 509             assertEquals(logger2b, global);
 510             Logger logger3 = manager.getLogger("");
 511             Logger logger3b = manager.getLogger("");
 512             assertNull(logger3);
 513             assertNull(logger3b);
 514             Logger root = new Bridge.CustomLogger("");
 515             manager.addLogger(root);
 516             Logger logger4 = manager.getLogger("");
 517             Logger logger4b = manager.getLogger("");
 518             assertNotNull(logger4);
 519             assertNotNull(logger4b);
 520             assertEquals(logger4, root);
 521             assertEquals(logger4b, root);
 522 
 523             Bridge.changeContext();
 524 
 525             // this is not a supported configuration:
 526             // We are in an applet context with several log managers.
 527             // We haowever need to check our assumptions...
 528 
 529             // Applet context => root logger and global logger are not null.
 530             //   root == LogManager.getLogManager().rootLogger
 531             //   global == Logger.global
 532 
 533             Logger logger5 = manager.getLogger("");
 534             Logger logger5b = manager.getLogger("");
 535             Logger expectedRoot = (System.getSecurityManager() != null
 536                   ? LogManager.getLogManager().getLogger("")
 537                   : root);
 538 
 539             assertNotNull(logger5);
 540             assertNotNull(logger5b);
 541             assertEquals(logger5, expectedRoot);
 542             assertEquals(logger5b, expectedRoot);
 543             if (System.getSecurityManager() != null) {
 544                 assertNotEquals(logger5, root);
 545                 assertNotEquals(logger5b, root);
 546             }
 547 
 548             Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
 549             manager.addLogger(global2); // adding a global logger will not work in applet context
 550                // we will always get back the global logger.
 551                // this could be considered as a bug...
 552             Logger logger6 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
 553             Logger logger6b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
 554             Logger expectedGlobal = (System.getSecurityManager() != null
 555                   ? Logger.getGlobal()
 556                   : global);
 557             assertNotNull(logger6);
 558             assertNotNull(logger6b);
 559             assertEquals(logger6, expectedGlobal); // adding a global logger will not work in applet context
 560             assertEquals(logger6b, expectedGlobal); // adding a global logger will not work in applet context
 561 
 562             Logger root2 = new Bridge.CustomLogger("");
 563             manager.addLogger(root2); // adding a root logger will not work in applet context
 564                // we will always get back the default manager's root logger.
 565                // this could be considered as a bug...
 566             Logger logger7 = manager.getLogger("");
 567             Logger logger7b = manager.getLogger("");
 568             assertNotNull(logger7);
 569             assertNotNull(logger7b);
 570             assertEquals(logger7, expectedRoot); // adding a global logger will not work in applet context
 571             assertEquals(logger7b, expectedRoot); // adding a global logger will not work in applet context
 572             assertNotEquals(logger7, root2);
 573             assertNotEquals(logger7b, root2);
 574         }
 575     }
 576 
 577     public static void testParent(Logger logger) {
 578         Logger l = logger;
 579         while (l.getParent() != null) {
 580             l = l.getParent();
 581         }
 582         assertEquals("", l.getName());
 583     }
 584 
 585     public static class TestError extends RuntimeException {
 586         public TestError(String msg) {
 587             super(msg);
 588         }
 589     }
 590 
 591     public static void assertNotNull(Object obj) {
 592         if (obj == null) throw new NullPointerException();
 593     }
 594 
 595     public static void assertNull(Object obj) {
 596         if (obj != null) throw new TestError("Null expected, got "+obj);
 597     }
 598 
 599     public static void assertEquals(Object o1, Object o2) {
 600         if (o1 != o2) {
 601             throw new TestError(o1 + " != " + o2);
 602         }
 603     }
 604 
 605     public static void assertNotEquals(Object o1, Object o2) {
 606         if (o1 == o2) {
 607             throw new TestError(o1 + " == " + o2);
 608         }
 609     }
 610 }