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 }