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 8019945 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 for (int j = 0; j<3; j++) { 436 Bridge.changeContext(); 437 438 // this is not a supported configuration: 439 // We are in an applet context with several log managers. 440 // We however need to check our assumptions... 441 442 // Applet context => root logger and global logger should also be null. 443 444 Logger expected = (System.getSecurityManager() == null ? global : null); 445 Logger logger3 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 446 Logger logger3b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 447 assertEquals(expected, logger3); 448 assertEquals(expected, logger3b); 449 Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME); 450 manager.addLogger(global2); 451 Logger logger4 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 452 Logger logger4b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 453 assertNotNull(logger4); 454 assertNotNull(logger4b); 455 expected = (System.getSecurityManager() == null ? global : global2);; 456 assertEquals(logger4, expected); 457 assertEquals(logger4b, expected); 458 459 Logger logger5 = manager.getLogger(""); 460 Logger logger5b = manager.getLogger(""); 461 Logger expectedRoot = null; 462 assertEquals(logger5, expectedRoot); 463 assertEquals(logger5b, expectedRoot); 464 } 465 466 } 467 } 468 469 /** 470 * This test is designed to test the behavior of additional LogManager instances. 471 * It must be noted that if the security manager is off, then calling 472 * Bridge.changeContext() has actually no effect - which explains why we have 473 * some differences between the cases security manager on & security manager 474 * off. 475 **/ 476 public static void testSeven() { 477 for (int i=0; i<3 ; i++) { 478 Bridge.desactivate(); 479 LogManager manager = new LogManager() {}; 480 Logger logger1 = manager.getLogger(""); 481 Logger logger1b = manager.getLogger(""); 482 assertNull(logger1); 483 assertNull(logger1b); 484 Logger global = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME); 485 manager.addLogger(global); 486 Logger logger2 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 487 Logger logger2b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 488 assertNotNull(logger2); 489 assertNotNull(logger2b); 490 assertEquals(logger2, global); 491 assertEquals(logger2b, global); 492 Logger logger3 = manager.getLogger(""); 493 Logger logger3b = manager.getLogger(""); 494 assertNull(logger3); 495 assertNull(logger3b); 496 Logger root = new Bridge.CustomLogger(""); 497 manager.addLogger(root); 498 Logger logger4 = manager.getLogger(""); 499 Logger logger4b = manager.getLogger(""); 500 assertNotNull(logger4); 501 assertNotNull(logger4b); 502 assertEquals(logger4, root); 503 assertEquals(logger4b, root); 504 505 for (int j = 0 ; j < 3 ; j++) { 506 Bridge.changeContext(); 507 508 // this is not a supported configuration: 509 // We are in an applet context with several log managers. 510 // We however need to check our assumptions... 511 512 // Applet context => root logger and global logger should also be null. 513 514 Logger logger5 = manager.getLogger(""); 515 Logger logger5b = manager.getLogger(""); 516 Logger expectedRoot = (System.getSecurityManager() == null ? root : null); 517 assertEquals(logger5, expectedRoot); 518 assertEquals(logger5b, expectedRoot); 519 520 if (System.getSecurityManager() != null) { 521 assertNull(manager.getLogger(Logger.GLOBAL_LOGGER_NAME)); 522 } else { 523 assertEquals(global, manager.getLogger(Logger.GLOBAL_LOGGER_NAME)); 524 } 525 526 Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME); 527 manager.addLogger(global2); 528 Logger logger6 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 529 Logger logger6b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 530 Logger expectedGlobal = (System.getSecurityManager() == null ? global : global2); 531 532 assertNotNull(logger6); 533 assertNotNull(logger6b); 534 assertEquals(logger6, expectedGlobal); 535 assertEquals(logger6b, expectedGlobal); 536 if (System.getSecurityManager() != null) { 537 assertNull(manager.getLogger("")); 538 } else { 539 assertEquals(root, manager.getLogger("")); 540 } 541 542 Logger root2 = new Bridge.CustomLogger(""); 543 manager.addLogger(root2); 544 expectedRoot = (System.getSecurityManager() == null ? root : root2); 545 Logger logger7 = manager.getLogger(""); 546 Logger logger7b = manager.getLogger(""); 547 assertNotNull(logger7); 548 assertNotNull(logger7b); 549 assertEquals(logger7, expectedRoot); 550 assertEquals(logger7b, expectedRoot); 551 } 552 } 553 } 554 555 public static void testParent(Logger logger) { 556 Logger l = logger; 557 while (l.getParent() != null) { 558 l = l.getParent(); 559 } 560 assertEquals("", l.getName()); 561 } 562 563 public static class TestError extends RuntimeException { 564 public TestError(String msg) { 565 super(msg); 566 } 567 } 568 569 public static void assertNotNull(Object obj) { 570 if (obj == null) throw new NullPointerException(); 571 } 572 573 public static void assertNull(Object obj) { 574 if (obj != null) throw new TestError("Null expected, got "+obj); 575 } 576 577 public static void assertEquals(Object o1, Object o2) { 578 if (o1 != o2) { 579 throw new TestError(o1 + " != " + o2); 580 } 581 } 582 583 public static void assertNotEquals(Object o1, Object o2) { 584 if (o1 == o2) { 585 throw new TestError(o1 + " == " + o2); 586 } 587 } 588 }