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