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.security.AccessControlException;
  24 import java.security.AccessController;
  25 import java.security.CodeSource;
  26 import java.security.Permission;
  27 import java.security.PermissionCollection;
  28 import java.security.Permissions;
  29 import java.security.Policy;
  30 import java.security.PrivilegedAction;
  31 import java.security.ProtectionDomain;
  32 import java.util.Arrays;
  33 import java.util.Collections;
  34 import java.util.Enumeration;
  35 import java.util.HashMap;
  36 import java.util.Map;
  37 import java.util.Objects;
  38 import java.util.Queue;
  39 import java.util.ResourceBundle;
  40 import java.util.concurrent.ArrayBlockingQueue;
  41 import java.util.concurrent.ConcurrentHashMap;
  42 import java.util.concurrent.atomic.AtomicBoolean;
  43 import java.util.concurrent.atomic.AtomicLong;
  44 import java.util.function.Supplier;
  45 import java.util.logging.Handler;
  46 import java.util.logging.LogRecord;
  47 import java.lang.System.LoggerFinder;
  48 import java.lang.System.Logger;
  49 import java.lang.System.Logger.Level;
  50 import java.util.stream.Stream;
  51 import sun.util.logging.PlatformLogger;
  52 import java.lang.reflect.Module;
  53 
  54 /**
  55  * @test
  56  * @bug     8140364
  57  * @summary JDK implementation specific unit test for JDK internal artifacts.
  58  *          Tests all bridge methods from PlatformLogger with the a custom
  59  *          backend whose loggers implement PlatformLogger.Bridge.
  60  * @modules java.base/sun.util.logging
  61  *          java.logging
  62  * @build CustomSystemClassLoader PlatformLoggerBridgeTest
  63  * @run  main/othervm -Djava.system.class.loader=CustomSystemClassLoader PlatformLoggerBridgeTest NOSECURITY
  64  * @run  main/othervm -Djava.system.class.loader=CustomSystemClassLoader PlatformLoggerBridgeTest NOPERMISSIONS
  65  * @run  main/othervm -Djava.system.class.loader=CustomSystemClassLoader PlatformLoggerBridgeTest WITHPERMISSIONS
  66  * @author danielfuchs
  67  */
  68 public class PlatformLoggerBridgeTest {
  69 
  70     static final RuntimePermission LOGGERFINDER_PERMISSION =
  71                 new RuntimePermission("loggerFinder");
  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     static final Class<?> providerClass;
  94     static {
  95         try {
  96             // Preload classes before the security manager is on.
  97             providerClass = ClassLoader.getSystemClassLoader().loadClass("PlatformLoggerBridgeTest$LogProducerFinder");
  98             ((LoggerFinder)providerClass.newInstance()).getLogger("foo", providerClass.getModule());
  99         } catch (Exception ex) {
 100             throw new ExceptionInInitializerError(ex);
 101         }
 102     }
 103 
 104     public static final Queue<LogEvent> eventQueue = new ArrayBlockingQueue<>(128);
 105 
 106     public static final class LogEvent implements Cloneable {
 107 
 108         public LogEvent() {
 109             this(sequencer.getAndIncrement());
 110         }
 111 
 112         LogEvent(long sequenceNumber) {
 113             this.sequenceNumber = sequenceNumber;
 114         }
 115 
 116         long sequenceNumber;
 117         boolean isLoggable;
 118         String loggerName;
 119         sun.util.logging.PlatformLogger.Level level;
 120         ResourceBundle bundle;
 121         Throwable thrown;
 122         Object[] args;
 123         String msg;
 124         Supplier<String> supplier;
 125         String className;
 126         String methodName;
 127 
 128         Object[] toArray() {
 129             return new Object[] {
 130                 sequenceNumber,
 131                 loggerName,
 132                 level,
 133                 isLoggable,
 134                 bundle,
 135                 msg,
 136                 supplier,
 137                 thrown,
 138                 args,
 139                 className,
 140                 methodName,
 141             };
 142         }
 143 
 144         @Override
 145         public String toString() {
 146             return Arrays.deepToString(toArray());
 147         }
 148 
 149         @Override
 150         public boolean equals(Object obj) {
 151             return obj instanceof LogEvent
 152                     && Objects.deepEquals(this.toArray(), ((LogEvent)obj).toArray());
 153         }
 154 
 155         @Override
 156         public int hashCode() {
 157             return Objects.hash(toArray());
 158         }
 159 
 160         public LogEvent cloneWith(long sequenceNumber)
 161                 throws CloneNotSupportedException {
 162             LogEvent cloned = (LogEvent)super.clone();
 163             cloned.sequenceNumber = sequenceNumber;
 164             return cloned;
 165         }
 166 
 167         public static LogEvent of(long sequenceNumber,
 168                 boolean isLoggable, String name,
 169                 sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
 170                 String key, Throwable thrown, Object... params) {
 171             return LogEvent.of(sequenceNumber, isLoggable, name,
 172                     null, null, level, bundle, key,
 173                     thrown, params);
 174         }
 175         public static LogEvent of(long sequenceNumber,
 176                 boolean isLoggable, String name,
 177                 sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
 178                 Supplier<String> supplier, Throwable thrown, Object... params) {
 179             return LogEvent.of(sequenceNumber, isLoggable, name,
 180                     null, null, level, bundle, supplier,
 181                     thrown, params);
 182         }
 183 
 184         public static LogEvent of(long sequenceNumber,
 185                 boolean isLoggable, String name,
 186                 String className, String methodName,
 187                 sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
 188                 String key, Throwable thrown, Object... params) {
 189             LogEvent evt = new LogEvent(sequenceNumber);
 190             evt.loggerName = name;
 191             evt.level = level;
 192             evt.args = params;
 193             evt.bundle = bundle;
 194             evt.thrown = thrown;
 195             evt.msg = key;
 196             evt.isLoggable = isLoggable;
 197             evt.className = className;
 198             evt.methodName = methodName;
 199             return evt;
 200         }
 201 
 202         public static LogEvent of(boolean isLoggable, String name,
 203                 String className, String methodName,
 204                 sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
 205                 String key, Throwable thrown, Object... params) {
 206             return LogEvent.of(sequencer.getAndIncrement(), isLoggable, name,
 207                     className, methodName, level, bundle, key, thrown, params);
 208         }
 209 
 210         public static LogEvent of(long sequenceNumber,
 211                 boolean isLoggable, String name,
 212                 String className, String methodName,
 213                 sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
 214                 Supplier<String> supplier, Throwable thrown, Object... params) {
 215             LogEvent evt = new LogEvent(sequenceNumber);
 216             evt.loggerName = name;
 217             evt.level = level;
 218             evt.args = params;
 219             evt.bundle = bundle;
 220             evt.thrown = thrown;
 221             evt.supplier = supplier;
 222             evt.isLoggable = isLoggable;
 223             evt.className = className;
 224             evt.methodName = methodName;
 225             return evt;
 226         }
 227 
 228         public static LogEvent of(boolean isLoggable, String name,
 229                 String className, String methodName,
 230                 sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
 231                 Supplier<String> supplier, Throwable thrown, Object... params) {
 232             return LogEvent.of(sequencer.getAndIncrement(), isLoggable, name,
 233                     className, methodName, level, bundle, supplier, thrown, params);
 234         }
 235 
 236     }
 237 
 238     public static class LogProducerFinder extends LoggerFinder {
 239         static final RuntimePermission LOGGERFINDER_PERMISSION =
 240                 new RuntimePermission("loggerFinder");
 241         final ConcurrentHashMap<String, LoggerImpl> system = new ConcurrentHashMap<>();
 242         final ConcurrentHashMap<String, LoggerImpl> user = new ConcurrentHashMap<>();
 243 
 244         public class LoggerImpl implements Logger, PlatformLogger.Bridge {
 245             private final String name;
 246             private sun.util.logging.PlatformLogger.Level level = sun.util.logging.PlatformLogger.Level.INFO;
 247             private sun.util.logging.PlatformLogger.Level OFF = sun.util.logging.PlatformLogger.Level.OFF;
 248             private sun.util.logging.PlatformLogger.Level FINE = sun.util.logging.PlatformLogger.Level.FINE;
 249             private sun.util.logging.PlatformLogger.Level FINER = sun.util.logging.PlatformLogger.Level.FINER;
 250             private sun.util.logging.PlatformLogger.Level FINEST = sun.util.logging.PlatformLogger.Level.FINEST;
 251             private sun.util.logging.PlatformLogger.Level CONFIG = sun.util.logging.PlatformLogger.Level.CONFIG;
 252             private sun.util.logging.PlatformLogger.Level INFO = sun.util.logging.PlatformLogger.Level.INFO;
 253             private sun.util.logging.PlatformLogger.Level WARNING = sun.util.logging.PlatformLogger.Level.WARNING;
 254             private sun.util.logging.PlatformLogger.Level SEVERE = sun.util.logging.PlatformLogger.Level.SEVERE;
 255 
 256             public LoggerImpl(String name) {
 257                 this.name = name;
 258             }
 259 
 260             @Override
 261             public String getName() {
 262                 return name;
 263             }
 264 
 265             @Override
 266             public boolean isLoggable(Level level) {
 267                 return this.level != OFF && this.level.intValue() <= level.getSeverity();
 268             }
 269 
 270             @Override
 271             public void log(Level level, ResourceBundle bundle,
 272                     String key, Throwable thrown) {
 273                 throw new UnsupportedOperationException();
 274             }
 275 
 276             @Override
 277             public void log(Level level, ResourceBundle bundle,
 278                     String format, Object... params) {
 279                 throw new UnsupportedOperationException();
 280             }
 281 
 282             void log(LogEvent event) {
 283                 eventQueue.add(event);
 284             }
 285 
 286             @Override
 287             public void log(Level level, Supplier<String> msgSupplier) {
 288                 throw new UnsupportedOperationException();
 289             }
 290 
 291             @Override
 292             public void log(Level level, Supplier<String> msgSupplier,
 293                             Throwable thrown) {
 294                 throw new UnsupportedOperationException();
 295             }
 296 
 297             @Override
 298             public void log(sun.util.logging.PlatformLogger.Level level, String msg) {
 299                 log(LogEvent.of(isLoggable(level), name, null, null,
 300                         level, null, msg, null, (Object[])null));
 301             }
 302 
 303             @Override
 304             public void log(sun.util.logging.PlatformLogger.Level level,
 305                     Supplier<String> msgSupplier) {
 306                 log(LogEvent.of(isLoggable(level), name, null, null,
 307                         level, null, msgSupplier, null, (Object[])null));
 308             }
 309 
 310             @Override
 311             public void log(sun.util.logging.PlatformLogger.Level level, String msg,
 312                     Object... params) {
 313                 log(LogEvent.of(isLoggable(level), name, null, null,
 314                         level, null, msg, null, params));
 315             }
 316 
 317             @Override
 318             public void log(sun.util.logging.PlatformLogger.Level level, String msg,
 319                     Throwable thrown) {
 320                 log(LogEvent.of(isLoggable(level), name, null, null,
 321                         level, null, msg, thrown, (Object[])null));
 322             }
 323 
 324             @Override
 325             public void log(sun.util.logging.PlatformLogger.Level level, Throwable thrown,
 326                     Supplier<String> msgSupplier) {
 327                 log(LogEvent.of(isLoggable(level), name, null, null,
 328                         level, null, msgSupplier, thrown, (Object[])null));
 329             }
 330 
 331             @Override
 332             public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass,
 333                     String sourceMethod, String msg) {
 334                 log(LogEvent.of(isLoggable(level), name,
 335                         sourceClass, sourceMethod,
 336                         level, null, msg, null, (Object[])null));
 337             }
 338 
 339             @Override
 340             public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass,
 341                     String sourceMethod, Supplier<String> msgSupplier) {
 342                 log(LogEvent.of(isLoggable(level), name,
 343                         sourceClass, sourceMethod,
 344                         level, null, msgSupplier, null, (Object[])null));
 345             }
 346 
 347             @Override
 348             public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass,
 349                     String sourceMethod, String msg, Object... params) {
 350                 log(LogEvent.of(isLoggable(level), name,
 351                         sourceClass, sourceMethod,
 352                         level, null, msg, null, params));
 353             }
 354 
 355             @Override
 356             public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass,
 357                     String sourceMethod, String msg, Throwable thrown) {
 358                 log(LogEvent.of(isLoggable(level), name,
 359                         sourceClass, sourceMethod,
 360                         level, null, msg, thrown, (Object[])null));
 361             }
 362 
 363             @Override
 364             public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass,
 365                     String sourceMethod, Throwable thrown,
 366                     Supplier<String> msgSupplier) {
 367                 log(LogEvent.of(isLoggable(level), name,
 368                         sourceClass, sourceMethod,
 369                         level, null, msgSupplier, thrown, (Object[])null));
 370             }
 371 
 372             @Override
 373             public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass,
 374                     String sourceMethod, ResourceBundle bundle, String msg,
 375                     Object... params) {
 376                 log(LogEvent.of(isLoggable(level), name,
 377                         sourceClass, sourceMethod,
 378                         level, bundle, msg, null, params));
 379             }
 380 
 381             @Override
 382             public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
 383                     String msg, Object... params) {
 384                 log(LogEvent.of(isLoggable(level), name, null, null,
 385                         level, bundle, msg, null, params));
 386             }
 387 
 388             @Override
 389             public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass,
 390                     String sourceMethod, ResourceBundle bundle, String msg,
 391                     Throwable thrown) {
 392                 log(LogEvent.of(isLoggable(level), name,
 393                         sourceClass, sourceMethod,
 394                         level, bundle, msg, thrown, (Object[])null));
 395             }
 396 
 397             @Override
 398             public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
 399                     String msg, Throwable thrown) {
 400                 log(LogEvent.of(isLoggable(level), name, null, null,
 401                         level, bundle, msg, thrown, (Object[])null));
 402             }
 403 
 404             @Override
 405             public boolean isLoggable(sun.util.logging.PlatformLogger.Level level) {
 406                 return this.level != OFF && level.intValue()
 407                         >= this.level.intValue();
 408             }
 409 
 410             @Override
 411             public boolean isEnabled() {
 412                 return this.level != OFF;
 413             }
 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 final sun.util.logging.PlatformLogger.Level[] julLevels = {
 435         sun.util.logging.PlatformLogger.Level.ALL,
 436         sun.util.logging.PlatformLogger.Level.FINEST,
 437         sun.util.logging.PlatformLogger.Level.FINER,
 438         sun.util.logging.PlatformLogger.Level.FINE,
 439         sun.util.logging.PlatformLogger.Level.CONFIG,
 440         sun.util.logging.PlatformLogger.Level.INFO,
 441         sun.util.logging.PlatformLogger.Level.WARNING,
 442         sun.util.logging.PlatformLogger.Level.SEVERE,
 443         sun.util.logging.PlatformLogger.Level.OFF,
 444     };
 445 
 446     public static class MyBundle extends ResourceBundle {
 447 
 448         final ConcurrentHashMap map = new ConcurrentHashMap();
 449 
 450         @Override
 451         protected Object handleGetObject(String key) {
 452             if (key.contains(" (translated)")) {
 453                 throw new RuntimeException("Unexpected key: " + key);
 454             }
 455             return map.computeIfAbsent(key, k -> k + " (translated)");
 456         }
 457 
 458         @Override
 459         public Enumeration<String> getKeys() {
 460             return Collections.enumeration(map.keySet());
 461         }
 462 
 463     }
 464 
 465     public static class MyHandler extends Handler {
 466 
 467         @Override
 468         public java.util.logging.Level getLevel() {
 469             return java.util.logging.Level.ALL;
 470         }
 471 
 472         @Override
 473         public void publish(LogRecord record) {
 474             eventQueue.add(LogEvent.of(sequencer.getAndIncrement(),
 475                     true, record.getLoggerName(),
 476                     record.getSourceClassName(),
 477                     record.getSourceMethodName(),
 478                     PlatformLogger.Level.valueOf(record.getLevel().getName()),
 479                     record.getResourceBundle(), record.getMessage(),
 480                     record.getThrown(), record.getParameters()));
 481         }
 482         @Override
 483         public void flush() {
 484         }
 485         @Override
 486         public void close() throws SecurityException {
 487         }
 488 
 489     }
 490 
 491     public static class MyLoggerBundle extends MyBundle {
 492 
 493     }
 494 
 495     static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS};
 496 
 497     static void setSecurityManager() {
 498         if (System.getSecurityManager() == null) {
 499             Policy.setPolicy(new SimplePolicy(allowControl, allowAccess, allowAll));
 500             System.setSecurityManager(new SecurityManager());
 501         }
 502     }
 503 
 504     public static void main(String[] args) {
 505         if (args.length == 0)
 506             args = new String[] {
 507                 //"NOSECURITY",
 508                 "NOPERMISSIONS",
 509                 "WITHPERMISSIONS"
 510             };
 511 
 512 
 513         Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> {
 514             LoggerFinder provider;
 515             switch (testCase) {
 516                 case NOSECURITY:
 517                     System.out.println("\n*** Without Security Manager\n");
 518                     provider = LoggerFinder.getLoggerFinder();
 519                     test(provider, true);
 520                     System.out.println("Tetscase count: " + sequencer.get());
 521                     break;
 522                 case NOPERMISSIONS:
 523                     System.out.println("\n*** With Security Manager, without permissions\n");
 524                     setSecurityManager();
 525                     try {
 526                         provider = LoggerFinder.getLoggerFinder();
 527                         throw new RuntimeException("Expected exception not raised");
 528                     } catch (AccessControlException x) {
 529                         if (!LOGGERFINDER_PERMISSION.equals(x.getPermission())) {
 530                             throw new RuntimeException("Unexpected permission check", x);
 531                         }
 532                         final boolean control = allowControl.get().get();
 533                         try {
 534                             allowControl.get().set(true);
 535                             provider = LoggerFinder.getLoggerFinder();
 536                         } finally {
 537                             allowControl.get().set(control);
 538                         }
 539                     }
 540                     test(provider, false);
 541                     System.out.println("Tetscase count: " + sequencer.get());
 542                     break;
 543                 case WITHPERMISSIONS:
 544                     System.out.println("\n*** With Security Manager, with access permission\n");
 545                     setSecurityManager();
 546                     final boolean control = allowControl.get().get();
 547                     try {
 548                         allowControl.get().set(true);
 549                         provider = LoggerFinder.getLoggerFinder();
 550                     } finally {
 551                         allowControl.get().set(control);
 552                     }
 553                     final boolean access = allowAccess.get().get();
 554                     try {
 555                         allowAccess.get().set(true);
 556                         test(provider, true);
 557                     } finally {
 558                         allowAccess.get().set(access);
 559                     }
 560                     break;
 561                 default:
 562                     throw new RuntimeException("Unknown test case: " + testCase);
 563             }
 564         });
 565         System.out.println("\nPASSED: Tested " + sequencer.get() + " cases.");
 566     }
 567 
 568     public static void test(LoggerFinder provider, boolean hasRequiredPermissions) {
 569 
 570         final Map<PlatformLogger, String> loggerDescMap = new HashMap<>();
 571 
 572         PlatformLogger sysLogger1 = null;
 573         try {
 574             sysLogger1 = PlatformLogger.getLogger("foo");
 575             loggerDescMap.put(sysLogger1, "PlatformLogger.getLogger(\"foo\")");
 576             if (!hasRequiredPermissions) {
 577                 throw new RuntimeException("Managed to obtain a system logger without permission");
 578             }
 579         } catch (AccessControlException acx) {
 580             if (hasRequiredPermissions) {
 581                 throw new RuntimeException("Unexpected security exception: ", acx);
 582             }
 583             if (!acx.getPermission().equals(SimplePolicy.ACCESS_LOGGING)) {
 584                 throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
 585             }
 586             final boolean old = allowAccess.get().get();
 587             allowAccess.get().set(true);
 588             try {
 589                 sysLogger1 = PlatformLogger.getLogger("foo");
 590                 loggerDescMap.put(sysLogger1, "PlatformLogger.getLogger(\"foo\")");
 591             } finally {
 592                 allowAccess.get().set(old);
 593             }
 594             System.out.println("Got expected exception for system logger: " + acx);
 595         }
 596 
 597         final LogProducerFinder.LoggerImpl sysSink;
 598         boolean old = allowControl.get().get();
 599         allowControl.get().set(true);
 600         try {
 601            sysSink = LogProducerFinder.LoggerImpl.class.cast(
 602                         provider.getLogger("foo", Thread.class.getModule()));
 603         } finally {
 604             allowControl.get().set(old);
 605         }
 606 
 607         testLogger(provider, loggerDescMap, "foo", null, sysLogger1, sysSink);
 608     }
 609 
 610     public static class Foo {
 611 
 612     }
 613 
 614     static void verbose(String msg) {
 615        if (VERBOSE) {
 616            System.out.println(msg);
 617        }
 618     }
 619 
 620     static void checkLogEvent(LoggerFinder provider, String desc,
 621             LogEvent expected) {
 622         LogEvent actual =  eventQueue.poll();
 623         if (!expected.equals(actual)) {
 624             throw new RuntimeException("mismatch for " + desc
 625                     + "\n\texpected=" + expected
 626                     + "\n\t  actual=" + actual);
 627         } else {
 628             verbose("Got expected results for "
 629                     + desc + "\n\t" + expected);
 630         }
 631     }
 632 
 633     static void checkLogEvent(LoggerFinder provider, String desc,
 634             LogEvent expected, boolean expectNotNull) {
 635         LogEvent actual =  eventQueue.poll();
 636         if (actual == null && !expectNotNull) return;
 637         if (actual != null && !expectNotNull) {
 638             throw new RuntimeException("Unexpected log event found for " + desc
 639                 + "\n\tgot: " + actual);
 640         }
 641         if (!expected.equals(actual)) {
 642             throw new RuntimeException("mismatch for " + desc
 643                     + "\n\texpected=" + expected
 644                     + "\n\t  actual=" + actual);
 645         } else {
 646             verbose("Got expected results for "
 647                     + desc + "\n\t" + expected);
 648         }
 649     }
 650 
 651     static void setLevel( LogProducerFinder.LoggerImpl sink,
 652             sun.util.logging.PlatformLogger.Level loggerLevel) {
 653         sink.level = loggerLevel;
 654     }
 655 
 656     // Calls the methods defined on LogProducer and verify the
 657     // parameters received by the underlying LogProducerFinder.LoggerImpl
 658     // logger.
 659     private static void testLogger(LoggerFinder provider,
 660             Map<PlatformLogger, String> loggerDescMap,
 661             String name,
 662             ResourceBundle loggerBundle,
 663             PlatformLogger logger,
 664             LogProducerFinder.LoggerImpl sink) {
 665 
 666         System.out.println("Testing " + loggerDescMap.get(logger) + " [" + logger +"]");
 667         final sun.util.logging.PlatformLogger.Level OFF = sun.util.logging.PlatformLogger.Level.OFF;
 668         final sun.util.logging.PlatformLogger.Level ALL = sun.util.logging.PlatformLogger.Level.OFF;
 669 
 670         Foo foo = new Foo();
 671         String fooMsg = foo.toString();
 672         System.out.println("\tlogger.log(messageLevel, fooMsg)");
 673         System.out.println("\tlogger.<level>(fooMsg)");
 674         for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
 675             setLevel(sink, loggerLevel);
 676             for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
 677                 if (messageLevel == ALL || messageLevel == OFF) continue;
 678                 LogEvent expected =
 679                         LogEvent.of(
 680                             sequencer.get(),
 681                             loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
 682                             name, messageLevel, loggerBundle,
 683                             fooMsg, (Throwable)null, (Object[])null);
 684                 String desc2 = "logger." + messageLevel.toString().toLowerCase()
 685                         + "(fooMsg): loggerLevel="
 686                         + loggerLevel+", messageLevel="+messageLevel;
 687                 if (messageLevel == sun.util.logging.PlatformLogger.Level.FINEST) {
 688                     logger.finest(fooMsg);
 689                     checkLogEvent(provider, desc2, expected);
 690                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.FINER) {
 691                     logger.finer(fooMsg);
 692                     checkLogEvent(provider, desc2, expected);
 693                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.FINE) {
 694                     logger.fine(fooMsg);
 695                     checkLogEvent(provider, desc2, expected);
 696                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.CONFIG) {
 697                     logger.config(fooMsg);
 698                     checkLogEvent(provider, desc2, expected);
 699                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.INFO) {
 700                     logger.info(fooMsg);
 701                     checkLogEvent(provider, desc2, expected);
 702                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.WARNING) {
 703                     logger.warning(fooMsg);
 704                     checkLogEvent(provider, desc2, expected);
 705                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.SEVERE) {
 706                     logger.severe(fooMsg);
 707                     checkLogEvent(provider, desc2, expected);
 708                 }
 709             }
 710         }
 711 
 712         String format = "two params [{1} {2}]";
 713         Object arg1 = foo;
 714         Object arg2 = fooMsg;
 715         System.out.println("\tlogger.log(messageLevel, format, arg1, arg2)");
 716         for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
 717             setLevel(sink, loggerLevel);
 718             for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
 719                 if (messageLevel == ALL || messageLevel == OFF) continue;
 720                 LogEvent expected =
 721                         LogEvent.of(
 722                             sequencer.get(),
 723                             loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
 724                             name, messageLevel, loggerBundle,
 725                             format, (Throwable)null, arg1, arg2);
 726                 String desc2 = "logger." + messageLevel.toString().toLowerCase()
 727                         + "(format, foo, fooMsg): loggerLevel="
 728                         + loggerLevel+", messageLevel="+messageLevel;
 729                 if (messageLevel == sun.util.logging.PlatformLogger.Level.FINEST) {
 730                     logger.finest(format, arg1, arg2);
 731                     checkLogEvent(provider, desc2, expected);
 732                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.FINER) {
 733                     logger.finer(format, arg1, arg2);
 734                     checkLogEvent(provider, desc2, expected);
 735                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.FINE) {
 736                     logger.fine(format, arg1, arg2);
 737                     checkLogEvent(provider, desc2, expected);
 738                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.CONFIG) {
 739                     logger.config(format, arg1, arg2);
 740                     checkLogEvent(provider, desc2, expected);
 741                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.INFO) {
 742                     logger.info(format, arg1, arg2);
 743                     checkLogEvent(provider, desc2, expected);
 744                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.WARNING) {
 745                     logger.warning(format, arg1, arg2);
 746                     checkLogEvent(provider, desc2, expected);
 747                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.SEVERE) {
 748                     logger.severe(format, arg1, arg2);
 749                     checkLogEvent(provider, desc2, expected);
 750                 }
 751             }
 752         }
 753 
 754         Throwable thrown = new Exception("OK: log me!");
 755         System.out.println("\tlogger.log(messageLevel, fooMsg, thrown)");
 756         for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
 757             setLevel(sink, loggerLevel);
 758             for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
 759                 if (messageLevel == ALL || messageLevel == OFF) continue;
 760                 LogEvent expected =
 761                         LogEvent.of(
 762                             sequencer.get(),
 763                             loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
 764                             name, messageLevel, loggerBundle,
 765                             fooMsg, thrown, (Object[])null);
 766                 String desc2 = "logger." + messageLevel.toString().toLowerCase()
 767                         + "(fooMsg, thrown): loggerLevel="
 768                         + loggerLevel+", messageLevel="+messageLevel;
 769                 if (messageLevel == sun.util.logging.PlatformLogger.Level.FINEST) {
 770                     logger.finest(fooMsg, thrown);
 771                     checkLogEvent(provider, desc2, expected);
 772                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.FINER) {
 773                     logger.finer(fooMsg, thrown);
 774                     checkLogEvent(provider, desc2, expected);
 775                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.FINE) {
 776                     logger.fine(fooMsg, thrown);
 777                     checkLogEvent(provider, desc2, expected);
 778                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.CONFIG) {
 779                     logger.config(fooMsg, thrown);
 780                     checkLogEvent(provider, desc2, expected);
 781                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.INFO) {
 782                     logger.info(fooMsg, thrown);
 783                     checkLogEvent(provider, desc2, expected);
 784                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.WARNING) {
 785                     logger.warning(fooMsg, thrown);
 786                     checkLogEvent(provider, desc2, expected);
 787                 } else if (messageLevel == sun.util.logging.PlatformLogger.Level.SEVERE) {
 788                     logger.severe(fooMsg, thrown);
 789                     checkLogEvent(provider, desc2, expected);
 790                 }
 791             }
 792         }
 793     }
 794 
 795     final static class PermissionsBuilder {
 796         final Permissions perms;
 797         public PermissionsBuilder() {
 798             this(new Permissions());
 799         }
 800         public PermissionsBuilder(Permissions perms) {
 801             this.perms = perms;
 802         }
 803         public PermissionsBuilder add(Permission p) {
 804             perms.add(p);
 805             return this;
 806         }
 807         public PermissionsBuilder addAll(PermissionCollection col) {
 808             if (col != null) {
 809                 for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
 810                     perms.add(e.nextElement());
 811                 }
 812             }
 813             return this;
 814         }
 815         public Permissions toPermissions() {
 816             final PermissionsBuilder builder = new PermissionsBuilder();
 817             builder.addAll(perms);
 818             return builder.perms;
 819         }
 820     }
 821 
 822     public static class SimplePolicy extends Policy {
 823         final static RuntimePermission CONTROL = LOGGERFINDER_PERMISSION;
 824         final static RuntimePermission ACCESS_LOGGER = new RuntimePermission("accessClassInPackage.jdk.internal.logger");
 825         final static RuntimePermission ACCESS_LOGGING = new RuntimePermission("accessClassInPackage.sun.util.logging");
 826 
 827         final Permissions permissions;
 828         final Permissions allPermissions;
 829         final ThreadLocal<AtomicBoolean> allowControl;
 830         final ThreadLocal<AtomicBoolean> allowAccess;
 831         final ThreadLocal<AtomicBoolean> allowAll;
 832         public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl,
 833                 ThreadLocal<AtomicBoolean> allowAccess,
 834                 ThreadLocal<AtomicBoolean> allowAll) {
 835             this.allowControl = allowControl;
 836             this.allowAccess = allowAccess;
 837             this.allowAll = allowAll;
 838             permissions = new Permissions();
 839             allPermissions = new PermissionsBuilder()
 840                     .add(new java.security.AllPermission())
 841                     .toPermissions();
 842         }
 843 
 844         Permissions getPermissions() {
 845             if (allowControl.get().get() || allowAccess.get().get() || allowAll.get().get()) {
 846                 PermissionsBuilder builder =  new PermissionsBuilder()
 847                         .addAll(permissions);
 848                 if (allowControl.get().get()) {
 849                     builder.add(CONTROL);
 850                 }
 851                 if (allowAccess.get().get()) {
 852                     builder.add(ACCESS_LOGGER);
 853                     builder.add(ACCESS_LOGGING);
 854                 }
 855                 if (allowAll.get().get()) {
 856                     builder.addAll(allPermissions);
 857                 }
 858                 return builder.toPermissions();
 859             }
 860             return permissions;
 861         }
 862 
 863         @Override
 864         public boolean implies(ProtectionDomain domain, Permission permission) {
 865             return getPermissions().implies(permission);
 866         }
 867 
 868         @Override
 869         public PermissionCollection getPermissions(CodeSource codesource) {
 870             return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
 871         }
 872 
 873         @Override
 874         public PermissionCollection getPermissions(ProtectionDomain domain) {
 875             return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
 876         }
 877     }
 878 }