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