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