1 /* 2 * Copyright (c) 2015, 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 import java.security.AccessControlException; 24 import java.security.AccessController; 25 import java.security.CodeSource; 26 import java.security.Permission; 27 import java.security.PermissionCollection; 28 import java.security.Permissions; 29 import java.security.Policy; 30 import java.security.PrivilegedAction; 31 import java.security.ProtectionDomain; 32 import java.util.Arrays; 33 import java.util.Collections; 34 import java.util.Enumeration; 35 import java.util.HashMap; 36 import java.util.Map; 37 import java.util.Objects; 38 import java.util.Queue; 39 import java.util.ResourceBundle; 40 import java.util.concurrent.ArrayBlockingQueue; 41 import java.util.concurrent.ConcurrentHashMap; 42 import java.util.concurrent.atomic.AtomicBoolean; 43 import java.util.concurrent.atomic.AtomicLong; 44 import java.util.function.Supplier; 45 import java.lang.System.LoggerFinder; 46 import java.lang.System.Logger; 47 import java.lang.System.Logger.Level; 48 import java.util.stream.Stream; 49 import java.lang.reflect.Module; 50 import java.security.AllPermission; 51 52 /** 53 * @test 54 * @bug 8140364 55 * @summary Tests loggers returned by System.getLogger with a naive implementation 56 * of LoggerFinder, and in particular the default body of 57 * System.Logger methods. 58 * @build CustomLoggerTest AccessSystemLogger 59 * @run driver AccessSystemLogger 60 * @run main/othervm -Xbootclasspath/a:boot CustomLoggerTest NOSECURITY 61 * @run main/othervm -Xbootclasspath/a:boot CustomLoggerTest NOPERMISSIONS 62 * @run main/othervm -Xbootclasspath/a:boot CustomLoggerTest WITHPERMISSIONS 63 * @author danielfuchs 64 */ 65 public class CustomLoggerTest { 66 67 final static AtomicLong sequencer = new AtomicLong(); 68 final static boolean VERBOSE = false; 69 static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() { 70 @Override 71 protected AtomicBoolean initialValue() { 72 return new AtomicBoolean(false); 73 } 74 }; 75 static final ThreadLocal<AtomicBoolean> allowAll = new ThreadLocal<AtomicBoolean>() { 76 @Override 77 protected AtomicBoolean initialValue() { 78 return new AtomicBoolean(false); 79 } 80 }; 81 82 public static class MyBundle extends ResourceBundle { 83 84 final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>(); 85 86 @Override 87 protected Object handleGetObject(String key) { 88 if (key.contains(" (translated)")) { 89 throw new RuntimeException("Unexpected key: " + key); 90 } 91 return map.computeIfAbsent(key, k -> k + " (translated)"); 92 } 93 94 @Override 95 public Enumeration<String> getKeys() { 96 return Collections.enumeration(map.keySet()); 97 } 98 99 } 100 public static class MyLoggerBundle extends MyBundle { 101 102 } 103 104 105 public static class BaseLoggerFinder extends LoggerFinder { 106 final ConcurrentHashMap<String, LoggerImpl> system = new ConcurrentHashMap<>(); 107 final ConcurrentHashMap<String, LoggerImpl> user = new ConcurrentHashMap<>(); 108 public Queue<LogEvent> eventQueue = new ArrayBlockingQueue<>(128); 109 110 // changing this to true requires changing the logic in the 111 // test in order to load this class with a protection domain 112 // that has the CONTROL_PERMISSION (e.g. by using a custom 113 // system class loader. 114 final boolean doChecks = false; 115 116 public static final class LogEvent { 117 118 public LogEvent() { 119 this(sequencer.getAndIncrement()); 120 } 121 122 LogEvent(long sequenceNumber) { 123 this.sequenceNumber = sequenceNumber; 124 } 125 126 long sequenceNumber; 127 boolean isLoggable; 128 String loggerName; 129 Level level; 130 ResourceBundle bundle; 131 Throwable thrown; 132 Object[] args; 133 Supplier<String> supplier; 134 String msg; 135 136 Object[] toArray() { 137 return new Object[] { 138 sequenceNumber, 139 isLoggable, 140 loggerName, 141 level, 142 bundle, 143 thrown, 144 args, 145 supplier, 146 msg, 147 }; 148 } 149 150 @Override 151 public String toString() { 152 return Arrays.deepToString(toArray()); 153 } 154 155 156 157 @Override 158 public boolean equals(Object obj) { 159 return obj instanceof LogEvent 160 && Objects.deepEquals(this.toArray(), ((LogEvent)obj).toArray()); 161 } 162 163 @Override 164 public int hashCode() { 165 return Objects.hash(toArray()); 166 } 167 168 169 public static LogEvent of(boolean isLoggable, String name, 170 Level level, ResourceBundle bundle, 171 String key, Throwable thrown) { 172 LogEvent evt = new LogEvent(); 173 evt.isLoggable = isLoggable; 174 evt.loggerName = name; 175 evt.level = level; 176 evt.args = null; 177 evt.bundle = bundle; 178 evt.thrown = thrown; 179 evt.supplier = null; 180 evt.msg = key; 181 return evt; 182 } 183 184 public static LogEvent of(boolean isLoggable, String name, 185 Level level, ResourceBundle bundle, 186 String key, Object... params) { 187 LogEvent evt = new LogEvent(); 188 evt.isLoggable = isLoggable; 189 evt.loggerName = name; 190 evt.level = level; 191 evt.args = params; 192 evt.bundle = bundle; 193 evt.thrown = null; 194 evt.supplier = null; 195 evt.msg = key; 196 return evt; 197 } 198 199 public static LogEvent of(long sequenceNumber, 200 boolean isLoggable, String name, 201 Level level, ResourceBundle bundle, 202 String key, Supplier<String> supplier, 203 Throwable thrown, Object... params) { 204 LogEvent evt = new LogEvent(sequenceNumber); 205 evt.loggerName = name; 206 evt.level = level; 207 evt.args = params; 208 evt.bundle = bundle; 209 evt.thrown = thrown; 210 evt.supplier = supplier; 211 evt.msg = key; 212 evt.isLoggable = isLoggable; 213 return evt; 214 } 215 216 } 217 218 public class LoggerImpl implements Logger { 219 private final String name; 220 private Level level = Level.INFO; 221 222 public LoggerImpl(String name) { 223 this.name = name; 224 } 225 226 @Override 227 public String getName() { 228 return name; 229 } 230 231 @Override 232 public boolean isLoggable(Level level) { 233 return this.level != Level.OFF && this.level.getSeverity() <= level.getSeverity(); 234 } 235 236 @Override 237 public void log(Level level, ResourceBundle bundle, String key, Throwable thrown) { 238 log(LogEvent.of(isLoggable(level), this.name, level, bundle, key, thrown)); 239 } 240 241 @Override 242 public void log(Level level, ResourceBundle bundle, String format, Object... params) { 243 log(LogEvent.of(isLoggable(level), name, level, bundle, format, params)); 244 } 245 246 void log(LogEvent event) { 247 eventQueue.add(event); 248 } 249 } 250 251 @Override 252 public Logger getLogger(String name, Module caller) { 253 // We should check the permission to obey the API contract, but 254 // what happens if we don't? 255 // This is the main difference compared with what we test in 256 // java/lang/System/LoggerFinder/BaseLoggerFinderTest 257 SecurityManager sm = System.getSecurityManager(); 258 if (sm != null && doChecks) { 259 sm.checkPermission(SimplePolicy.LOGGERFINDER_PERMISSION); 260 } 261 262 final boolean before = allowAll.get().getAndSet(true); 263 final ClassLoader callerLoader; 264 try { 265 callerLoader = caller.getClassLoader(); 266 } finally { 267 allowAll.get().set(before); 268 } 269 if (callerLoader == null) { 270 return system.computeIfAbsent(name, (n) -> new LoggerImpl(n)); 271 } else { 272 return user.computeIfAbsent(name, (n) -> new LoggerImpl(n)); 273 } 274 } 275 } 276 277 static final AccessSystemLogger accessSystemLogger = new AccessSystemLogger(); 278 279 static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS}; 280 281 static void setSecurityManager() { 282 if (System.getSecurityManager() == null) { 283 Policy.setPolicy(new SimplePolicy(allowControl, allowAll)); 284 System.setSecurityManager(new SecurityManager()); 285 } 286 } 287 public static void main(String[] args) { 288 if (args.length == 0) 289 args = new String[] { 290 "NOSECURITY", 291 "NOPERMISSIONS", 292 "WITHPERMISSIONS" 293 }; 294 295 // 1. Obtain destination loggers directly from the LoggerFinder 296 // - LoggerFinder.getLogger("foo", type) 297 BaseLoggerFinder provider = 298 BaseLoggerFinder.class.cast(LoggerFinder.getLoggerFinder()); 299 BaseLoggerFinder.LoggerImpl appSink = 300 BaseLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", CustomLoggerTest.class.getModule())); 301 BaseLoggerFinder.LoggerImpl sysSink = 302 BaseLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class.getModule())); 303 304 305 Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> { 306 switch (testCase) { 307 case NOSECURITY: 308 System.out.println("\n*** Without Security Manager\n"); 309 test(provider, true, appSink, sysSink); 310 System.out.println("Tetscase count: " + sequencer.get()); 311 break; 312 case NOPERMISSIONS: 313 System.out.println("\n*** With Security Manager, without permissions\n"); 314 setSecurityManager(); 315 test(provider, false, appSink, sysSink); 316 System.out.println("Tetscase count: " + sequencer.get()); 317 break; 318 case WITHPERMISSIONS: 319 System.out.println("\n*** With Security Manager, with control permission\n"); 320 setSecurityManager(); 321 final boolean control = allowControl.get().get(); 322 try { 323 allowControl.get().set(true); 324 test(provider, true, appSink, sysSink); 325 } finally { 326 allowControl.get().set(control); 327 } 328 break; 329 default: 330 throw new RuntimeException("Unknown test case: " + testCase); 331 } 332 }); 333 System.out.println("\nPASSED: Tested " + sequencer.get() + " cases."); 334 } 335 336 public static void test(BaseLoggerFinder provider, boolean hasRequiredPermissions, 337 BaseLoggerFinder.LoggerImpl appSink, BaseLoggerFinder.LoggerImpl sysSink) { 338 339 ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName()); 340 final Map<Logger, String> loggerDescMap = new HashMap<>(); 341 342 343 // 1. Test loggers returned by: 344 // - System.getLogger("foo") 345 // - and AccessSystemLogger.getLogger("foo") 346 Logger appLogger1 = System.getLogger("foo"); 347 loggerDescMap.put(appLogger1, "System.getLogger(\"foo\");"); 348 349 Logger sysLogger1 = null; 350 try { 351 sysLogger1 = accessSystemLogger.getLogger("foo"); 352 loggerDescMap.put(sysLogger1, "AccessSystemLogger.getLogger(\"foo\")"); 353 } catch (AccessControlException acx) { 354 if (hasRequiredPermissions) { 355 throw new RuntimeException("Unexpected security exception: ", acx); 356 } 357 if (!acx.getPermission().equals(SimplePolicy.LOGGERFINDER_PERMISSION)) { 358 throw new RuntimeException("Unexpected permission in exception: " + acx, acx); 359 } 360 throw new RuntimeException("unexpected exception: " + acx, acx); 361 } 362 363 if (appLogger1 == sysLogger1) { 364 throw new RuntimeException("identical loggers"); 365 } 366 367 if (provider.system.contains(appLogger1)) { 368 throw new RuntimeException("app logger in system map"); 369 } 370 if (provider.user.contains(sysLogger1)) { 371 throw new RuntimeException("sys logger in appplication map"); 372 } 373 if (provider.system.contains(sysLogger1)) { 374 // sysLogger should be a a LazyLoggerWrapper 375 throw new RuntimeException("sys logger is in system map (should be wrapped)"); 376 } 377 378 379 // 2. Test loggers returned by: 380 // - System.getLogger(\"foo\", loggerBundle) 381 // - and AccessSystemLogger.getLogger(\"foo\", loggerBundle) 382 Logger appLogger2 = 383 System.getLogger("foo", loggerBundle); 384 loggerDescMap.put(appLogger2, "System.getLogger(\"foo\", loggerBundle)"); 385 386 Logger sysLogger2 = null; 387 try { 388 sysLogger2 = accessSystemLogger.getLogger("foo", loggerBundle); 389 loggerDescMap.put(sysLogger2, "AccessSystemLogger.getLogger(\"foo\", loggerBundle)"); 390 } catch (AccessControlException acx) { 391 if (hasRequiredPermissions) { 392 throw new RuntimeException("Unexpected security exception: ", acx); 393 } 394 if (!acx.getPermission().equals(SimplePolicy.LOGGERFINDER_PERMISSION)) { 395 throw new RuntimeException("Unexpected permission in exception: " + acx, acx); 396 } 397 throw new RuntimeException("unexpected exception: " + acx, acx); 398 } 399 if (appLogger2 == sysLogger2) { 400 throw new RuntimeException("identical loggers"); 401 } 402 if (appLogger2 == appSink) { 403 throw new RuntimeException("identical loggers"); 404 } 405 if (sysLogger2 == sysSink) { 406 throw new RuntimeException("identical loggers"); 407 } 408 409 if (provider.system.contains(appLogger2)) { 410 throw new RuntimeException("localized app logger in system map"); 411 } 412 if (provider.user.contains(appLogger2)) { 413 throw new RuntimeException("localized app logger in appplication map"); 414 } 415 if (provider.user.contains(sysLogger2)) { 416 throw new RuntimeException("localized sys logger in appplication map"); 417 } 418 if (provider.system.contains(sysLogger2)) { 419 throw new RuntimeException("localized sys logger not in system map"); 420 } 421 422 testLogger(provider, loggerDescMap, "foo", null, appLogger1, appSink); 423 testLogger(provider, loggerDescMap, "foo", null, sysLogger1, sysSink); 424 testLogger(provider, loggerDescMap, "foo", loggerBundle, appLogger2, appSink); 425 testLogger(provider, loggerDescMap, "foo", loggerBundle, sysLogger2, sysSink); 426 } 427 428 public static class Foo { 429 430 } 431 432 static void verbose(String msg) { 433 if (VERBOSE) { 434 System.out.println(msg); 435 } 436 } 437 438 // Calls the 8 methods defined on Logger and verify the 439 // parameters received by the underlying BaseLoggerFinder.LoggerImpl 440 // logger. 441 private static void testLogger(BaseLoggerFinder provider, 442 Map<Logger, String> loggerDescMap, 443 String name, 444 ResourceBundle loggerBundle, 445 Logger logger, 446 BaseLoggerFinder.LoggerImpl sink) { 447 448 System.out.println("Testing " + loggerDescMap.get(logger)); 449 450 Foo foo = new Foo(); 451 String fooMsg = foo.toString(); 452 for (Level loggerLevel : Level.values()) { 453 sink.level = loggerLevel; 454 for (Level messageLevel : Level.values()) { 455 String desc = "logger.log(messageLevel, foo): loggerLevel=" 456 + loggerLevel+", messageLevel="+messageLevel; 457 BaseLoggerFinder.LogEvent expected = 458 BaseLoggerFinder.LogEvent.of( 459 sequencer.get(), 460 messageLevel.compareTo(loggerLevel) >= 0, 461 name, messageLevel, (ResourceBundle)null, 462 fooMsg, null, (Throwable)null, (Object[])null); 463 logger.log(messageLevel, foo); 464 if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 465 if (provider.eventQueue.poll() != null) { 466 throw new RuntimeException("unexpected event in queue for " + desc); 467 } 468 } else { 469 BaseLoggerFinder.LogEvent actual = provider.eventQueue.poll(); 470 if (!expected.equals(actual)) { 471 throw new RuntimeException("mismatch for " + desc 472 + "\n\texpected=" + expected 473 + "\n\t actual=" + actual); 474 } else { 475 verbose("Got expected results for " 476 + desc + "\n\t" + expected); 477 } 478 } 479 } 480 } 481 482 String msg = "blah"; 483 for (Level loggerLevel : Level.values()) { 484 sink.level = loggerLevel; 485 for (Level messageLevel : Level.values()) { 486 String desc = "logger.log(messageLevel, \"blah\"): loggerLevel=" 487 + loggerLevel+", messageLevel="+messageLevel; 488 BaseLoggerFinder.LogEvent expected = 489 BaseLoggerFinder.LogEvent.of( 490 sequencer.get(), 491 messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF, 492 name, messageLevel, loggerBundle, 493 msg, null, (Throwable)null, (Object[])null); 494 logger.log(messageLevel, msg); 495 BaseLoggerFinder.LogEvent actual = provider.eventQueue.poll(); 496 if (!expected.equals(actual)) { 497 throw new RuntimeException("mismatch for " + desc 498 + "\n\texpected=" + expected 499 + "\n\t actual=" + actual); 500 } else { 501 verbose("Got expected results for " 502 + desc + "\n\t" + expected); 503 } 504 } 505 } 506 507 Supplier<String> fooSupplier = new Supplier<String>() { 508 @Override 509 public String get() { 510 return this.toString(); 511 } 512 }; 513 514 for (Level loggerLevel : Level.values()) { 515 sink.level = loggerLevel; 516 for (Level messageLevel : Level.values()) { 517 String desc = "logger.log(messageLevel, fooSupplier): loggerLevel=" 518 + loggerLevel+", messageLevel="+messageLevel; 519 BaseLoggerFinder.LogEvent expected = 520 BaseLoggerFinder.LogEvent.of( 521 sequencer.get(), 522 messageLevel.compareTo(loggerLevel) >= 0, 523 name, messageLevel, (ResourceBundle)null, 524 fooSupplier.get(), null, 525 (Throwable)null, (Object[])null); 526 logger.log(messageLevel, fooSupplier); 527 if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 528 if (provider.eventQueue.poll() != null) { 529 throw new RuntimeException("unexpected event in queue for " + desc); 530 } 531 } else { 532 BaseLoggerFinder.LogEvent actual = provider.eventQueue.poll(); 533 if (!expected.equals(actual)) { 534 throw new RuntimeException("mismatch for " + desc 535 + "\n\texpected=" + expected 536 + "\n\t actual=" + actual); 537 } else { 538 verbose("Got expected results for " 539 + desc + "\n\t" + expected); 540 } 541 } 542 } 543 } 544 545 String format = "two params [{1} {2}]"; 546 Object arg1 = foo; 547 Object arg2 = msg; 548 for (Level loggerLevel : Level.values()) { 549 sink.level = loggerLevel; 550 for (Level messageLevel : Level.values()) { 551 String desc = "logger.log(messageLevel, format, params...): loggerLevel=" 552 + loggerLevel+", messageLevel="+messageLevel; 553 BaseLoggerFinder.LogEvent expected = 554 BaseLoggerFinder.LogEvent.of( 555 sequencer.get(), 556 messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF, 557 name, messageLevel, loggerBundle, 558 format, null, (Throwable)null, new Object[] {arg1, arg2}); 559 logger.log(messageLevel, format, arg1, arg2); 560 BaseLoggerFinder.LogEvent actual = provider.eventQueue.poll(); 561 if (!expected.equals(actual)) { 562 throw new RuntimeException("mismatch for " + desc 563 + "\n\texpected=" + expected 564 + "\n\t actual=" + actual); 565 } else { 566 verbose("Got expected results for " 567 + desc + "\n\t" + expected); 568 } 569 } 570 } 571 572 Throwable thrown = new Exception("OK: log me!"); 573 for (Level loggerLevel : Level.values()) { 574 sink.level = loggerLevel; 575 for (Level messageLevel : Level.values()) { 576 String desc = "logger.log(messageLevel, \"blah\", thrown): loggerLevel=" 577 + loggerLevel+", messageLevel="+messageLevel; 578 BaseLoggerFinder.LogEvent expected = 579 BaseLoggerFinder.LogEvent.of( 580 sequencer.get(), 581 messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF, 582 name, messageLevel, loggerBundle, 583 msg, null, thrown, (Object[]) null); 584 logger.log(messageLevel, msg, thrown); 585 BaseLoggerFinder.LogEvent actual = provider.eventQueue.poll(); 586 if (!expected.equals(actual)) { 587 throw new RuntimeException("mismatch for " + desc 588 + "\n\texpected=" + expected 589 + "\n\t actual=" + actual); 590 } else { 591 verbose("Got expected results for " 592 + desc + "\n\t" + expected); 593 } 594 } 595 } 596 597 598 for (Level loggerLevel : Level.values()) { 599 sink.level = loggerLevel; 600 for (Level messageLevel : Level.values()) { 601 String desc = "logger.log(messageLevel, thrown, fooSupplier): loggerLevel=" 602 + loggerLevel+", messageLevel="+messageLevel; 603 BaseLoggerFinder.LogEvent expected = 604 BaseLoggerFinder.LogEvent.of( 605 sequencer.get(), 606 messageLevel.compareTo(loggerLevel) >= 0, 607 name, messageLevel, (ResourceBundle)null, 608 fooSupplier.get(), null, 609 (Throwable)thrown, (Object[])null); 610 logger.log(messageLevel, fooSupplier, thrown); 611 if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 612 if (provider.eventQueue.poll() != null) { 613 throw new RuntimeException("unexpected event in queue for " + desc); 614 } 615 } else { 616 BaseLoggerFinder.LogEvent actual = provider.eventQueue.poll(); 617 if (!expected.equals(actual)) { 618 throw new RuntimeException("mismatch for " + desc 619 + "\n\texpected=" + expected 620 + "\n\t actual=" + actual); 621 } else { 622 verbose("Got expected results for " 623 + desc + "\n\t" + expected); 624 } 625 } 626 } 627 } 628 629 ResourceBundle bundle = ResourceBundle.getBundle(MyBundle.class.getName()); 630 for (Level loggerLevel : Level.values()) { 631 sink.level = loggerLevel; 632 for (Level messageLevel : Level.values()) { 633 String desc = "logger.log(messageLevel, bundle, format, params...): loggerLevel=" 634 + loggerLevel+", messageLevel="+messageLevel; 635 BaseLoggerFinder.LogEvent expected = 636 BaseLoggerFinder.LogEvent.of( 637 sequencer.get(), 638 messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF, 639 name, messageLevel, bundle, 640 format, null, (Throwable)null, new Object[] {foo, msg}); 641 logger.log(messageLevel, bundle, format, foo, msg); 642 BaseLoggerFinder.LogEvent actual = provider.eventQueue.poll(); 643 if (!expected.equals(actual)) { 644 throw new RuntimeException("mismatch for " + desc 645 + "\n\texpected=" + expected 646 + "\n\t actual=" + actual); 647 } else { 648 verbose("Got expected results for " 649 + desc + "\n\t" + expected); 650 } 651 } 652 } 653 654 for (Level loggerLevel : Level.values()) { 655 sink.level = loggerLevel; 656 for (Level messageLevel : Level.values()) { 657 String desc = "logger.log(messageLevel, bundle, \"blah\", thrown): loggerLevel=" 658 + loggerLevel+", messageLevel="+messageLevel; 659 BaseLoggerFinder.LogEvent expected = 660 BaseLoggerFinder.LogEvent.of( 661 sequencer.get(), 662 messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF, 663 name, messageLevel, bundle, 664 msg, null, thrown, (Object[]) null); 665 logger.log(messageLevel, bundle, msg, thrown); 666 BaseLoggerFinder.LogEvent actual = provider.eventQueue.poll(); 667 if (!expected.equals(actual)) { 668 throw new RuntimeException("mismatch for " + desc 669 + "\n\texpected=" + expected 670 + "\n\t actual=" + actual); 671 } else { 672 verbose("Got expected results for " 673 + desc + "\n\t" + expected); 674 } 675 } 676 } 677 } 678 679 final static class PermissionsBuilder { 680 final Permissions perms; 681 public PermissionsBuilder() { 682 this(new Permissions()); 683 } 684 public PermissionsBuilder(Permissions perms) { 685 this.perms = perms; 686 } 687 public PermissionsBuilder add(Permission p) { 688 perms.add(p); 689 return this; 690 } 691 public PermissionsBuilder addAll(PermissionCollection col) { 692 if (col != null) { 693 for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) { 694 perms.add(e.nextElement()); 695 } 696 } 697 return this; 698 } 699 public Permissions toPermissions() { 700 final PermissionsBuilder builder = new PermissionsBuilder(); 701 builder.addAll(perms); 702 return builder.perms; 703 } 704 } 705 706 public static class SimplePolicy extends Policy { 707 708 static final RuntimePermission LOGGERFINDER_PERMISSION = 709 new RuntimePermission("loggerFinder"); 710 final Permissions permissions; 711 final Permissions controlPermissions; 712 final Permissions allPermissions; 713 final ThreadLocal<AtomicBoolean> allowControl; 714 final ThreadLocal<AtomicBoolean> allowAll; 715 public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl, ThreadLocal<AtomicBoolean> allowAll) { 716 this.allowControl = allowControl; 717 this.allowAll = allowAll; 718 permissions = new Permissions(); 719 720 // these are used for configuring the test itself... 721 controlPermissions = new Permissions(); 722 controlPermissions.add(LOGGERFINDER_PERMISSION); 723 724 // these are used for simulating a doPrivileged call from 725 // a class in the BCL 726 allPermissions = new Permissions(); 727 allPermissions.add(new AllPermission()); 728 729 } 730 731 Permissions permissions() { 732 if (allowAll.get().get()) return allPermissions; 733 if (allowControl.get().get()) return controlPermissions; 734 return permissions; 735 736 } 737 738 @Override 739 public boolean implies(ProtectionDomain domain, Permission permission) { 740 return permissions().implies(permission); 741 } 742 743 @Override 744 public PermissionCollection getPermissions(CodeSource codesource) { 745 return new PermissionsBuilder().addAll(permissions()).toPermissions(); 746 } 747 748 @Override 749 public PermissionCollection getPermissions(ProtectionDomain domain) { 750 return new PermissionsBuilder().addAll(permissions()).toPermissions(); 751 } 752 } 753 }