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