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.io.ByteArrayOutputStream; 24 import java.io.IOException; 25 import java.io.PrintStream; 26 import java.io.UncheckedIOException; 27 import java.security.AccessControlException; 28 import java.security.CodeSource; 29 import java.security.Permission; 30 import java.security.PermissionCollection; 31 import java.security.Permissions; 32 import java.security.Policy; 33 import java.security.ProtectionDomain; 34 import java.util.Collections; 35 import java.util.Enumeration; 36 import java.util.HashMap; 37 import java.util.Map; 38 import java.util.ResourceBundle; 39 import java.util.stream.Stream; 40 import java.util.concurrent.ConcurrentHashMap; 41 import java.util.concurrent.atomic.AtomicBoolean; 42 import java.util.concurrent.atomic.AtomicLong; 43 import java.util.function.Supplier; 44 import java.lang.System.LoggerFinder; 45 import java.lang.System.Logger; 46 import java.lang.System.Logger.Level; 47 import java.lang.reflect.InvocationTargetException; 48 import java.lang.reflect.Method; 49 import java.security.AccessController; 50 import java.security.PrivilegedAction; 51 import java.util.Locale; 52 import java.util.Objects; 53 import java.util.concurrent.atomic.AtomicReference; 54 import java.util.function.Function; 55 import jdk.internal.logger.DefaultLoggerFinder; 56 import jdk.internal.logger.SimpleConsoleLogger; 57 import sun.util.logging.PlatformLogger; 58 59 /** 60 * @test 61 * @bug 8140364 8145686 62 * @summary JDK implementation specific unit test for the base DefaultLoggerFinder. 63 * Tests the behavior of DefaultLoggerFinder and SimpleConsoleLogger 64 * implementation. 65 * @modules java.base/sun.util.logging 66 * java.base/jdk.internal.logger 67 * @build AccessSystemLogger BaseDefaultLoggerFinderTest CustomSystemClassLoader 68 * @run driver AccessSystemLogger 69 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseDefaultLoggerFinderTest NOSECURITY 70 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseDefaultLoggerFinderTest NOPERMISSIONS 71 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseDefaultLoggerFinderTest WITHPERMISSIONS 72 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseDefaultLoggerFinderTest WITHCUSTOMWRAPPERS 73 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseDefaultLoggerFinderTest WITHREFLECTION 74 * @author danielfuchs 75 */ 76 public class BaseDefaultLoggerFinderTest { 77 78 static final RuntimePermission LOGGERFINDER_PERMISSION = 79 new RuntimePermission("loggerFinder"); 80 final static boolean VERBOSE = false; 81 static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() { 82 @Override 83 protected AtomicBoolean initialValue() { 84 return new AtomicBoolean(false); 85 } 86 }; 87 static final ThreadLocal<AtomicBoolean> allowAccess = new ThreadLocal<AtomicBoolean>() { 88 @Override 89 protected AtomicBoolean initialValue() { 90 return new AtomicBoolean(false); 91 } 92 }; 93 94 final static AccessSystemLogger accessSystemLogger = new AccessSystemLogger(); 95 static final Class<?>[] providerClass; 96 static { 97 try { 98 providerClass = new Class<?>[] { 99 ClassLoader.getSystemClassLoader().loadClass("BaseDefaultLoggerFinderTest$BaseLoggerFinder"), 100 }; 101 } catch (ClassNotFoundException ex) { 102 throw new ExceptionInInitializerError(ex); 103 } 104 } 105 106 /** 107 * What our test provider needs to implement. 108 */ 109 public static interface TestLoggerFinder { 110 public final static AtomicBoolean fails = new AtomicBoolean(); 111 public final static AtomicReference<String> conf = new AtomicReference<>(""); 112 public final static AtomicLong sequencer = new AtomicLong(); 113 114 115 public Logger getLogger(String name, Module caller); 116 public Logger getLocalizedLogger(String name, ResourceBundle bundle, Module caller); 117 void setLevel(Logger logger, Level level, Module caller); 118 void setLevel(Logger logger, PlatformLogger.Level level, Module caller); 119 PlatformLogger.Bridge asPlatformLoggerBridge(Logger logger); 120 } 121 122 public static class BaseLoggerFinder extends DefaultLoggerFinder implements TestLoggerFinder { 123 124 static final RuntimePermission LOGGERFINDER_PERMISSION = 125 new RuntimePermission("loggerFinder"); 126 public BaseLoggerFinder() { 127 if (fails.get()) { 128 throw new RuntimeException("Simulate exception while loading provider"); 129 } 130 } 131 132 @Override 133 public void setLevel(Logger logger, Level level, Module caller) { 134 PrivilegedAction<Void> pa = () -> { 135 setLevel(logger, PlatformLogger.toPlatformLevel(level), caller); 136 return null; 137 }; 138 AccessController.doPrivileged(pa); 139 } 140 141 @Override 142 public void setLevel(Logger logger, PlatformLogger.Level level, Module caller) { 143 PrivilegedAction<Logger> pa = () -> demandLoggerFor(logger.getName(), caller); 144 Logger impl = AccessController.doPrivileged(pa); 145 SimpleConsoleLogger.class.cast(impl) 146 .getLoggerConfiguration() 147 .setPlatformLevel(level); 148 } 149 150 @Override 151 public PlatformLogger.Bridge asPlatformLoggerBridge(Logger logger) { 152 PrivilegedAction<PlatformLogger.Bridge> pa = () -> 153 PlatformLogger.Bridge.convert(logger); 154 return AccessController.doPrivileged(pa); 155 } 156 157 } 158 159 public static class MyBundle extends ResourceBundle { 160 161 final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>(); 162 163 @Override 164 protected Object handleGetObject(String key) { 165 if (key.contains(" (translated)")) { 166 throw new RuntimeException("Unexpected key: " + key); 167 } 168 return map.computeIfAbsent(key, k -> k.toUpperCase(Locale.ROOT) + " (translated)"); 169 } 170 171 @Override 172 public Enumeration<String> getKeys() { 173 return Collections.enumeration(map.keySet()); 174 } 175 176 } 177 public static class MyLoggerBundle extends MyBundle { 178 179 } 180 181 static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS, 182 WITHCUSTOMWRAPPERS, WITHREFLECTION}; 183 184 static void setSecurityManager() { 185 if (System.getSecurityManager() == null) { 186 Policy.setPolicy(new SimplePolicy(allowControl, allowAccess)); 187 System.setSecurityManager(new SecurityManager()); 188 } 189 } 190 191 static TestLoggerFinder getLoggerFinder(Class<?> expectedClass) { 192 LoggerFinder provider = null; 193 try { 194 TestLoggerFinder.sequencer.incrementAndGet(); 195 provider = LoggerFinder.getLoggerFinder(); 196 } catch(AccessControlException a) { 197 throw a; 198 } 199 ErrorStream.errorStream.store(); 200 System.out.println("*** Actual LoggerFinder class is: " + provider.getClass().getName()); 201 expectedClass.cast(provider); 202 return TestLoggerFinder.class.cast(provider); 203 } 204 205 206 static class ErrorStream extends PrintStream { 207 208 static AtomicBoolean forward = new AtomicBoolean(); 209 ByteArrayOutputStream out; 210 String saved = ""; 211 public ErrorStream(ByteArrayOutputStream out) { 212 super(out); 213 this.out = out; 214 } 215 216 @Override 217 public void write(int b) { 218 super.write(b); 219 if (forward.get()) err.write(b); 220 } 221 222 @Override 223 public void write(byte[] b) throws IOException { 224 super.write(b); 225 if (forward.get()) err.write(b); 226 } 227 228 @Override 229 public void write(byte[] buf, int off, int len) { 230 super.write(buf, off, len); 231 if (forward.get()) err.write(buf, off, len); 232 } 233 234 public String peek() { 235 flush(); 236 return out.toString(); 237 } 238 239 public String drain() { 240 flush(); 241 String res = out.toString(); 242 out.reset(); 243 return res; 244 } 245 246 public void store() { 247 flush(); 248 saved = out.toString(); 249 out.reset(); 250 } 251 252 public void restore() { 253 out.reset(); 254 try { 255 out.write(saved.getBytes()); 256 } catch(IOException io) { 257 throw new UncheckedIOException(io); 258 } 259 } 260 261 static final PrintStream err = System.err; 262 static final ErrorStream errorStream = new ErrorStream(new ByteArrayOutputStream()); 263 } 264 265 private static StringBuilder appendProperty(StringBuilder b, String name) { 266 String value = System.getProperty(name); 267 if (value == null) return b; 268 return b.append(name).append("=").append(value).append('\n'); 269 } 270 271 static class CustomLoggerWrapper implements Logger { 272 273 Logger impl; 274 public CustomLoggerWrapper(Logger logger) { 275 this.impl = Objects.requireNonNull(logger); 276 } 277 278 279 @Override 280 public String getName() { 281 return impl.getName(); 282 } 283 284 @Override 285 public boolean isLoggable(Level level) { 286 return impl.isLoggable(level); 287 } 288 289 @Override 290 public void log(Level level, ResourceBundle rb, String string, Throwable thrwbl) { 291 impl.log(level, rb, string, thrwbl); 292 } 293 294 @Override 295 public void log(Level level, ResourceBundle rb, String string, Object... os) { 296 impl.log(level, rb, string, os); 297 } 298 299 @Override 300 public void log(Level level, Object o) { 301 impl.log(level, o); 302 } 303 304 @Override 305 public void log(Level level, String string) { 306 impl.log(level, string); 307 } 308 309 @Override 310 public void log(Level level, Supplier<String> splr) { 311 impl.log(level, splr); 312 } 313 314 @Override 315 public void log(Level level, String string, Object... os) { 316 impl.log(level, string, os); 317 } 318 319 @Override 320 public void log(Level level, String string, Throwable thrwbl) { 321 impl.log(level, string, thrwbl); 322 } 323 324 @Override 325 public void log(Level level, Supplier<String> splr, Throwable thrwbl) { 326 Logger.super.log(level, splr, thrwbl); 327 } 328 329 @Override 330 public String toString() { 331 return super.toString() + "(impl=" + impl + ")"; 332 } 333 334 } 335 /** 336 * The ReflectionLoggerWrapper additionally makes it possible to verify 337 * that code which use reflection to call System.Logger will be skipped 338 * when looking for the calling method. 339 */ 340 static class ReflectionLoggerWrapper implements Logger { 341 342 Logger impl; 343 public ReflectionLoggerWrapper(Logger logger) { 344 this.impl = Objects.requireNonNull(logger); 345 } 346 347 private Object invoke(Method m, Object... params) { 348 try { 349 return m.invoke(impl, params); 350 } catch (IllegalAccessException | IllegalArgumentException 351 | InvocationTargetException ex) { 352 throw new RuntimeException(ex); 353 } 354 } 355 356 @Override 357 public String getName() { 358 return impl.getName(); 359 } 360 361 @Override 362 public boolean isLoggable(Level level) { 363 return impl.isLoggable(level); 364 } 365 366 @Override 367 public void log(Level level, ResourceBundle rb, String string, Throwable thrwbl) { 368 try { 369 invoke(System.Logger.class.getMethod( 370 "log", Level.class, ResourceBundle.class, String.class, Throwable.class), 371 level, rb, string, thrwbl); 372 } catch (NoSuchMethodException ex) { 373 throw new RuntimeException(ex); 374 } 375 } 376 377 @Override 378 public void log(Level level, ResourceBundle rb, String string, Object... os) { 379 try { 380 invoke(System.Logger.class.getMethod( 381 "log", Level.class, ResourceBundle.class, String.class, Object[].class), 382 level, rb, string, os); 383 } catch (NoSuchMethodException ex) { 384 throw new RuntimeException(ex); 385 } 386 } 387 388 @Override 389 public void log(Level level, String string) { 390 try { 391 invoke(System.Logger.class.getMethod( 392 "log", Level.class, String.class), 393 level, string); 394 } catch (NoSuchMethodException ex) { 395 throw new RuntimeException(ex); 396 } 397 } 398 399 @Override 400 public void log(Level level, String string, Object... os) { 401 try { 402 invoke(System.Logger.class.getMethod( 403 "log", Level.class, String.class, Object[].class), 404 level, string, os); 405 } catch (NoSuchMethodException ex) { 406 throw new RuntimeException(ex); 407 } 408 } 409 410 @Override 411 public void log(Level level, String string, Throwable thrwbl) { 412 try { 413 invoke(System.Logger.class.getMethod( 414 "log", Level.class, String.class, Throwable.class), 415 level, string, thrwbl); 416 } catch (NoSuchMethodException ex) { 417 throw new RuntimeException(ex); 418 } 419 } 420 421 422 @Override 423 public String toString() { 424 return super.toString() + "(impl=" + impl + ")"; 425 } 426 427 } 428 429 430 public static void main(String[] args) { 431 if (args.length == 0) { 432 args = new String[] { 433 //"NOSECURITY", 434 "NOPERMISSIONS", 435 "WITHPERMISSIONS", 436 "WITHCUSTOMWRAPPERS", 437 "WITHREFLECTION" 438 }; 439 } 440 Locale.setDefault(Locale.ENGLISH); 441 System.setErr(ErrorStream.errorStream); 442 //System.setProperty("jdk.logger.finder.error", "ERROR"); 443 //System.setProperty("jdk.logger.finder.singleton", "true"); 444 //System.setProperty("test.fails", "true"); 445 TestLoggerFinder.fails.set(Boolean.getBoolean("test.fails")); 446 StringBuilder c = new StringBuilder(); 447 appendProperty(c, "jdk.logger.packages"); 448 appendProperty(c, "jdk.logger.finder.error"); 449 appendProperty(c, "jdk.logger.finder.singleton"); 450 appendProperty(c, "test.fails"); 451 TestLoggerFinder.conf.set(c.toString()); 452 try { 453 test(args); 454 } finally { 455 try { 456 System.setErr(ErrorStream.err); 457 } catch (Error | RuntimeException x) { 458 x.printStackTrace(ErrorStream.err); 459 } 460 } 461 } 462 463 464 public static void test(String[] args) { 465 466 final Class<?> expectedClass = jdk.internal.logger.DefaultLoggerFinder.class; 467 468 System.out.println("Declared provider class: " + providerClass[0] 469 + "[" + providerClass[0].getClassLoader() + "]"); 470 471 Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> { 472 TestLoggerFinder provider; 473 ErrorStream.errorStream.restore(); 474 switch (testCase) { 475 case NOSECURITY: 476 System.out.println("\n*** Without Security Manager\n"); 477 System.out.println(TestLoggerFinder.conf.get()); 478 provider = getLoggerFinder(expectedClass); 479 if (!provider.getClass().getName().equals("BaseDefaultLoggerFinderTest$BaseLoggerFinder")) { 480 throw new RuntimeException("Unexpected provider: " + provider.getClass().getName()); 481 } 482 test(provider, true); 483 System.out.println("Tetscase count: " + TestLoggerFinder.sequencer.get()); 484 break; 485 case NOPERMISSIONS: 486 System.out.println("\n*** With Security Manager, without permissions\n"); 487 System.out.println(TestLoggerFinder.conf.get()); 488 setSecurityManager(); 489 try { 490 provider = getLoggerFinder(expectedClass); 491 throw new RuntimeException("Expected exception not raised"); 492 } catch (AccessControlException x) { 493 if (!LOGGERFINDER_PERMISSION.equals(x.getPermission())) { 494 throw new RuntimeException("Unexpected permission check", x); 495 } 496 final boolean control = allowControl.get().get(); 497 try { 498 allowControl.get().set(true); 499 provider = getLoggerFinder(expectedClass); 500 if (!provider.getClass().getName().equals("BaseDefaultLoggerFinderTest$BaseLoggerFinder")) { 501 throw new RuntimeException("Unexpected provider: " + provider.getClass().getName()); 502 } 503 } finally { 504 allowControl.get().set(control); 505 } 506 } 507 test(provider, false); 508 System.out.println("Tetscase count: " + TestLoggerFinder.sequencer.get()); 509 break; 510 case WITHPERMISSIONS: 511 System.out.println("\n*** With Security Manager, with control permission\n"); 512 System.out.println(TestLoggerFinder.conf.get()); 513 setSecurityManager(); 514 final boolean control = allowControl.get().get(); 515 try { 516 allowControl.get().set(true); 517 provider = getLoggerFinder(expectedClass); 518 if (!provider.getClass().getName().equals("BaseDefaultLoggerFinderTest$BaseLoggerFinder")) { 519 throw new RuntimeException("Unexpected provider: " + provider.getClass().getName()); 520 } 521 test(provider, true); 522 } finally { 523 allowControl.get().set(control); 524 } 525 break; 526 case WITHCUSTOMWRAPPERS: 527 System.out.println("\n*** With Security Manager, with control permission and custom Wrapper\n"); 528 System.out.println(TestLoggerFinder.conf.get()); 529 setSecurityManager(); 530 final boolean previous = allowControl.get().get(); 531 try { 532 allowControl.get().set(true); 533 provider = getLoggerFinder(expectedClass); 534 if (!provider.getClass().getName().equals("BaseDefaultLoggerFinderTest$BaseLoggerFinder")) { 535 throw new RuntimeException("Unexpected provider: " + provider.getClass().getName()); 536 } 537 test(provider, CustomLoggerWrapper::new, true); 538 } finally { 539 allowControl.get().set(previous); 540 } 541 break; 542 case WITHREFLECTION: 543 System.out.println("\n*** With Security Manager," 544 + " with control permission," 545 + " using reflection while logging\n"); 546 System.out.println(TestLoggerFinder.conf.get()); 547 setSecurityManager(); 548 final boolean before = allowControl.get().get(); 549 try { 550 allowControl.get().set(true); 551 provider = getLoggerFinder(expectedClass); 552 if (!provider.getClass().getName().equals("BaseDefaultLoggerFinderTest$BaseLoggerFinder")) { 553 throw new RuntimeException("Unexpected provider: " + provider.getClass().getName()); 554 } 555 test(provider, ReflectionLoggerWrapper::new, true); 556 } finally { 557 allowControl.get().set(before); 558 } 559 break; 560 default: 561 throw new RuntimeException("Unknown test case: " + testCase); 562 } 563 }); 564 System.out.println("\nPASSED: Tested " + TestLoggerFinder.sequencer.get() + " cases."); 565 } 566 567 public static void test(TestLoggerFinder provider, boolean hasRequiredPermissions) { 568 test(provider, Function.identity(), hasRequiredPermissions); 569 } 570 571 public static void test(TestLoggerFinder provider, Function<Logger, Logger> wrapper, boolean hasRequiredPermissions) { 572 573 ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName()); 574 final Map<Logger, String> loggerDescMap = new HashMap<>(); 575 576 System.Logger sysLogger = wrapper.apply(accessSystemLogger.getLogger("foo")); 577 loggerDescMap.put(sysLogger, "accessSystemLogger.getLogger(\"foo\")"); 578 System.Logger localizedSysLogger = wrapper.apply(accessSystemLogger.getLogger("fox", loggerBundle)); 579 loggerDescMap.put(localizedSysLogger, "accessSystemLogger.getLogger(\"fox\", loggerBundle)"); 580 System.Logger appLogger = wrapper.apply(System.getLogger("bar")); 581 loggerDescMap.put(appLogger,"System.getLogger(\"bar\")"); 582 System.Logger localizedAppLogger = wrapper.apply(System.getLogger("baz", loggerBundle)); 583 loggerDescMap.put(localizedAppLogger,"System.getLogger(\"baz\", loggerBundle)"); 584 585 testLogger(provider, loggerDescMap, "foo", null, sysLogger, accessSystemLogger.getClass()); 586 testLogger(provider, loggerDescMap, "foo", loggerBundle, localizedSysLogger, accessSystemLogger.getClass()); 587 testLogger(provider, loggerDescMap, "foo", null, appLogger, BaseDefaultLoggerFinderTest.class); 588 testLogger(provider, loggerDescMap, "foo", loggerBundle, localizedAppLogger, BaseDefaultLoggerFinderTest.class); 589 } 590 591 public static class Foo { 592 593 } 594 595 static void verbose(String msg) { 596 if (VERBOSE) { 597 System.out.println(msg); 598 } 599 } 600 601 // Calls the 8 methods defined on Logger and verify the 602 // parameters received by the underlying TestProvider.LoggerImpl 603 // logger. 604 private static void testLogger(TestLoggerFinder provider, 605 Map<Logger, String> loggerDescMap, 606 String name, 607 ResourceBundle loggerBundle, 608 Logger logger, 609 Class<?> callerClass) { 610 611 System.out.println("Testing " + loggerDescMap.get(logger) + " [" + logger +"]"); 612 AtomicLong sequencer = TestLoggerFinder.sequencer; 613 614 Module caller = callerClass.getModule(); 615 Foo foo = new Foo(); 616 String fooMsg = foo.toString(); 617 for (Level loggerLevel : Level.values()) { 618 provider.setLevel(logger, loggerLevel, caller); 619 for (Level messageLevel : Level.values()) { 620 ErrorStream.errorStream.drain(); 621 String desc = "logger.log(messageLevel, foo): loggerLevel=" 622 + loggerLevel+", messageLevel="+messageLevel; 623 sequencer.incrementAndGet(); 624 logger.log(messageLevel, foo); 625 if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 626 if (!ErrorStream.errorStream.peek().isEmpty()) { 627 throw new RuntimeException("unexpected event in queue for " 628 + desc +": " + "\n\t" + ErrorStream.errorStream.drain()); 629 } 630 } else { 631 String logged = ErrorStream.errorStream.drain(); 632 if (!logged.contains("BaseDefaultLoggerFinderTest testLogger") 633 || !logged.contains(messageLevel.getName() + ": " + fooMsg)) { 634 throw new RuntimeException("mismatch for " + desc 635 + "\n\texpected:" + "\n<<<<\n" 636 + "[date] BaseDefaultLoggerFinderTest testLogger\n" 637 + messageLevel.getName() + " " + fooMsg 638 + "\n>>>>" 639 + "\n\t actual:" 640 + "\n<<<<\n" + logged + ">>>>\n"); 641 } else { 642 verbose("Got expected results for " 643 + desc + "\n<<<<\n" + logged + ">>>>\n"); 644 } 645 } 646 } 647 } 648 649 String msg = "blah"; 650 for (Level loggerLevel : Level.values()) { 651 provider.setLevel(logger, loggerLevel, caller); 652 for (Level messageLevel : Level.values()) { 653 String desc = "logger.log(messageLevel, \"blah\"): loggerLevel=" 654 + loggerLevel+", messageLevel="+messageLevel; 655 sequencer.incrementAndGet(); 656 logger.log(messageLevel, msg); 657 if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 658 if (!ErrorStream.errorStream.peek().isEmpty()) { 659 throw new RuntimeException("unexpected event in queue for " 660 + desc +": " + "\n\t" + ErrorStream.errorStream.drain()); 661 } 662 } else { 663 String logged = ErrorStream.errorStream.drain(); 664 String msgText = loggerBundle == null ? msg : loggerBundle.getString(msg); 665 if (!logged.contains("BaseDefaultLoggerFinderTest testLogger") 666 || !logged.contains(messageLevel.getName() + ": " + msgText)) { 667 throw new RuntimeException("mismatch for " + desc 668 + "\n\texpected:" + "\n<<<<\n" 669 + "[date] BaseDefaultLoggerFinderTest testLogger\n" 670 + messageLevel.getName() + " " + msgText 671 + "\n>>>>" 672 + "\n\t actual:" 673 + "\n<<<<\n" + logged + ">>>>\n"); 674 } else { 675 verbose("Got expected results for " 676 + desc + "\n<<<<\n" + logged + ">>>>\n"); 677 } 678 } 679 } 680 } 681 682 Supplier<String> fooSupplier = new Supplier<String>() { 683 @Override 684 public String get() { 685 return this.toString(); 686 } 687 }; 688 689 for (Level loggerLevel : Level.values()) { 690 provider.setLevel(logger, loggerLevel, caller); 691 for (Level messageLevel : Level.values()) { 692 String desc = "logger.log(messageLevel, fooSupplier): loggerLevel=" 693 + loggerLevel+", messageLevel="+messageLevel; 694 sequencer.incrementAndGet(); 695 logger.log(messageLevel, fooSupplier); 696 if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 697 if (!ErrorStream.errorStream.peek().isEmpty()) { 698 throw new RuntimeException("unexpected event in queue for " 699 + desc +": " + "\n\t" + ErrorStream.errorStream.drain()); 700 } 701 } else { 702 String logged = ErrorStream.errorStream.drain(); 703 if (!logged.contains("BaseDefaultLoggerFinderTest testLogger") 704 || !logged.contains(messageLevel.getName() + ": " + fooSupplier.get())) { 705 throw new RuntimeException("mismatch for " + desc 706 + "\n\texpected:" + "\n<<<<\n" 707 + "[date] BaseDefaultLoggerFinderTest testLogger\n" 708 + messageLevel.getName() + " " + fooSupplier.get() 709 + "\n>>>>" 710 + "\n\t actual:" 711 + "\n<<<<\n" + logged + ">>>>\n"); 712 } else { 713 verbose("Got expected results for " 714 + desc + "\n<<<<\n" + logged + ">>>>\n"); 715 } 716 } 717 } 718 } 719 720 721 String format = "two params [{1} {2}]"; 722 Object arg1 = foo; 723 Object arg2 = msg; 724 for (Level loggerLevel : Level.values()) { 725 provider.setLevel(logger, loggerLevel, caller); 726 for (Level messageLevel : Level.values()) { 727 String desc = "logger.log(messageLevel, format, params...): loggerLevel=" 728 + loggerLevel+", messageLevel="+messageLevel; 729 sequencer.incrementAndGet(); 730 logger.log(messageLevel, format, foo, msg); 731 if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 732 if (!ErrorStream.errorStream.peek().isEmpty()) { 733 throw new RuntimeException("unexpected event in queue for " 734 + desc +": " + "\n\t" + ErrorStream.errorStream.drain()); 735 } 736 } else { 737 String logged = ErrorStream.errorStream.drain(); 738 String msgFormat = loggerBundle == null ? format : loggerBundle.getString(format); 739 String text = java.text.MessageFormat.format(msgFormat, foo, msg); 740 if (!logged.contains("BaseDefaultLoggerFinderTest testLogger") 741 || !logged.contains(messageLevel.getName() + ": " + text)) { 742 throw new RuntimeException("mismatch for " + desc 743 + "\n\texpected:" + "\n<<<<\n" 744 + "[date] BaseDefaultLoggerFinderTest testLogger\n" 745 + messageLevel.getName() + " " + text 746 + "\n>>>>" 747 + "\n\t actual:" 748 + "\n<<<<\n" + logged + ">>>>\n"); 749 } else { 750 verbose("Got expected results for " 751 + desc + "\n<<<<\n" + logged + ">>>>\n"); 752 } 753 } 754 } 755 } 756 757 Throwable thrown = new Exception("OK: log me!"); 758 for (Level loggerLevel : Level.values()) { 759 provider.setLevel(logger, loggerLevel, caller); 760 for (Level messageLevel : Level.values()) { 761 String desc = "logger.log(messageLevel, \"blah\", thrown): loggerLevel=" 762 + loggerLevel+", messageLevel="+messageLevel; 763 sequencer.incrementAndGet(); 764 logger.log(messageLevel, msg, thrown); 765 if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 766 if (!ErrorStream.errorStream.peek().isEmpty()) { 767 throw new RuntimeException("unexpected event in queue for " 768 + desc +": " + "\n\t" + ErrorStream.errorStream.drain()); 769 } 770 } else { 771 String logged = ErrorStream.errorStream.drain(); 772 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 773 thrown.printStackTrace(new PrintStream(baos)); 774 String text = baos.toString(); 775 String msgText = loggerBundle == null ? msg : loggerBundle.getString(msg); 776 if (!logged.contains("BaseDefaultLoggerFinderTest testLogger") 777 || !logged.contains(messageLevel.getName() + ": " + msgText) 778 || !logged.contains(text)) { 779 throw new RuntimeException("mismatch for " + desc 780 + "\n\texpected:" + "\n<<<<\n" 781 + "[date] BaseDefaultLoggerFinderTest testLogger\n" 782 + messageLevel.getName() + " " + msgText +"\n" 783 + text 784 + ">>>>" 785 + "\n\t actual:" 786 + "\n<<<<\n" + logged + ">>>>\n"); 787 } else { 788 verbose("Got expected results for " 789 + desc + "\n<<<<\n" + logged + ">>>>\n"); 790 } 791 } 792 } 793 } 794 795 796 for (Level loggerLevel : Level.values()) { 797 provider.setLevel(logger, loggerLevel, caller); 798 for (Level messageLevel : Level.values()) { 799 String desc = "logger.log(messageLevel, thrown, fooSupplier): loggerLevel=" 800 + loggerLevel+", messageLevel="+messageLevel; 801 sequencer.incrementAndGet(); 802 logger.log(messageLevel, fooSupplier, thrown); 803 if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 804 if (!ErrorStream.errorStream.peek().isEmpty()) { 805 throw new RuntimeException("unexpected event in queue for " 806 + desc +": " + "\n\t" + ErrorStream.errorStream.drain()); 807 } 808 } else { 809 String logged = ErrorStream.errorStream.drain(); 810 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 811 thrown.printStackTrace(new PrintStream(baos)); 812 String text = baos.toString(); 813 if (!logged.contains("BaseDefaultLoggerFinderTest testLogger") 814 || !logged.contains(messageLevel.getName() + ": " + fooSupplier.get()) 815 || !logged.contains(text)) { 816 throw new RuntimeException("mismatch for " + desc 817 + "\n\texpected:" + "\n<<<<\n" 818 + "[date] BaseDefaultLoggerFinderTest testLogger\n" 819 + messageLevel.getName() + " " + fooSupplier.get() +"\n" 820 + text 821 + ">>>>" 822 + "\n\t actual:" 823 + "\n<<<<\n" + logged + ">>>>\n"); 824 } else { 825 verbose("Got expected results for " 826 + desc + "\n<<<<\n" + logged + ">>>>\n"); 827 } 828 } 829 } 830 } 831 832 ResourceBundle bundle = ResourceBundle.getBundle(MyBundle.class.getName()); 833 for (Level loggerLevel : Level.values()) { 834 provider.setLevel(logger, loggerLevel, caller); 835 for (Level messageLevel : Level.values()) { 836 String desc = "logger.log(messageLevel, bundle, format, params...): loggerLevel=" 837 + loggerLevel+", messageLevel="+messageLevel; 838 sequencer.incrementAndGet(); 839 logger.log(messageLevel, bundle, format, foo, msg); 840 if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 841 if (!ErrorStream.errorStream.peek().isEmpty()) { 842 throw new RuntimeException("unexpected event in queue for " 843 + desc +": " + "\n\t" + ErrorStream.errorStream.drain()); 844 } 845 } else { 846 String logged = ErrorStream.errorStream.drain(); 847 String text = java.text.MessageFormat.format(bundle.getString(format), foo, msg); 848 if (!logged.contains("BaseDefaultLoggerFinderTest testLogger") 849 || !logged.contains(messageLevel.getName() + ": " + text)) { 850 throw new RuntimeException("mismatch for " + desc 851 + "\n\texpected:" + "\n<<<<\n" 852 + "[date] BaseDefaultLoggerFinderTest testLogger\n" 853 + messageLevel.getName() + " " + text 854 + "\n>>>>" 855 + "\n\t actual:" 856 + "\n<<<<\n" + logged + ">>>>\n"); 857 } else { 858 verbose("Got expected results for " 859 + desc + "\n<<<<\n" + logged + ">>>>\n"); 860 } 861 } 862 } 863 } 864 865 for (Level loggerLevel : Level.values()) { 866 provider.setLevel(logger, loggerLevel, caller); 867 for (Level messageLevel : Level.values()) { 868 String desc = "logger.log(messageLevel, bundle, \"blah\", thrown): loggerLevel=" 869 + loggerLevel+", messageLevel="+messageLevel; 870 sequencer.incrementAndGet(); 871 logger.log(messageLevel, bundle, msg, thrown); 872 if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 873 if (!ErrorStream.errorStream.peek().isEmpty()) { 874 throw new RuntimeException("unexpected event in queue for " 875 + desc +": " + "\n\t" + ErrorStream.errorStream.drain()); 876 } 877 } else { 878 String logged = ErrorStream.errorStream.drain(); 879 String textMsg = bundle.getString(msg); 880 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 881 thrown.printStackTrace(new PrintStream(baos)); 882 String text = baos.toString(); 883 if (!logged.contains("BaseDefaultLoggerFinderTest testLogger") 884 || !logged.contains(messageLevel.getName() + ": " + textMsg) 885 || !logged.contains(text)) { 886 throw new RuntimeException("mismatch for " + desc 887 + "\n\texpected:" + "\n<<<<\n" 888 + "[date] BaseDefaultLoggerFinderTest testLogger\n" 889 + messageLevel.getName() + " " + textMsg +"\n" 890 + text 891 + ">>>>" 892 + "\n\t actual:" 893 + "\n<<<<\n" + logged + ">>>>\n"); 894 } else { 895 verbose("Got expected results for " 896 + desc + "\n<<<<\n" + logged + ">>>>\n"); 897 } 898 } 899 } 900 } 901 902 } 903 904 final static class PermissionsBuilder { 905 final Permissions perms; 906 public PermissionsBuilder() { 907 this(new Permissions()); 908 } 909 public PermissionsBuilder(Permissions perms) { 910 this.perms = perms; 911 } 912 public PermissionsBuilder add(Permission p) { 913 perms.add(p); 914 return this; 915 } 916 public PermissionsBuilder addAll(PermissionCollection col) { 917 if (col != null) { 918 for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) { 919 perms.add(e.nextElement()); 920 } 921 } 922 return this; 923 } 924 public Permissions toPermissions() { 925 final PermissionsBuilder builder = new PermissionsBuilder(); 926 builder.addAll(perms); 927 return builder.perms; 928 } 929 } 930 931 public static class SimplePolicy extends Policy { 932 final static RuntimePermission CONTROL = LOGGERFINDER_PERMISSION; 933 final static RuntimePermission ACCESS = new RuntimePermission("accessClassInPackage.jdk.internal.logger"); 934 935 final Permissions permissions; 936 final ThreadLocal<AtomicBoolean> allowControl; 937 final ThreadLocal<AtomicBoolean> allowAccess; 938 public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl, ThreadLocal<AtomicBoolean> allowAccess) { 939 this.allowControl = allowControl; 940 this.allowAccess = allowAccess; 941 permissions = new Permissions(); 942 permissions.add(new RuntimePermission("setIO")); 943 } 944 945 Permissions getPermissions() { 946 if (allowControl.get().get() || allowAccess.get().get()) { 947 PermissionsBuilder builder = new PermissionsBuilder() 948 .addAll(permissions); 949 if (allowControl.get().get()) { 950 builder.add(CONTROL); 951 } 952 if (allowAccess.get().get()) { 953 builder.add(ACCESS); 954 } 955 return builder.toPermissions(); 956 } 957 return permissions; 958 } 959 960 @Override 961 public boolean implies(ProtectionDomain domain, Permission permission) { 962 return getPermissions().implies(permission); 963 } 964 965 @Override 966 public PermissionCollection getPermissions(CodeSource codesource) { 967 return new PermissionsBuilder().addAll(getPermissions()).toPermissions(); 968 } 969 970 @Override 971 public PermissionCollection getPermissions(ProtectionDomain domain) { 972 return new PermissionsBuilder().addAll(getPermissions()).toPermissions(); 973 } 974 } 975 }