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