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