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