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