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 114 @Override 115 public Object getAppletContext() { return active ? exc : null; } 116 @Override 117 public Object get(Object o) { return exc.get(o); } 118 @Override 119 public void put(Object o, Object o1) { exc.put(o, o1); } 120 @Override 121 public void remove(Object o) { exc.remove(o); } 122 @Override 123 public boolean isDisposed() { return false; } 124 @Override 125 public boolean isMainAppContext() { return !active || exc == null; } 126 } 127 128 final static JavaAWTAccessStub javaAwtAccess = new JavaAWTAccessStub(); 129 public static void init() { 130 SharedSecrets.setJavaAWTAccess(javaAwtAccess); 131 if (System.getProperty("test.security", "on").equals("on")) { 132 Policy p = new SimplePolicy(new LoggingPermission("control", null), 133 new RuntimePermission("setContextClassLoader"), 134 new RuntimePermission("shutdownHooks")); 135 Policy.setPolicy(p); 136 System.setSecurityManager(new SecurityManager()); 137 } 138 } 139 140 public static void changeContext() { 141 System.out.println("... Switching to a new applet context ..."); 142 javaAwtAccess.active = true; 143 javaAwtAccess.exc = new JavaAWTAccessStub.TestExc(); 144 } 145 146 public static void desactivate() { 147 System.out.println("... Running with no applet context ..."); 148 javaAwtAccess.exc = null; 149 javaAwtAccess.active = false; 150 } 151 152 public static class CustomAnonymousLogger extends Logger { 153 public CustomAnonymousLogger() { 154 this(""); 155 } 156 public CustomAnonymousLogger(String name) { 157 super(null, null); 158 System.out.println( " LogManager: " +LogManager.getLogManager()); 159 System.out.println( " getLogger: " +LogManager.getLogManager().getLogger(name)); 160 setParent(LogManager.getLogManager().getLogger(name)); 161 } 162 } 163 164 public static class CustomLogger extends Logger { 165 CustomLogger(String name) { 166 super(name, null); 167 } 168 } 169 } 170 171 public static enum TestCase { 172 LoadingApplet, LoadingMain, One, Two, Three, Four, Five, Six, Seven; 173 public void test() { 174 switch(this) { 175 // When run - each of these two tests must be 176 // run before any other tests and before each other. 177 case LoadingApplet: testLoadingApplet(); break; 178 case LoadingMain: testLoadingMain(); break; 179 case One: testOne(); break; 180 case Two: testTwo(); break; 181 case Three: testThree(); break; 182 case Four: testFour(); break; 183 case Five: testFive(); break; 184 case Six: testSix(); break; 185 case Seven: testSeven(); break; 186 } 187 } 188 public String describe() { 189 switch(this) { 190 case LoadingApplet: 191 return "Test that when the LogManager class is" 192 + " loaded in an applet thread first," 193 + "\n all LoggerContexts are correctly initialized"; 194 case LoadingMain: 195 return "Test that when the LogManager class is" 196 + " loaded in the main thread first," 197 + "\n all LoggerContexts are correctly initialized"; 198 case One: 199 return "Test that Logger.getAnonymousLogger()" 200 + " and new CustomAnonymousLogger() don't throw NPE"; 201 case Two: 202 return "Test that Logger.getLogger(\"\")" 203 + " does not return null nor throws NPE"; 204 case Three: 205 return "Test that LogManager.getLogManager().getLogger(\"\")" 206 + " does not return null nor throws NPE"; 207 case Four: 208 return "Test that Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)" 209 + " does not return null,\n and that" 210 + " new CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME)" 211 + " does not throw NPE"; 212 case Five: 213 return "Test that LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME)" 214 + "\n does not return null nor throws NPE"; 215 case Six: 216 return "Test that manager.getLogger(Logger.GLOBAL_LOGGER_NAME)" 217 + " returns null\n when manager is not the default" 218 + " LogManager instance.\n" 219 + "Test adding a new logger named \"global\" in that" 220 + " non default instance."; 221 case Seven: return "Test that manager.getLogger(\"\")" 222 + " returns null\n when manager is not the default" 223 + " LogManager instance.\n" 224 + "Test adding a new logger named \"\" in that" 225 + " non default instance."; 226 default: return "Undefined"; 227 } 228 } 229 }; 230 231 /** 232 * @param args the command line arguments 233 */ 234 public static void main(String[] args) { 235 Bridge.init(); 236 EnumSet<TestCase> tests = EnumSet.noneOf(TestCase.class); 237 for (String arg : args) { 238 tests.add(TestCase.valueOf(arg)); 239 } 240 if (args.length == 0) { 241 tests = EnumSet.complementOf(EnumSet.of(TestCase.LoadingMain)); 242 } 243 final EnumSet<TestCase> loadingTests = 244 EnumSet.of(TestCase.LoadingApplet, TestCase.LoadingMain); 245 int testrun = 0; 246 for (TestCase test : tests) { 247 if (loadingTests.contains(test)) { 248 if (testrun > 0) { 249 throw new UnsupportedOperationException("Test case " 250 + test + " must be executed first!"); 251 } 252 } 253 System.out.println("Testing "+ test+": "); 254 System.out.println(test.describe()); 255 try { 256 test.test(); 257 } catch (Exception x) { 258 throw new Error(String.valueOf(test) 259 + (System.getSecurityManager() == null ? " without " : " with ") 260 + "security failed: "+x+"\n "+"FAILED: "+test.describe()+"\n", x); 261 } finally { 262 testrun++; 263 } 264 Bridge.changeContext(); 265 System.out.println("PASSED: "+ test); 266 } 267 } 268 269 public static void testLoadingApplet() { 270 Bridge.changeContext(); 271 272 Logger bar = new Bridge.CustomLogger("com.foo.Bar"); 273 LogManager.getLogManager().addLogger(bar); 274 assertNotNull(bar.getParent()); 275 testParent(bar); 276 testParent(LogManager.getLogManager().getLogger("global")); 277 testParent(LogManager.getLogManager().getLogger(bar.getName())); 278 279 Bridge.desactivate(); 280 281 Logger foo = new Bridge.CustomLogger("com.foo.Foo"); 282 boolean b = LogManager.getLogManager().addLogger(foo); 283 assertEquals(Boolean.TRUE, Boolean.valueOf(b)); 284 assertNotNull(foo.getParent()); 285 testParent(foo); 286 testParent(LogManager.getLogManager().getLogger("global")); 287 testParent(LogManager.getLogManager().getLogger(foo.getName())); 288 } 289 290 public static void testLoadingMain() { 291 Bridge.desactivate(); 292 293 Logger bar = new Bridge.CustomLogger("com.foo.Bar"); 294 LogManager.getLogManager().addLogger(bar); 295 assertNotNull(bar.getParent()); 296 testParent(bar); 297 testParent(LogManager.getLogManager().getLogger("global")); 298 testParent(LogManager.getLogManager().getLogger(bar.getName())); 299 300 Bridge.changeContext(); 301 302 Logger foo = new Bridge.CustomLogger("com.foo.Foo"); 303 boolean b = LogManager.getLogManager().addLogger(foo); 304 assertEquals(Boolean.TRUE, Boolean.valueOf(b)); 305 assertNotNull(foo.getParent()); 306 testParent(foo); 307 testParent(LogManager.getLogManager().getLogger("global")); 308 testParent(LogManager.getLogManager().getLogger(foo.getName())); 309 310 } 311 312 public static void testOne() { 313 for (int i=0; i<3 ; i++) { 314 Logger logger1 = Logger.getAnonymousLogger(); 315 Logger logger1b = Logger.getAnonymousLogger(); 316 Bridge.changeContext(); 317 Logger logger2 = Logger.getAnonymousLogger(); 318 Logger logger2b = Logger.getAnonymousLogger(); 319 Bridge.changeContext(); 320 Logger logger3 = new Bridge.CustomAnonymousLogger(); 321 Logger logger3b = new Bridge.CustomAnonymousLogger(); 322 Bridge.changeContext(); 323 Logger logger4 = new Bridge.CustomAnonymousLogger(); 324 Logger logger4b = new Bridge.CustomAnonymousLogger(); 325 } 326 } 327 328 329 public static void testTwo() { 330 for (int i=0; i<3 ; i++) { 331 Logger logger1 = Logger.getLogger(""); 332 Logger logger1b = Logger.getLogger(""); 333 assertNotNull(logger1); 334 assertNotNull(logger1b); 335 assertEquals(logger1, logger1b); 336 Bridge.changeContext(); 337 Logger logger2 = Logger.getLogger(""); 338 Logger logger2b = Logger.getLogger(""); 339 assertNotNull(logger2); 340 assertNotNull(logger2b); 341 assertEquals(logger2, logger2b); 342 assertEquals(logger1, logger2); 343 } 344 } 345 346 public static void testThree() { 347 for (int i=0; i<3 ; i++) { 348 Logger logger1 = LogManager.getLogManager().getLogger(""); 349 Logger logger1b = LogManager.getLogManager().getLogger(""); 350 assertNotNull(logger1); 351 assertNotNull(logger1b); 352 assertEquals(logger1, logger1b); 353 Bridge.changeContext(); 354 Logger logger2 = LogManager.getLogManager().getLogger(""); 355 Logger logger2b = LogManager.getLogManager().getLogger(""); 356 assertNotNull(logger2); 357 assertNotNull(logger2b); 358 assertEquals(logger2, logger2b); 359 assertEquals(logger1, logger2); 360 } 361 } 362 363 public static void testFour() { 364 for (int i=0; i<3 ; i++) { 365 Logger logger1 = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); 366 Logger logger1b = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); 367 assertNotNull(logger1); 368 assertNotNull(logger1b); 369 assertEquals(logger1, logger1b); 370 Bridge.changeContext(); 371 372 Logger logger2 = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); 373 Logger logger2b = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); 374 assertNotNull(logger2); 375 assertNotNull(logger2b); 376 assertEquals(logger2, logger2b); 377 378 assertEquals(logger1, logger2); 379 380 Bridge.changeContext(); 381 Logger logger3 = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME); 382 Logger logger3b = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME); 383 Bridge.changeContext(); 384 Logger logger4 = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME); 385 Logger logger4b = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME); 386 } 387 } 388 389 public static void testFive() { 390 for (int i=0; i<3 ; i++) { 391 Logger logger1 = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME); 392 Logger logger1b = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME); 393 assertNotNull(logger1); 394 assertNotNull(logger1b); 395 assertEquals(logger1, logger1b); 396 397 Bridge.changeContext(); 398 399 Logger logger2 = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME); 400 Logger logger2b = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME); 401 assertNotNull(logger2); 402 assertNotNull(logger2b); 403 assertEquals(logger2, logger2b); 404 405 assertEquals(logger1, logger2); 406 } 407 } 408 409 /** 410 * This test is designed to test the behavior of additional LogManager instances. 411 * It must be noted that if the security manager is off, then calling 412 * Bridge.changeContext() has actually no effect - which explains why we have 413 * some differences between the cases security manager on & security manager 414 * off. 415 **/ 416 public static void testSix() { 417 for (int i=0; i<3 ; i++) { 418 Bridge.desactivate(); 419 LogManager manager = new LogManager() {}; 420 Logger logger1 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 421 Logger logger1b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 422 assertNull(logger1); 423 assertNull(logger1b); 424 Logger global = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME); 425 manager.addLogger(global); 426 Logger logger2 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 427 Logger logger2b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 428 assertNotNull(logger2); 429 assertNotNull(logger2b); 430 assertEquals(logger2, global); 431 assertEquals(logger2b, global); 432 assertNull(manager.getLogger("")); 433 assertNull(manager.getLogger("")); 434 435 Bridge.changeContext(); 436 437 // this is not a supported configuration: 438 // We are in an applet context with several log managers. 439 // We however need to check our assumptions... 440 441 // Applet context => root logger and global logger are not null. 442 // root == LogManager.getLogManager().rootLogger 443 // global == Logger.global 444 445 Logger logger3 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 446 Logger logger3b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 447 assertNotNull(logger3); 448 assertNotNull(logger3b); 449 Logger expected = (System.getSecurityManager() != null 450 ? Logger.getGlobal() 451 : global); 452 assertEquals(logger3, expected); // in applet context, we will not see 453 // the LogManager's custom global logger added above... 454 assertEquals(logger3b, expected); // in applet context, we will not see 455 // the LogManager's custom global logger added above... 456 Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME); 457 manager.addLogger(global2); // adding a global logger will not work in applet context 458 // we will always get back the global logger. 459 // this could be considered as a bug... 460 Logger logger4 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 461 Logger logger4b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 462 assertNotNull(logger4); 463 assertNotNull(logger4b); 464 assertEquals(logger4, expected); // adding a global logger will not work in applet context 465 assertEquals(logger4b, expected); // adding a global logger will not work in applet context 466 467 Logger logger5 = manager.getLogger(""); 468 Logger logger5b = manager.getLogger(""); 469 Logger expectedRoot = (System.getSecurityManager() != null 470 ? LogManager.getLogManager().getLogger("") 471 : null); 472 assertEquals(logger5, expectedRoot); 473 assertEquals(logger5b, expectedRoot); 474 475 } 476 } 477 478 /** 479 * This test is designed to test the behavior of additional LogManager instances. 480 * It must be noted that if the security manager is off, then calling 481 * Bridge.changeContext() has actually no effect - which explains why we have 482 * some differences between the cases security manager on & security manager 483 * off. 484 **/ 485 public static void testSeven() { 486 for (int i=0; i<3 ; i++) { 487 Bridge.desactivate(); 488 LogManager manager = new LogManager() {}; 489 Logger logger1 = manager.getLogger(""); 490 Logger logger1b = manager.getLogger(""); 491 assertNull(logger1); 492 assertNull(logger1b); 493 Logger global = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME); 494 manager.addLogger(global); 495 Logger logger2 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 496 Logger logger2b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 497 assertNotNull(logger2); 498 assertNotNull(logger2b); 499 assertEquals(logger2, global); 500 assertEquals(logger2b, global); 501 Logger logger3 = manager.getLogger(""); 502 Logger logger3b = manager.getLogger(""); 503 assertNull(logger3); 504 assertNull(logger3b); 505 Logger root = new Bridge.CustomLogger(""); 506 manager.addLogger(root); 507 Logger logger4 = manager.getLogger(""); 508 Logger logger4b = manager.getLogger(""); 509 assertNotNull(logger4); 510 assertNotNull(logger4b); 511 assertEquals(logger4, root); 512 assertEquals(logger4b, root); 513 514 Bridge.changeContext(); 515 516 // this is not a supported configuration: 517 // We are in an applet context with several log managers. 518 // We haowever need to check our assumptions... 519 520 // Applet context => root logger and global logger are not null. 521 // root == LogManager.getLogManager().rootLogger 522 // global == Logger.global 523 524 Logger logger5 = manager.getLogger(""); 525 Logger logger5b = manager.getLogger(""); 526 Logger expectedRoot = (System.getSecurityManager() != null 527 ? LogManager.getLogManager().getLogger("") 528 : root); 529 530 assertNotNull(logger5); 531 assertNotNull(logger5b); 532 assertEquals(logger5, expectedRoot); 533 assertEquals(logger5b, expectedRoot); 534 if (System.getSecurityManager() != null) { 535 assertNotEquals(logger5, root); 536 assertNotEquals(logger5b, root); 537 } 538 539 Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME); 540 manager.addLogger(global2); // adding a global logger will not work in applet context 541 // we will always get back the global logger. 542 // this could be considered as a bug... 543 Logger logger6 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 544 Logger logger6b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 545 Logger expectedGlobal = (System.getSecurityManager() != null 546 ? Logger.getGlobal() 547 : global); 548 assertNotNull(logger6); 549 assertNotNull(logger6b); 550 assertEquals(logger6, expectedGlobal); // adding a global logger will not work in applet context 551 assertEquals(logger6b, expectedGlobal); // adding a global logger will not work in applet context 552 553 Logger root2 = new Bridge.CustomLogger(""); 554 manager.addLogger(root2); // adding a root logger will not work in applet context 555 // we will always get back the default manager's root logger. 556 // this could be considered as a bug... 557 Logger logger7 = manager.getLogger(""); 558 Logger logger7b = manager.getLogger(""); 559 assertNotNull(logger7); 560 assertNotNull(logger7b); 561 assertEquals(logger7, expectedRoot); // adding a global logger will not work in applet context 562 assertEquals(logger7b, expectedRoot); // adding a global logger will not work in applet context 563 assertNotEquals(logger7, root2); 564 assertNotEquals(logger7b, root2); 565 } 566 } 567 568 public static void testParent(Logger logger) { 569 Logger l = logger; 570 while (l.getParent() != null) { 571 l = l.getParent(); 572 } 573 assertEquals("", l.getName()); 574 } 575 576 public static class TestError extends RuntimeException { 577 public TestError(String msg) { 578 super(msg); 579 } 580 } 581 582 public static void assertNotNull(Object obj) { 583 if (obj == null) throw new NullPointerException(); 584 } 585 586 public static void assertNull(Object obj) { 587 if (obj != null) throw new TestError("Null expected, got "+obj); 588 } 589 590 public static void assertEquals(Object o1, Object o2) { 591 if (o1 != o2) { 592 throw new TestError(o1 + " != " + o2); 593 } 594 } 595 596 public static void assertNotEquals(Object o1, Object o2) { 597 if (o1 == o2) { 598 throw new TestError(o1 + " == " + o2); 599 } 600 } 601 }