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