1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 import java.security.AccessControlException; 24 import java.security.AccessController; 25 import java.security.CodeSource; 26 import java.security.Permission; 27 import java.security.PermissionCollection; 28 import java.security.Permissions; 29 import java.security.Policy; 30 import java.security.PrivilegedAction; 31 import java.security.ProtectionDomain; 32 import java.util.Arrays; 33 import java.util.Collections; 34 import java.util.Enumeration; 35 import java.util.HashMap; 36 import java.util.Map; 37 import java.util.Objects; 38 import java.util.Queue; 39 import java.util.ResourceBundle; 40 import java.util.concurrent.ArrayBlockingQueue; 41 import java.util.concurrent.ConcurrentHashMap; 42 import java.util.concurrent.atomic.AtomicBoolean; 43 import java.util.concurrent.atomic.AtomicLong; 44 import java.util.function.Supplier; 45 import sun.util.logging.PlatformLogger; 46 import java.lang.System.LoggerFinder; 47 import java.lang.System.Logger; 48 import java.lang.System.Logger.Level; 49 import java.util.stream.Stream; 50 51 /** 52 * @test 53 * @bug 8140364 54 * @summary JDK implementation specific unit test for JDK internal artifacts. 55 * Tests a naive implementation of System.Logger, and in particular 56 * the default mapping provided by PlatformLogger.Bridge. 57 * @modules java.base/sun.util.logging java.base/jdk.internal.logger 58 * @build CustomSystemClassLoader BaseLoggerBridgeTest 59 * @run main/othervm -Djava.system.class.loader=CustomSystemClassLoader BaseLoggerBridgeTest NOSECURITY 60 * @run main/othervm -Djava.system.class.loader=CustomSystemClassLoader BaseLoggerBridgeTest NOPERMISSIONS 61 * @run main/othervm -Djava.system.class.loader=CustomSystemClassLoader BaseLoggerBridgeTest WITHPERMISSIONS 62 * @author danielfuchs 63 */ 64 public class BaseLoggerBridgeTest { 65 66 static final RuntimePermission LOGGERFINDER_PERMISSION = 67 new RuntimePermission("loggerFinder"); 68 final static AtomicLong sequencer = new AtomicLong(); 69 final static boolean VERBOSE = false; 70 // whether the implementation of Logger try to do a best 71 // effort for logp... Our base logger finder stub doesn't 72 // support logp, and thus the logp() implementation comes from 73 // LoggerWrapper - which does a best effort. 74 static final boolean BEST_EFFORT_FOR_LOGP = true; 75 static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() { 76 @Override 77 protected AtomicBoolean initialValue() { 78 return new AtomicBoolean(false); 79 } 80 }; 81 static final ThreadLocal<AtomicBoolean> allowAccess = new ThreadLocal<AtomicBoolean>() { 82 @Override 83 protected AtomicBoolean initialValue() { 84 return new AtomicBoolean(false); 85 } 86 }; 87 static final ThreadLocal<AtomicBoolean> allowAll = new ThreadLocal<AtomicBoolean>() { 88 @Override 89 protected AtomicBoolean initialValue() { 90 return new AtomicBoolean(false); 91 } 92 }; 93 94 static final Class<?> providerClass; 95 static { 96 try { 97 providerClass = ClassLoader.getSystemClassLoader().loadClass("BaseLoggerBridgeTest$BaseLoggerFinder"); 98 } catch (ClassNotFoundException ex) { 99 throw new ExceptionInInitializerError(ex); 100 } 101 } 102 103 static final sun.util.logging.PlatformLogger.Level[] julLevels = { 104 sun.util.logging.PlatformLogger.Level.ALL, 105 sun.util.logging.PlatformLogger.Level.FINEST, 106 sun.util.logging.PlatformLogger.Level.FINER, 107 sun.util.logging.PlatformLogger.Level.FINE, 108 sun.util.logging.PlatformLogger.Level.CONFIG, 109 sun.util.logging.PlatformLogger.Level.INFO, 110 sun.util.logging.PlatformLogger.Level.WARNING, 111 sun.util.logging.PlatformLogger.Level.SEVERE, 112 sun.util.logging.PlatformLogger.Level.OFF, 113 }; 114 115 static final Level[] mappedLevels = { 116 Level.ALL, // ALL 117 Level.TRACE, // FINEST 118 Level.TRACE, // FINER 119 Level.DEBUG, // FINE 120 Level.DEBUG, // CONFIG 121 Level.INFO, // INFO 122 Level.WARNING, // WARNING 123 Level.ERROR, // SEVERE 124 Level.OFF, // OFF 125 }; 126 127 final static Map<sun.util.logging.PlatformLogger.Level, Level> julToSpiMap; 128 static { 129 Map<sun.util.logging.PlatformLogger.Level, Level> map = new HashMap<>(); 130 if (mappedLevels.length != julLevels.length) { 131 throw new ExceptionInInitializerError("Array lengths differ" 132 + "\n\tjulLevels=" + Arrays.deepToString(julLevels) 133 + "\n\tmappedLevels=" + Arrays.deepToString(mappedLevels)); 134 } 135 for (int i=0; i<julLevels.length; i++) { 136 map.put(julLevels[i], mappedLevels[i]); 137 } 138 julToSpiMap = Collections.unmodifiableMap(map); 139 } 140 141 public static class MyBundle extends ResourceBundle { 142 143 final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>(); 144 145 @Override 146 protected Object handleGetObject(String key) { 147 if (key.contains(" (translated)")) { 148 throw new RuntimeException("Unexpected key: " + key); 149 } 150 return map.computeIfAbsent(key, k -> k + " (translated)"); 151 } 152 153 @Override 154 public Enumeration<String> getKeys() { 155 return Collections.enumeration(map.keySet()); 156 } 157 158 } 159 public static class MyLoggerBundle extends MyBundle { 160 161 } 162 163 public static interface TestLoggerFinder { 164 final ConcurrentHashMap<String, LoggerImpl> system = new ConcurrentHashMap<>(); 165 final ConcurrentHashMap<String, LoggerImpl> user = new ConcurrentHashMap<>(); 166 public Queue<LogEvent> eventQueue = new ArrayBlockingQueue<>(128); 167 168 public static final class LogEvent implements Cloneable { 169 170 public LogEvent() { 171 this(sequencer.getAndIncrement()); 172 } 173 174 LogEvent(long sequenceNumber) { 175 this.sequenceNumber = sequenceNumber; 176 } 177 178 boolean callSupplier = false; 179 long sequenceNumber; 180 boolean isLoggable; 181 String loggerName; 182 Level level; 183 ResourceBundle bundle; 184 Throwable thrown; 185 Object[] args; 186 Supplier<String> supplier; 187 String msg; 188 189 Object[] toArray(boolean callSupplier) { 190 return new Object[] { 191 sequenceNumber, 192 isLoggable, 193 loggerName, 194 level, 195 bundle, 196 thrown, 197 args, 198 callSupplier && supplier != null ? supplier.get() : supplier, 199 msg, 200 }; 201 } 202 203 boolean callSupplier(Object obj) { 204 return callSupplier || ((LogEvent)obj).callSupplier; 205 } 206 207 @Override 208 public String toString() { 209 return Arrays.deepToString(toArray(false)); 210 } 211 212 213 214 @Override 215 public boolean equals(Object obj) { 216 return obj instanceof LogEvent 217 && Objects.deepEquals(toArray(callSupplier(obj)), ((LogEvent)obj).toArray(callSupplier(obj))); 218 } 219 220 @Override 221 public int hashCode() { 222 return Objects.hash(toArray(true)); 223 } 224 225 public LogEvent cloneWith(long sequenceNumber) 226 throws CloneNotSupportedException { 227 LogEvent cloned = (LogEvent)super.clone(); 228 cloned.sequenceNumber = sequenceNumber; 229 return cloned; 230 } 231 232 public static LogEvent of(boolean isLoggable, String name, 233 Level level, ResourceBundle bundle, 234 String key, Throwable thrown) { 235 LogEvent evt = new LogEvent(); 236 evt.isLoggable = isLoggable; 237 evt.loggerName = name; 238 evt.level = level; 239 evt.args = null; 240 evt.bundle = bundle; 241 evt.thrown = thrown; 242 evt.supplier = null; 243 evt.msg = key; 244 return evt; 245 } 246 247 public static LogEvent of(boolean isLoggable, String name, 248 Level level, Throwable thrown, Supplier<String> supplier) { 249 LogEvent evt = new LogEvent(); 250 evt.isLoggable = isLoggable; 251 evt.loggerName = name; 252 evt.level = level; 253 evt.args = null; 254 evt.bundle = null; 255 evt.thrown = thrown; 256 evt.supplier = supplier; 257 evt.msg = null; 258 return evt; 259 } 260 261 public static LogEvent of(boolean isLoggable, String name, 262 Level level, ResourceBundle bundle, 263 String key, Object... params) { 264 LogEvent evt = new LogEvent(); 265 evt.isLoggable = isLoggable; 266 evt.loggerName = name; 267 evt.level = level; 268 evt.args = params; 269 evt.bundle = bundle; 270 evt.thrown = null; 271 evt.supplier = null; 272 evt.msg = key; 273 return evt; 274 } 275 276 public static LogEvent of(long sequenceNumber, 277 boolean isLoggable, String name, 278 Level level, ResourceBundle bundle, 279 String key, Supplier<String> supplier, 280 Throwable thrown, Object... params) { 281 LogEvent evt = new LogEvent(sequenceNumber); 282 evt.loggerName = name; 283 evt.level = level; 284 evt.args = params; 285 evt.bundle = bundle; 286 evt.thrown = thrown; 287 evt.supplier = supplier; 288 evt.msg = key; 289 evt.isLoggable = isLoggable; 290 return evt; 291 } 292 293 public static LogEvent ofp(boolean callSupplier, LogEvent evt) { 294 evt.callSupplier = callSupplier; 295 return evt; 296 } 297 } 298 299 public class LoggerImpl implements Logger { 300 private final String name; 301 private Level level = Level.INFO; 302 303 public LoggerImpl(String name) { 304 this.name = name; 305 } 306 307 @Override 308 public String getName() { 309 return name; 310 } 311 312 @Override 313 public boolean isLoggable(Level level) { 314 return this.level != Level.OFF && this.level.getSeverity() <= level.getSeverity(); 315 } 316 317 @Override 318 public void log(Level level, ResourceBundle bundle, String key, Throwable thrown) { 319 log(LogEvent.of(isLoggable(level), this.name, level, bundle, key, thrown)); 320 } 321 322 @Override 323 public void log(Level level, ResourceBundle bundle, String format, Object... params) { 324 log(LogEvent.of(isLoggable(level), name, level, bundle, format, params)); 325 } 326 327 void log(LogEvent event) { 328 eventQueue.add(event); 329 } 330 331 @Override 332 public void log(Level level, Supplier<String> msgSupplier) { 333 log(LogEvent.of(isLoggable(level), name, level, null, msgSupplier)); 334 } 335 336 @Override 337 public void log(Level level, Supplier<String> msgSupplier, Throwable thrown) { 338 log(LogEvent.of(isLoggable(level), name, level, thrown, msgSupplier)); 339 } 340 341 342 343 } 344 345 public Logger getLogger(String name, Class<?> caller); 346 public Logger getLocalizedLogger(String name, ResourceBundle bundle, Class<?> caller); 347 } 348 349 public static class BaseLoggerFinder extends LoggerFinder implements TestLoggerFinder { 350 static final RuntimePermission LOGGERFINDER_PERMISSION = 351 new RuntimePermission("loggerFinder"); 352 @Override 353 public Logger getLogger(String name, Class<?> caller) { 354 SecurityManager sm = System.getSecurityManager(); 355 if (sm != null) { 356 sm.checkPermission(LOGGERFINDER_PERMISSION); 357 } 358 PrivilegedAction<ClassLoader> pa = () -> caller.getClassLoader(); 359 ClassLoader callerLoader = AccessController.doPrivileged(pa); 360 if (callerLoader == null) { 361 return system.computeIfAbsent(name, (n) -> new LoggerImpl(n)); 362 } else { 363 return user.computeIfAbsent(name, (n) -> new LoggerImpl(n)); 364 } 365 } 366 } 367 368 static PlatformLogger.Bridge convert(Logger logger) { 369 boolean old = allowAll.get().get(); 370 allowAccess.get().set(true); 371 try { 372 return PlatformLogger.Bridge.convert(logger); 373 } finally { 374 allowAccess.get().set(old); 375 } 376 } 377 378 static Logger getLogger(String name, Class<?> caller) { 379 boolean old = allowAll.get().get(); 380 allowAccess.get().set(true); 381 try { 382 return jdk.internal.logger.LazyLoggers.getLogger(name, caller); 383 } finally { 384 allowAccess.get().set(old); 385 } 386 } 387 388 static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS}; 389 390 static void setSecurityManager() { 391 if (System.getSecurityManager() == null) { 392 // Ugly test hack: preload the resources needed by String.format 393 // We need to do that before setting the security manager 394 // because our implementation of CustomSystemClassLoader 395 // doesn't have the required permission. 396 System.out.println(String.format("debug: %s", "Setting security manager")); 397 Policy.setPolicy(new SimplePolicy(allowControl, allowAccess, allowAll)); 398 System.setSecurityManager(new SecurityManager()); 399 } 400 } 401 402 public static void main(String[] args) { 403 if (args.length == 0) 404 args = new String[] { 405 "NOSECURITY", 406 "NOPERMISSIONS", 407 "WITHPERMISSIONS" 408 }; 409 410 411 Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> { 412 TestLoggerFinder provider; 413 switch (testCase) { 414 case NOSECURITY: 415 System.out.println("\n*** Without Security Manager\n"); 416 provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder()); 417 test(provider, true); 418 System.out.println("Tetscase count: " + sequencer.get()); 419 break; 420 case NOPERMISSIONS: 421 System.out.println("\n*** With Security Manager, without permissions\n"); 422 setSecurityManager(); 423 try { 424 provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder()); 425 throw new RuntimeException("Expected exception not raised"); 426 } catch (AccessControlException x) { 427 if (!LOGGERFINDER_PERMISSION.equals(x.getPermission())) { 428 throw new RuntimeException("Unexpected permission check", x); 429 } 430 final boolean control = allowControl.get().get(); 431 try { 432 allowControl.get().set(true); 433 provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder()); 434 } finally { 435 allowControl.get().set(control); 436 } 437 } 438 test(provider, false); 439 System.out.println("Tetscase count: " + sequencer.get()); 440 break; 441 case WITHPERMISSIONS: 442 System.out.println("\n*** With Security Manager, with control permission\n"); 443 setSecurityManager(); 444 final boolean control = allowControl.get().get(); 445 try { 446 allowControl.get().set(true); 447 provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder()); 448 test(provider, true); 449 } finally { 450 allowControl.get().set(control); 451 } 452 break; 453 default: 454 throw new RuntimeException("Unknown test case: " + testCase); 455 } 456 }); 457 System.out.println("\nPASSED: Tested " + sequencer.get() + " cases."); 458 } 459 460 public static void test(TestLoggerFinder provider, boolean hasRequiredPermissions) { 461 462 ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName()); 463 final Map<Object, String> loggerDescMap = new HashMap<>(); 464 465 466 TestLoggerFinder.LoggerImpl appSink = null; 467 try { 468 appSink = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", BaseLoggerBridgeTest.class)); 469 if (!hasRequiredPermissions) { 470 throw new RuntimeException("Managed to obtain a system logger without permission"); 471 } 472 } catch (AccessControlException acx) { 473 if (hasRequiredPermissions) { 474 throw new RuntimeException("Unexpected security exception: ", acx); 475 } 476 if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) { 477 throw new RuntimeException("Unexpected permission in exception: " + acx, acx); 478 } 479 System.out.println("Got expected exception for logger: " + acx); 480 boolean old = allowControl.get().get(); 481 allowControl.get().set(true); 482 try { 483 appSink = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", BaseLoggerBridgeTest.class)); 484 } finally { 485 allowControl.get().set(old); 486 } 487 } 488 489 490 TestLoggerFinder.LoggerImpl sysSink = null; 491 try { 492 sysSink = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class)); 493 if (!hasRequiredPermissions) { 494 throw new RuntimeException("Managed to obtain a system logger without permission"); 495 } 496 } catch (AccessControlException acx) { 497 if (hasRequiredPermissions) { 498 throw new RuntimeException("Unexpected security exception: ", acx); 499 } 500 if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) { 501 throw new RuntimeException("Unexpected permission in exception: " + acx, acx); 502 } 503 System.out.println("Got expected exception for system logger: " + acx); 504 } 505 if (hasRequiredPermissions && appSink == sysSink) { 506 throw new RuntimeException("identical loggers"); 507 } 508 509 if (provider.system.contains(appSink)) { 510 throw new RuntimeException("app logger in system map"); 511 } 512 if (!provider.user.contains(appSink)) { 513 throw new RuntimeException("app logger not in appplication map"); 514 } 515 if (hasRequiredPermissions && provider.user.contains(sysSink)) { 516 throw new RuntimeException("sys logger in appplication map"); 517 } 518 if (hasRequiredPermissions && !provider.system.contains(sysSink)) { 519 throw new RuntimeException("sys logger not in system map"); 520 } 521 522 Logger appLogger1 = System.getLogger("foo"); 523 loggerDescMap.put(appLogger1, "System.getLogger(\"foo\")"); 524 PlatformLogger.Bridge bridge = convert(appLogger1); 525 loggerDescMap.putIfAbsent(bridge, "PlatformLogger.Bridge.convert(System.getLogger(\"foo\"))"); 526 testLogger(provider, loggerDescMap, "foo", null, bridge, appSink); 527 528 Logger sysLogger1 = null; 529 try { 530 sysLogger1 = getLogger("foo", Thread.class); 531 loggerDescMap.put(sysLogger1, 532 "jdk.internal.logger.LazyLoggers.getLogger(\"foo\", Thread.class)"); 533 534 if (!hasRequiredPermissions) { 535 // check that the provider would have thrown an exception 536 provider.getLogger("foo", Thread.class); 537 throw new RuntimeException("Managed to obtain a system logger without permission"); 538 } 539 } catch (AccessControlException acx) { 540 if (hasRequiredPermissions) { 541 throw new RuntimeException("Unexpected security exception: ", acx); 542 } 543 if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) { 544 throw new RuntimeException("Unexpected permission in exception: " + acx, acx); 545 } 546 System.out.println("Got expected exception for system logger: " + acx); 547 } 548 549 if (hasRequiredPermissions) { 550 // if we don't have permissions sysSink will be null. 551 testLogger(provider, loggerDescMap, "foo", null, 552 PlatformLogger.Bridge.convert(sysLogger1), sysSink); 553 } 554 555 Logger appLogger2 = 556 System.getLogger("foo", loggerBundle); 557 loggerDescMap.put(appLogger2, "System.getLogger(\"foo\", loggerBundle)"); 558 559 if (appLogger2 == appLogger1) { 560 throw new RuntimeException("identical loggers"); 561 } 562 563 if (provider.system.contains(appLogger2)) { 564 throw new RuntimeException("localized app logger in system map"); 565 } 566 if (provider.user.contains(appLogger2)) { 567 throw new RuntimeException("localized app logger in appplication map"); 568 } 569 570 testLogger(provider, loggerDescMap, "foo", loggerBundle, 571 PlatformLogger.Bridge.convert(appLogger2), appSink); 572 573 Logger sysLogger2 = null; 574 try { 575 sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class); 576 loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class)"); 577 if (!hasRequiredPermissions) { 578 throw new RuntimeException("Managed to obtain a system logger without permission"); 579 } 580 } catch (AccessControlException acx) { 581 if (hasRequiredPermissions) { 582 throw new RuntimeException("Unexpected security exception: ", acx); 583 } 584 if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) { 585 throw new RuntimeException("Unexpected permission in exception: " + acx, acx); 586 } 587 System.out.println("Got expected exception for localized system logger: " + acx); 588 } 589 if (hasRequiredPermissions && appLogger2 == sysLogger2) { 590 throw new RuntimeException("identical loggers"); 591 } 592 if (hasRequiredPermissions && sysLogger2 == sysLogger1) { 593 throw new RuntimeException("identical loggers"); 594 } 595 if (hasRequiredPermissions && provider.user.contains(sysLogger2)) { 596 throw new RuntimeException("localized sys logger in appplication map"); 597 } 598 if (hasRequiredPermissions && provider.system.contains(sysLogger2)) { 599 throw new RuntimeException("localized sys logger not in system map"); 600 } 601 602 if (hasRequiredPermissions) { 603 // if we don't have permissions sysSink will be null. 604 testLogger(provider, loggerDescMap, "foo", loggerBundle, 605 PlatformLogger.Bridge.convert(sysLogger2), sysSink); 606 } 607 608 } 609 610 public static class Foo { 611 612 } 613 614 static void verbose(String msg) { 615 if (VERBOSE) { 616 System.out.println(msg); 617 } 618 } 619 620 static void checkLogEvent(TestLoggerFinder provider, String desc, 621 TestLoggerFinder.LogEvent expected) { 622 TestLoggerFinder.LogEvent actual = provider.eventQueue.poll(); 623 if (!Objects.equals(expected, actual)) { 624 throw new RuntimeException("mismatch for " + desc 625 + "\n\texpected=" + expected 626 + "\n\t actual=" + actual); 627 } else { 628 verbose("Got expected results for " 629 + desc + "\n\t" + expected); 630 } 631 } 632 633 static void checkLogEvent(TestLoggerFinder provider, String desc, 634 TestLoggerFinder.LogEvent expected, boolean expectNotNull) { 635 TestLoggerFinder.LogEvent actual = provider.eventQueue.poll(); 636 if (actual == null && !expectNotNull) return; 637 if (actual != null && !expectNotNull) { 638 throw new RuntimeException("Unexpected log event found for " + desc 639 + "\n\tgot: " + actual); 640 } 641 if (!expected.equals(actual)) { 642 throw new RuntimeException("mismatch for " + desc 643 + "\n\texpected=" + expected 644 + "\n\t actual=" + actual); 645 } else { 646 verbose("Got expected results for " 647 + desc + "\n\t" + expected); 648 } 649 } 650 651 static Supplier<String> logpMessage(ResourceBundle bundle, 652 String className, String methodName, Supplier<String> msg) { 653 if (BEST_EFFORT_FOR_LOGP && bundle == null 654 && (className != null || methodName != null)) { 655 final String cName = className == null ? "" : className; 656 final String mName = methodName == null ? "" : methodName; 657 return () -> String.format("[%s %s] %s", cName, mName, msg.get()); 658 } else { 659 return msg; 660 } 661 } 662 663 static String logpMessage(ResourceBundle bundle, 664 String className, String methodName, String msg) { 665 if (BEST_EFFORT_FOR_LOGP && bundle == null 666 && (className != null || methodName != null)) { 667 final String cName = className == null ? "" : className; 668 final String mName = methodName == null ? "" : methodName; 669 return String.format("[%s %s] %s", cName, mName, msg == null ? "" : msg); 670 } else { 671 return msg; 672 } 673 } 674 675 // Calls the methods defined on LogProducer and verify the 676 // parameters received by the underlying TestLoggerFinder.LoggerImpl 677 // logger. 678 private static void testLogger(TestLoggerFinder provider, 679 Map<Object, String> loggerDescMap, 680 String name, 681 ResourceBundle loggerBundle, 682 PlatformLogger.Bridge logger, 683 TestLoggerFinder.LoggerImpl sink) { 684 685 if (loggerDescMap.get(logger) == null) { 686 throw new RuntimeException("Test bug: Missing description"); 687 } 688 System.out.println("Testing " + loggerDescMap.get(logger) +" [" + logger + "]"); 689 690 Foo foo = new Foo(); 691 String fooMsg = foo.toString(); 692 System.out.println("\tlogger.log(messageLevel, fooMsg)"); 693 System.out.println("\tlogger.<level>(fooMsg)"); 694 for (Level loggerLevel : Level.values()) { 695 sink.level = loggerLevel; 696 for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) { 697 String desc = "logger.log(messageLevel, fooMsg): loggerLevel=" 698 + loggerLevel+", messageLevel="+messageLevel; 699 Level expectedMessageLevel = julToSpiMap.get(messageLevel); 700 TestLoggerFinder.LogEvent expected = 701 TestLoggerFinder.LogEvent.of( 702 sequencer.get(), 703 loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0, 704 name, expectedMessageLevel, loggerBundle, 705 fooMsg, null, (Throwable)null, (Object[])null); 706 logger.log(messageLevel, fooMsg); 707 checkLogEvent(provider, desc, expected); 708 } 709 } 710 711 Supplier<String> supplier = new Supplier<String>() { 712 @Override 713 public String get() { 714 return this.toString(); 715 } 716 }; 717 System.out.println("\tlogger.log(messageLevel, supplier)"); 718 System.out.println("\tlogger.<level>(supplier)"); 719 for (Level loggerLevel : Level.values()) { 720 sink.level = loggerLevel; 721 for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) { 722 String desc = "logger.log(messageLevel, supplier): loggerLevel=" 723 + loggerLevel+", messageLevel="+messageLevel; 724 Level expectedMessageLevel = julToSpiMap.get(messageLevel); 725 TestLoggerFinder.LogEvent expected = 726 TestLoggerFinder.LogEvent.of( 727 sequencer.get(), 728 loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0, 729 name, expectedMessageLevel, (ResourceBundle) null, 730 null, supplier, (Throwable)null, (Object[])null); 731 logger.log(messageLevel, supplier); 732 checkLogEvent(provider, desc, expected); 733 } 734 } 735 736 String format = "two params [{1} {2}]"; 737 Object arg1 = foo; 738 Object arg2 = fooMsg; 739 System.out.println("\tlogger.log(messageLevel, format, arg1, arg2)"); 740 for (Level loggerLevel : Level.values()) { 741 sink.level = loggerLevel; 742 for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) { 743 String desc = "logger.log(messageLevel, format, foo, fooMsg): loggerLevel=" 744 + loggerLevel+", messageLevel="+messageLevel; 745 Level expectedMessageLevel = julToSpiMap.get(messageLevel); 746 TestLoggerFinder.LogEvent expected = 747 TestLoggerFinder.LogEvent.of( 748 sequencer.get(), 749 loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0, 750 name, expectedMessageLevel, loggerBundle, 751 format, null, (Throwable)null, arg1, arg2); 752 logger.log(messageLevel, format, arg1, arg2); 753 checkLogEvent(provider, desc, expected); 754 } 755 } 756 757 Throwable thrown = new Exception("OK: log me!"); 758 System.out.println("\tlogger.log(messageLevel, fooMsg, thrown)"); 759 for (Level loggerLevel : Level.values()) { 760 sink.level = loggerLevel; 761 for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) { 762 String desc = "logger.log(messageLevel, fooMsg, thrown): loggerLevel=" 763 + loggerLevel+", messageLevel="+messageLevel; 764 Level expectedMessageLevel = julToSpiMap.get(messageLevel); 765 TestLoggerFinder.LogEvent expected = 766 TestLoggerFinder.LogEvent.of( 767 sequencer.get(), 768 loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0, 769 name, expectedMessageLevel, loggerBundle, 770 fooMsg, null, thrown, (Object[])null); 771 logger.log(messageLevel, fooMsg, thrown); 772 checkLogEvent(provider, desc, expected); 773 } 774 } 775 776 System.out.println("\tlogger.log(messageLevel, thrown, supplier)"); 777 for (Level loggerLevel : Level.values()) { 778 sink.level = loggerLevel; 779 for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) { 780 String desc = "logger.log(messageLevel, thrown, supplier): loggerLevel=" 781 + loggerLevel+", messageLevel="+messageLevel; 782 Level expectedMessageLevel = julToSpiMap.get(messageLevel); 783 TestLoggerFinder.LogEvent expected = 784 TestLoggerFinder.LogEvent.of( 785 sequencer.get(), 786 loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0, 787 name, expectedMessageLevel, (ResourceBundle)null, 788 null, supplier, thrown, (Object[])null); 789 logger.log(messageLevel, thrown, supplier); 790 checkLogEvent(provider, desc, expected); 791 } 792 } 793 794 String sourceClass = "blah.Blah"; 795 String sourceMethod = "blih"; 796 System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, fooMsg)"); 797 for (Level loggerLevel : Level.values()) { 798 sink.level = loggerLevel; 799 for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) { 800 String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, fooMsg): loggerLevel=" 801 + loggerLevel+", messageLevel="+messageLevel; 802 Level expectedMessageLevel = julToSpiMap.get(messageLevel); 803 boolean isLoggable = loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0; 804 TestLoggerFinder.LogEvent expected = 805 isLoggable || loggerBundle != null && BEST_EFFORT_FOR_LOGP? 806 TestLoggerFinder.LogEvent.of( 807 sequencer.get(), 808 isLoggable, 809 name, expectedMessageLevel, loggerBundle, 810 logpMessage(loggerBundle, sourceClass, sourceMethod, fooMsg), 811 null, (Throwable)null, (Object[]) null) : null; 812 logger.logp(messageLevel, sourceClass, sourceMethod, fooMsg); 813 checkLogEvent(provider, desc, expected); 814 } 815 } 816 817 System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, supplier)"); 818 for (Level loggerLevel : Level.values()) { 819 sink.level = loggerLevel; 820 for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) { 821 String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, supplier): loggerLevel=" 822 + loggerLevel+", messageLevel="+messageLevel; 823 Level expectedMessageLevel = julToSpiMap.get(messageLevel); 824 boolean isLoggable = loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0; 825 TestLoggerFinder.LogEvent expected = isLoggable ? 826 TestLoggerFinder.LogEvent.ofp(BEST_EFFORT_FOR_LOGP, 827 TestLoggerFinder.LogEvent.of( 828 sequencer.get(), 829 isLoggable, 830 name, expectedMessageLevel, null, null, 831 logpMessage(null, sourceClass, sourceMethod, supplier), 832 (Throwable)null, (Object[]) null)) : null; 833 logger.logp(messageLevel, sourceClass, sourceMethod, supplier); 834 checkLogEvent(provider, desc, expected); 835 } 836 } 837 838 System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, format, arg1, arg2)"); 839 for (Level loggerLevel : Level.values()) { 840 sink.level = loggerLevel; 841 for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) { 842 String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, format, arg1, arg2): loggerLevel=" 843 + loggerLevel+", messageLevel="+messageLevel; 844 Level expectedMessageLevel = julToSpiMap.get(messageLevel); 845 boolean isLoggable = loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0; 846 TestLoggerFinder.LogEvent expected = 847 isLoggable || loggerBundle != null && BEST_EFFORT_FOR_LOGP? 848 TestLoggerFinder.LogEvent.of( 849 sequencer.get(), 850 loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0, 851 name, expectedMessageLevel, loggerBundle, 852 logpMessage(loggerBundle, sourceClass, sourceMethod, format), 853 null, (Throwable)null, arg1, arg2) : null; 854 logger.logp(messageLevel, sourceClass, sourceMethod, format, arg1, arg2); 855 checkLogEvent(provider, desc, expected); 856 } 857 } 858 859 System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, fooMsg, thrown)"); 860 for (Level loggerLevel : Level.values()) { 861 sink.level = loggerLevel; 862 for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) { 863 String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, fooMsg, thrown): loggerLevel=" 864 + loggerLevel+", messageLevel="+messageLevel; 865 Level expectedMessageLevel = julToSpiMap.get(messageLevel); 866 boolean isLoggable = loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0; 867 TestLoggerFinder.LogEvent expected = 868 isLoggable || loggerBundle != null && BEST_EFFORT_FOR_LOGP ? 869 TestLoggerFinder.LogEvent.of( 870 sequencer.get(), 871 loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0, 872 name, expectedMessageLevel, loggerBundle, 873 logpMessage(loggerBundle, sourceClass, sourceMethod, fooMsg), 874 null, thrown, (Object[])null) : null; 875 logger.logp(messageLevel, sourceClass, sourceMethod, fooMsg, thrown); 876 checkLogEvent(provider, desc, expected); 877 } 878 } 879 880 System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, thrown, supplier)"); 881 for (Level loggerLevel : Level.values()) { 882 sink.level = loggerLevel; 883 for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) { 884 String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, thrown, supplier): loggerLevel=" 885 + loggerLevel+", messageLevel="+messageLevel; 886 Level expectedMessageLevel = julToSpiMap.get(messageLevel); 887 boolean isLoggable = loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0; 888 TestLoggerFinder.LogEvent expected = isLoggable ? 889 TestLoggerFinder.LogEvent.ofp(BEST_EFFORT_FOR_LOGP, 890 TestLoggerFinder.LogEvent.of( 891 sequencer.get(), 892 loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0, 893 name, expectedMessageLevel, null, null, 894 logpMessage(null, sourceClass, sourceMethod, supplier), 895 thrown, (Object[])null)) : null; 896 logger.logp(messageLevel, sourceClass, sourceMethod, thrown, supplier); 897 checkLogEvent(provider, desc, expected); 898 } 899 } 900 901 ResourceBundle bundle = ResourceBundle.getBundle(MyBundle.class.getName()); 902 System.out.println("\tlogger.logrb(messageLevel, bundle, format, arg1, arg2)"); 903 for (Level loggerLevel : Level.values()) { 904 sink.level = loggerLevel; 905 for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) { 906 String desc = "logger.logrb(messageLevel, bundle, format, arg1, arg2): loggerLevel=" 907 + loggerLevel+", messageLevel="+messageLevel; 908 Level expectedMessageLevel = julToSpiMap.get(messageLevel); 909 TestLoggerFinder.LogEvent expected = 910 TestLoggerFinder.LogEvent.of( 911 sequencer.get(), 912 loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0, 913 name, expectedMessageLevel, bundle, 914 format, null, (Throwable)null, arg1, arg2); 915 logger.logrb(messageLevel, bundle, format, arg1, arg2); 916 checkLogEvent(provider, desc, expected); 917 } 918 } 919 920 System.out.println("\tlogger.logrb(messageLevel, bundle, msg, thrown)"); 921 for (Level loggerLevel : Level.values()) { 922 sink.level = loggerLevel; 923 for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) { 924 String desc = "logger.logrb(messageLevel, bundle, msg, thrown): loggerLevel=" 925 + loggerLevel+", messageLevel="+messageLevel; 926 Level expectedMessageLevel = julToSpiMap.get(messageLevel); 927 TestLoggerFinder.LogEvent expected = 928 TestLoggerFinder.LogEvent.of( 929 sequencer.get(), 930 loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0, 931 name, expectedMessageLevel, bundle, 932 fooMsg, null, thrown, (Object[])null); 933 logger.logrb(messageLevel, bundle, fooMsg, thrown); 934 checkLogEvent(provider, desc, expected); 935 } 936 } 937 938 System.out.println("\tlogger.logrb(messageLevel, sourceClass, sourceMethod, bundle, format, arg1, arg2)"); 939 for (Level loggerLevel : Level.values()) { 940 sink.level = loggerLevel; 941 for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) { 942 String desc = "logger.logrb(messageLevel, sourceClass, sourceMethod, bundle, format, arg1, arg2): loggerLevel=" 943 + loggerLevel+", messageLevel="+messageLevel; 944 Level expectedMessageLevel = julToSpiMap.get(messageLevel); 945 TestLoggerFinder.LogEvent expected = 946 TestLoggerFinder.LogEvent.of( 947 sequencer.get(), 948 loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0, 949 name, expectedMessageLevel, bundle, 950 format, null, (Throwable)null, arg1, arg2); 951 logger.logrb(messageLevel, sourceClass, sourceMethod, bundle, format, arg1, arg2); 952 checkLogEvent(provider, desc, expected); 953 } 954 } 955 956 System.out.println("\tlogger.logrb(messageLevel, sourceClass, sourceMethod, bundle, msg, thrown)"); 957 for (Level loggerLevel : Level.values()) { 958 sink.level = loggerLevel; 959 for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) { 960 String desc = "logger.logrb(messageLevel, sourceClass, sourceMethod, bundle, msg, thrown): loggerLevel=" 961 + loggerLevel+", messageLevel="+messageLevel; 962 Level expectedMessageLevel = julToSpiMap.get(messageLevel); 963 TestLoggerFinder.LogEvent expected = 964 TestLoggerFinder.LogEvent.of( 965 sequencer.get(), 966 loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0, 967 name, expectedMessageLevel, bundle, 968 fooMsg, null, thrown, (Object[])null); 969 logger.logrb(messageLevel, sourceClass, sourceMethod, bundle, fooMsg, thrown); 970 checkLogEvent(provider, desc, expected); 971 } 972 } 973 } 974 975 final static class PermissionsBuilder { 976 final Permissions perms; 977 public PermissionsBuilder() { 978 this(new Permissions()); 979 } 980 public PermissionsBuilder(Permissions perms) { 981 this.perms = perms; 982 } 983 public PermissionsBuilder add(Permission p) { 984 perms.add(p); 985 return this; 986 } 987 public PermissionsBuilder addAll(PermissionCollection col) { 988 if (col != null) { 989 for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) { 990 perms.add(e.nextElement()); 991 } 992 } 993 return this; 994 } 995 public Permissions toPermissions() { 996 final PermissionsBuilder builder = new PermissionsBuilder(); 997 builder.addAll(perms); 998 return builder.perms; 999 } 1000 } 1001 1002 public static class SimplePolicy extends Policy { 1003 final static RuntimePermission CONTROL = LOGGERFINDER_PERMISSION; 1004 final static RuntimePermission ACCESS_LOGGER = new RuntimePermission("accessClassInPackage.jdk.internal.logger"); 1005 final static RuntimePermission ACCESS_LOGGING = new RuntimePermission("accessClassInPackage.sun.util.logging"); 1006 1007 final Permissions permissions; 1008 final Permissions allPermissions; 1009 final ThreadLocal<AtomicBoolean> allowControl; 1010 final ThreadLocal<AtomicBoolean> allowAccess; 1011 final ThreadLocal<AtomicBoolean> allowAll; 1012 public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl, 1013 ThreadLocal<AtomicBoolean> allowAccess, 1014 ThreadLocal<AtomicBoolean> allowAll) { 1015 this.allowControl = allowControl; 1016 this.allowAccess = allowAccess; 1017 this.allowAll = allowAll; 1018 permissions = new Permissions(); 1019 allPermissions = new PermissionsBuilder() 1020 .add(new java.security.AllPermission()) 1021 .toPermissions(); 1022 } 1023 1024 Permissions getPermissions() { 1025 if (allowControl.get().get() || allowAccess.get().get() || allowAll.get().get()) { 1026 PermissionsBuilder builder = new PermissionsBuilder() 1027 .addAll(permissions); 1028 if (allowControl.get().get()) { 1029 builder.add(CONTROL); 1030 } 1031 if (allowAccess.get().get()) { 1032 builder.add(ACCESS_LOGGER); 1033 builder.add(ACCESS_LOGGING); 1034 } 1035 if (allowAll.get().get()) { 1036 builder.addAll(allPermissions); 1037 } 1038 return builder.toPermissions(); 1039 } 1040 return permissions; 1041 } 1042 1043 @Override 1044 public boolean implies(ProtectionDomain domain, Permission permission) { 1045 return getPermissions().implies(permission); 1046 } 1047 1048 @Override 1049 public PermissionCollection getPermissions(CodeSource codesource) { 1050 return new PermissionsBuilder().addAll(getPermissions()).toPermissions(); 1051 } 1052 1053 @Override 1054 public PermissionCollection getPermissions(ProtectionDomain domain) { 1055 return new PermissionsBuilder().addAll(getPermissions()).toPermissions(); 1056 } 1057 } 1058 }