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.AccessController;
  24 import java.security.CodeSource;
  25 import java.security.Permission;
  26 import java.security.PermissionCollection;
  27 import java.security.Permissions;
  28 import java.security.Policy;
  29 import java.security.PrivilegedAction;
  30 import java.security.ProtectionDomain;
  31 import java.util.Arrays;
  32 import java.util.Collections;
  33 import java.util.Enumeration;
  34 import java.util.HashMap;
  35 import java.util.Map;
  36 import java.util.Objects;
  37 import java.util.Queue;
  38 import java.util.ResourceBundle;
  39 import java.util.concurrent.ArrayBlockingQueue;
  40 import java.util.concurrent.ConcurrentHashMap;
  41 import java.util.concurrent.atomic.AtomicBoolean;
  42 import java.util.concurrent.atomic.AtomicLong;
  43 import java.util.function.Supplier;
  44 import java.lang.System.LoggerFinder;
  45 import static java.lang.System.LoggerFinder.LOGGERFINDER_PERMISSION;
  46 import java.lang.System.Logger;
  47 import java.lang.System.Logger.Level;
  48 import java.security.AccessControlException;
  49 import java.util.stream.Stream;
  50 import sun.util.logging.PlatformLogger;
  51 
  52 /**
  53  * @test
  54  * @bug     8046565
  55  * @summary JDK implementation specific unit test for JDK internal API.
  56  *   Tests a naive implementation of System.Logger, and in particular
  57  *   the default mapping provided by PlatformLogger.
  58  * @modules java.base/sun.util.logging
  59  * @build CustomSystemClassLoader BasePlatformLoggerTest
  60  * @run  main/othervm -Djava.system.class.loader=CustomSystemClassLoader BasePlatformLoggerTest NOSECURITY
  61  * @run  main/othervm -Djava.system.class.loader=CustomSystemClassLoader BasePlatformLoggerTest NOPERMISSIONS
  62  * @run  main/othervm -Djava.system.class.loader=CustomSystemClassLoader BasePlatformLoggerTest WITHPERMISSIONS
  63  * @author danielfuchs
  64  */
  65 public class BasePlatformLoggerTest {
  66 
  67     final static AtomicLong sequencer = new AtomicLong();
  68     final static boolean VERBOSE = false;
  69     static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() {
  70         @Override
  71         protected AtomicBoolean initialValue() {
  72             return  new AtomicBoolean(false);
  73         }
  74     };
  75     static final ThreadLocal<AtomicBoolean> allowAccess = new ThreadLocal<AtomicBoolean>() {
  76         @Override
  77         protected AtomicBoolean initialValue() {
  78             return  new AtomicBoolean(false);
  79         }
  80     };
  81     static final ThreadLocal<AtomicBoolean> allowAll = new ThreadLocal<AtomicBoolean>() {
  82         @Override
  83         protected AtomicBoolean initialValue() {
  84             return  new AtomicBoolean(false);
  85         }
  86     };
  87 
  88     static final Class<?> providerClass;
  89     static {
  90         try {
  91             providerClass = ClassLoader.getSystemClassLoader().loadClass("BasePlatformLoggerTest$BaseLoggerFinder");
  92         } catch (ClassNotFoundException ex) {
  93             throw new ExceptionInInitializerError(ex);
  94         }
  95     }
  96 
  97     static final PlatformLogger.Level[] julLevels = {
  98         PlatformLogger.Level.ALL,
  99         PlatformLogger.Level.FINEST,
 100         PlatformLogger.Level.FINER,
 101         PlatformLogger.Level.FINE,
 102         PlatformLogger.Level.CONFIG,
 103         PlatformLogger.Level.INFO,
 104         PlatformLogger.Level.WARNING,
 105         PlatformLogger.Level.SEVERE,
 106         PlatformLogger.Level.OFF,
 107     };
 108 
 109     static final Level[] mappedLevels = {
 110         Level.ALL,     // ALL
 111         Level.TRACE,   // FINEST
 112         Level.TRACE,   // FINER
 113         Level.DEBUG,   // FINE
 114         Level.DEBUG,   // CONFIG
 115         Level.INFO,    // INFO
 116         Level.WARNING, // WARNING
 117         Level.ERROR,   // SEVERE
 118         Level.OFF,     // OFF
 119     };
 120 
 121     final static Map<PlatformLogger.Level, Level> julToSpiMap;
 122     static {
 123         Map<PlatformLogger.Level, Level> map = new HashMap<>();
 124         if (mappedLevels.length != julLevels.length) {
 125             throw new ExceptionInInitializerError("Array lengths differ"
 126                 + "\n\tjulLevels=" + Arrays.deepToString(julLevels)
 127                 + "\n\tmappedLevels=" + Arrays.deepToString(mappedLevels));
 128         }
 129         for (int i=0; i<julLevels.length; i++) {
 130             map.put(julLevels[i], mappedLevels[i]);
 131         }
 132         julToSpiMap = Collections.unmodifiableMap(map);
 133     }
 134 
 135     public static class MyBundle extends ResourceBundle {
 136 
 137         final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();
 138 
 139         @Override
 140         protected Object handleGetObject(String key) {
 141             if (key.contains(" (translated)")) {
 142                 throw new RuntimeException("Unexpected key: " + key);
 143             }
 144             return map.computeIfAbsent(key, k -> k + " (translated)");
 145         }
 146 
 147         @Override
 148         public Enumeration<String> getKeys() {
 149             return Collections.enumeration(map.keySet());
 150         }
 151 
 152     }
 153     public static class MyLoggerBundle extends MyBundle {
 154 
 155     }
 156 
 157 
 158     public static interface TestLoggerFinder  {
 159         final ConcurrentHashMap<String, LoggerImpl> system = new ConcurrentHashMap<>();
 160         final ConcurrentHashMap<String, LoggerImpl> user = new ConcurrentHashMap<>();
 161         public Queue<LogEvent> eventQueue = new ArrayBlockingQueue<>(128);
 162 
 163         public static final class LogEvent implements Cloneable {
 164 
 165             public LogEvent() {
 166                 this(sequencer.getAndIncrement());
 167             }
 168 
 169             LogEvent(long sequenceNumber) {
 170                 this.sequenceNumber = sequenceNumber;
 171             }
 172 
 173             long sequenceNumber;
 174             boolean isLoggable;
 175             String loggerName;
 176             Level level;
 177             ResourceBundle bundle;
 178             Throwable thrown;
 179             Object[] args;
 180             Supplier<String> supplier;
 181             String msg;
 182 
 183             Object[] toArray() {
 184                 return new Object[] {
 185                     sequenceNumber,
 186                     isLoggable,
 187                     loggerName,
 188                     level,
 189                     bundle,
 190                     thrown,
 191                     args,
 192                     supplier,
 193                     msg,
 194                 };
 195             }
 196 
 197             @Override
 198             public String toString() {
 199                 return Arrays.deepToString(toArray());
 200             }
 201 
 202 
 203 
 204             @Override
 205             public boolean equals(Object obj) {
 206                 return obj instanceof LogEvent
 207                         && Objects.deepEquals(this.toArray(), ((LogEvent)obj).toArray());
 208             }
 209 
 210             @Override
 211             public int hashCode() {
 212                 return Objects.hash(toArray());
 213             }
 214 
 215             public LogEvent cloneWith(long sequenceNumber)
 216                     throws CloneNotSupportedException {
 217                 LogEvent cloned = (LogEvent)super.clone();
 218                 cloned.sequenceNumber = sequenceNumber;
 219                 return cloned;
 220             }
 221 
 222             public static LogEvent of(boolean isLoggable, String name,
 223                     Level level, ResourceBundle bundle,
 224                     String key, Throwable thrown) {
 225                 LogEvent evt = new LogEvent();
 226                 evt.isLoggable = isLoggable;
 227                 evt.loggerName = name;
 228                 evt.level = level;
 229                 evt.args = null;
 230                 evt.bundle = bundle;
 231                 evt.thrown = thrown;
 232                 evt.supplier = null;
 233                 evt.msg = key;
 234                 return evt;
 235             }
 236 
 237             public static LogEvent of(boolean isLoggable, String name,
 238                     Level level, Throwable thrown, Supplier<String> supplier) {
 239                 LogEvent evt = new LogEvent();
 240                 evt.isLoggable = isLoggable;
 241                 evt.loggerName = name;
 242                 evt.level = level;
 243                 evt.args = null;
 244                 evt.bundle = null;
 245                 evt.thrown = thrown;
 246                 evt.supplier = supplier;
 247                 evt.msg = null;
 248                 return evt;
 249             }
 250 
 251             public static LogEvent of(boolean isLoggable, String name,
 252                     Level level, ResourceBundle bundle,
 253                     String key, Object... params) {
 254                 LogEvent evt = new LogEvent();
 255                 evt.isLoggable = isLoggable;
 256                 evt.loggerName = name;
 257                 evt.level = level;
 258                 evt.args = params;
 259                 evt.bundle = bundle;
 260                 evt.thrown = null;
 261                 evt.supplier = null;
 262                 evt.msg = key;
 263                 return evt;
 264             }
 265 
 266             public static LogEvent of(long sequenceNumber,
 267                     boolean isLoggable, String name,
 268                     Level level, ResourceBundle bundle,
 269                     String key, Supplier<String> supplier,
 270                     Throwable thrown, Object... params) {
 271                 LogEvent evt = new LogEvent(sequenceNumber);
 272                 evt.loggerName = name;
 273                 evt.level = level;
 274                 evt.args = params;
 275                 evt.bundle = bundle;
 276                 evt.thrown = thrown;
 277                 evt.supplier = supplier;
 278                 evt.msg = key;
 279                 evt.isLoggable = isLoggable;
 280                 return evt;
 281             }
 282 
 283         }
 284 
 285         public class LoggerImpl implements Logger {
 286             private final String name;
 287             private Level level = Level.INFO;
 288 
 289             public LoggerImpl(String name) {
 290                 this.name = name;
 291             }
 292 
 293             @Override
 294             public String getName() {
 295                 return name;
 296             }
 297 
 298             @Override
 299             public boolean isLoggable(Level level) {
 300                 return this.level != Level.OFF && this.level.getSeverity() <= level.getSeverity();
 301             }
 302 
 303             @Override
 304             public void log(Level level, ResourceBundle bundle, String key, Throwable thrown) {
 305                 log(LogEvent.of(isLoggable(level), this.name, level, bundle, key, thrown));
 306             }
 307 
 308             @Override
 309             public void log(Level level, ResourceBundle bundle, String format, Object... params) {
 310                 log(LogEvent.of(isLoggable(level), name, level, bundle, format, params));
 311             }
 312 
 313             void log(LogEvent event) {
 314                 eventQueue.add(event);
 315             }
 316 
 317             @Override
 318             public void log(Level level, Supplier<String> msgSupplier) {
 319                 log(LogEvent.of(isLoggable(level), name, level, null, msgSupplier));
 320             }
 321 
 322             @Override
 323             public void log(Level level,  Supplier<String> msgSupplier, Throwable thrown) {
 324                 log(LogEvent.of(isLoggable(level), name, level, thrown, msgSupplier));
 325             }
 326         }
 327 
 328         public Logger getLogger(String name, Class<?> caller);
 329     }
 330 
 331     public static class BaseLoggerFinder extends LoggerFinder implements TestLoggerFinder {
 332         @Override
 333         public Logger getLogger(String name, Class<?> caller) {
 334             SecurityManager sm = System.getSecurityManager();
 335             if (sm != null) {
 336                 sm.checkPermission(LOGGERFINDER_PERMISSION);
 337             }
 338             PrivilegedAction<ClassLoader> pa = () -> caller.getClassLoader();
 339             ClassLoader callerLoader = AccessController.doPrivileged(pa);
 340             if (callerLoader == null) {
 341                 return system.computeIfAbsent(name, (n) -> new LoggerImpl(n));
 342             } else {
 343                 return user.computeIfAbsent(name, (n) -> new LoggerImpl(n));
 344             }
 345         }
 346     }
 347 
 348     static PlatformLogger getPlatformLogger(String name) {
 349         boolean old = allowAccess.get().get();
 350         allowAccess.get().set(true);
 351         try {
 352             return PlatformLogger.getLogger(name);
 353         } finally {
 354             allowAccess.get().set(old);
 355         }
 356     }
 357 
 358     static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS};
 359 
 360     static void setSecurityManager() {
 361         if (System.getSecurityManager() == null) {
 362             Policy.setPolicy(new SimplePolicy(allowControl, allowAccess, allowAll));
 363             System.setSecurityManager(new SecurityManager());
 364         }
 365     }
 366 
 367     public static void main(String[] args) {
 368         if (args.length == 0)
 369             args = new String[] {
 370                 "NOSECURITY",
 371                 "NOPERMISSIONS",
 372                 "WITHPERMISSIONS"
 373             };
 374 
 375 
 376         Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> {
 377             TestLoggerFinder provider;
 378             switch (testCase) {
 379                 case NOSECURITY:
 380                     System.out.println("\n*** Without Security Manager\n");
 381                     provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
 382                     test(provider, true);
 383                     System.out.println("Tetscase count: " + sequencer.get());
 384                     break;
 385                 case NOPERMISSIONS:
 386                     System.out.println("\n*** With Security Manager, without permissions\n");
 387                     setSecurityManager();
 388                     try {
 389                         provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
 390                         throw new RuntimeException("Expected exception not raised");
 391                     } catch (AccessControlException x) {
 392                         if (!LoggerFinder.LOGGERFINDER_PERMISSION.equals(x.getPermission())) {
 393                             throw new RuntimeException("Unexpected permission check", x);
 394                         }
 395                         final boolean control = allowControl.get().get();
 396                         try {
 397                             allowControl.get().set(true);
 398                             provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
 399                         } finally {
 400                             allowControl.get().set(control);
 401                         }
 402                     }
 403                     test(provider, false);
 404                     System.out.println("Tetscase count: " + sequencer.get());
 405                     break;
 406                 case WITHPERMISSIONS:
 407                     System.out.println("\n*** With Security Manager, with control permission\n");
 408                     setSecurityManager();
 409                     final boolean control = allowControl.get().get();
 410                     try {
 411                         allowControl.get().set(true);
 412                         provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
 413                         test(provider, true);
 414                     } finally {
 415                         allowControl.get().set(control);
 416                     }
 417                     break;
 418                 default:
 419                     throw new RuntimeException("Unknown test case: " + testCase);
 420             }
 421         });
 422         System.out.println("\nPASSED: Tested " + sequencer.get() + " cases.");
 423     }
 424 
 425     public static void test(TestLoggerFinder provider, boolean hasRequiredPermissions) {
 426 
 427         final Map<PlatformLogger, String> loggerDescMap = new HashMap<>();
 428 
 429         TestLoggerFinder.LoggerImpl appSink;
 430         boolean before = allowControl.get().get();
 431         try {
 432             allowControl.get().set(true);
 433             appSink = TestLoggerFinder.LoggerImpl.class.cast(
 434                         provider.getLogger("foo", BasePlatformLoggerTest.class));
 435         } finally {
 436             allowControl.get().set(before);
 437         }
 438 
 439         TestLoggerFinder.LoggerImpl sysSink = null;
 440         before = allowControl.get().get();
 441         try {
 442             allowControl.get().set(true);
 443             sysSink = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class));
 444         } finally {
 445             allowControl.get().set(before);
 446         }
 447 
 448         if (hasRequiredPermissions && appSink == sysSink) {
 449             throw new RuntimeException("identical loggers");
 450         }
 451 
 452         if (provider.system.contains(appSink)) {
 453             throw new RuntimeException("app logger in system map");
 454         }
 455         if (!provider.user.contains(appSink)) {
 456             throw new RuntimeException("app logger not in appplication map");
 457         }
 458         if (hasRequiredPermissions && provider.user.contains(sysSink)) {
 459             throw new RuntimeException("sys logger in appplication map");
 460         }
 461         if (hasRequiredPermissions && !provider.system.contains(sysSink)) {
 462             throw new RuntimeException("sys logger not in system map");
 463         }
 464 
 465         PlatformLogger platform = getPlatformLogger("foo");
 466         loggerDescMap.put(platform, "PlatformLogger.getLogger(\"foo\")");
 467 
 468         testLogger(provider, loggerDescMap, "foo", null, platform, sysSink);
 469     }
 470 
 471     public static class Foo {
 472 
 473     }
 474 
 475     static void verbose(String msg) {
 476        if (VERBOSE) {
 477            System.out.println(msg);
 478        }
 479     }
 480 
 481     static void checkLogEvent(TestLoggerFinder provider, String desc,
 482             TestLoggerFinder.LogEvent expected) {
 483         TestLoggerFinder.LogEvent actual =  provider.eventQueue.poll();
 484         if (!expected.equals(actual)) {
 485             throw new RuntimeException("mismatch for " + desc
 486                     + "\n\texpected=" + expected
 487                     + "\n\t  actual=" + actual);
 488         } else {
 489             verbose("Got expected results for "
 490                     + desc + "\n\t" + expected);
 491         }
 492     }
 493 
 494     static void checkLogEvent(TestLoggerFinder provider, String desc,
 495             TestLoggerFinder.LogEvent expected, boolean expectNotNull) {
 496         TestLoggerFinder.LogEvent actual =  provider.eventQueue.poll();
 497         if (actual == null && !expectNotNull) return;
 498         if (actual != null && !expectNotNull) {
 499             throw new RuntimeException("Unexpected log event found for " + desc
 500                 + "\n\tgot: " + actual);
 501         }
 502         if (!expected.equals(actual)) {
 503             throw new RuntimeException("mismatch for " + desc
 504                     + "\n\texpected=" + expected
 505                     + "\n\t  actual=" + actual);
 506         } else {
 507             verbose("Got expected results for "
 508                     + desc + "\n\t" + expected);
 509         }
 510     }
 511 
 512     // Calls the methods defined on LogProducer and verify the
 513     // parameters received by the underlying TestLoggerFinder.LoggerImpl
 514     // logger.
 515     private static void testLogger(TestLoggerFinder provider,
 516             Map<PlatformLogger, String> loggerDescMap,
 517             String name,
 518             ResourceBundle loggerBundle,
 519             PlatformLogger logger,
 520             TestLoggerFinder.LoggerImpl sink) {
 521 
 522         System.out.println("Testing " + loggerDescMap.get(logger));
 523 
 524         Foo foo = new Foo();
 525         String fooMsg = foo.toString();
 526         System.out.println("\tlogger.<level>(fooMsg)");
 527         for (Level loggerLevel : Level.values()) {
 528             sink.level = loggerLevel;
 529             for (PlatformLogger.Level messageLevel :julLevels) {
 530                 Level expectedMessageLevel = julToSpiMap.get(messageLevel);
 531                 TestLoggerFinder.LogEvent expected =
 532                         TestLoggerFinder.LogEvent.of(
 533                             sequencer.get(),
 534                             loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
 535                             name, expectedMessageLevel, loggerBundle,
 536                             fooMsg, null, (Throwable)null, (Object[])null);
 537                 String desc2 = "logger." + messageLevel.toString().toLowerCase()
 538                         + "(fooMsg): loggerLevel="
 539                         + loggerLevel+", messageLevel="+messageLevel;
 540                 if (messageLevel == PlatformLogger.Level.FINEST) {
 541                     logger.finest(fooMsg);
 542                     checkLogEvent(provider, desc2, expected);
 543                 } else if (messageLevel == PlatformLogger.Level.FINER) {
 544                     logger.finer(fooMsg);
 545                     checkLogEvent(provider, desc2, expected);
 546                 } else if (messageLevel == PlatformLogger.Level.FINE) {
 547                     logger.fine(fooMsg);
 548                     checkLogEvent(provider, desc2, expected);
 549                 } else if (messageLevel == PlatformLogger.Level.CONFIG) {
 550                     logger.config(fooMsg);
 551                     checkLogEvent(provider, desc2, expected);
 552                 } else if (messageLevel == PlatformLogger.Level.INFO) {
 553                     logger.info(fooMsg);
 554                     checkLogEvent(provider, desc2, expected);
 555                 } else if (messageLevel == PlatformLogger.Level.WARNING) {
 556                     logger.warning(fooMsg);
 557                     checkLogEvent(provider, desc2, expected);
 558                 } else if (messageLevel == PlatformLogger.Level.SEVERE) {
 559                     logger.severe(fooMsg);
 560                     checkLogEvent(provider, desc2, expected);
 561                 }
 562             }
 563         }
 564 
 565         Throwable thrown = new Exception("OK: log me!");
 566         System.out.println("\tlogger.<level>(msg, thrown)");
 567         for (Level loggerLevel : Level.values()) {
 568             sink.level = loggerLevel;
 569             for (PlatformLogger.Level messageLevel :julLevels) {
 570                 Level expectedMessageLevel = julToSpiMap.get(messageLevel);
 571                 TestLoggerFinder.LogEvent expected =
 572                         TestLoggerFinder.LogEvent.of(
 573                             sequencer.get(),
 574                             loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
 575                             name, expectedMessageLevel, (ResourceBundle) null,
 576                             fooMsg, null, (Throwable)thrown, (Object[])null);
 577                 String desc2 = "logger." + messageLevel.toString().toLowerCase()
 578                         + "(msg, thrown): loggerLevel="
 579                         + loggerLevel+", messageLevel="+messageLevel;
 580                 if (messageLevel == PlatformLogger.Level.FINEST) {
 581                     logger.finest(fooMsg, thrown);
 582                     checkLogEvent(provider, desc2, expected);
 583                 } else if (messageLevel == PlatformLogger.Level.FINER) {
 584                     logger.finer(fooMsg, thrown);
 585                     checkLogEvent(provider, desc2, expected);
 586                 } else if (messageLevel == PlatformLogger.Level.FINE) {
 587                     logger.fine(fooMsg, thrown);
 588                     checkLogEvent(provider, desc2, expected);
 589                 } else if (messageLevel == PlatformLogger.Level.CONFIG) {
 590                     logger.config(fooMsg, thrown);
 591                     checkLogEvent(provider, desc2, expected);
 592                 } else if (messageLevel == PlatformLogger.Level.INFO) {
 593                     logger.info(fooMsg, thrown);
 594                     checkLogEvent(provider, desc2, expected);
 595                 } else if (messageLevel == PlatformLogger.Level.WARNING) {
 596                     logger.warning(fooMsg, thrown);
 597                     checkLogEvent(provider, desc2, expected);
 598                 } else if (messageLevel == PlatformLogger.Level.SEVERE) {
 599                     logger.severe(fooMsg, thrown);
 600                     checkLogEvent(provider, desc2, expected);
 601                 }
 602             }
 603         }
 604 
 605         String format = "two params [{1} {2}]";
 606         Object arg1 = foo;
 607         Object arg2 = fooMsg;
 608         System.out.println("\tlogger.<level>(format, arg1, arg2)");
 609         for (Level loggerLevel : Level.values()) {
 610             sink.level = loggerLevel;
 611             for (PlatformLogger.Level messageLevel :julLevels) {
 612                 Level expectedMessageLevel = julToSpiMap.get(messageLevel);
 613                 TestLoggerFinder.LogEvent expected =
 614                         TestLoggerFinder.LogEvent.of(
 615                             sequencer.get(),
 616                             loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
 617                             name, expectedMessageLevel, (ResourceBundle) null,
 618                             format, null, (Throwable)null, foo, fooMsg);
 619                 String desc2 = "logger." + messageLevel.toString().toLowerCase()
 620                         + "(format, foo, fooMsg): loggerLevel="
 621                         + loggerLevel+", messageLevel="+messageLevel;
 622                 if (messageLevel == PlatformLogger.Level.FINEST) {
 623                     logger.finest(format, foo, fooMsg);
 624                     checkLogEvent(provider, desc2, expected);
 625                 } else if (messageLevel == PlatformLogger.Level.FINER) {
 626                     logger.finer(format, foo, fooMsg);
 627                     checkLogEvent(provider, desc2, expected);
 628                 } else if (messageLevel == PlatformLogger.Level.FINE) {
 629                     logger.fine(format, foo, fooMsg);
 630                     checkLogEvent(provider, desc2, expected);
 631                 } else if (messageLevel == PlatformLogger.Level.CONFIG) {
 632                     logger.config(format, foo, fooMsg);
 633                     checkLogEvent(provider, desc2, expected);
 634                 } else if (messageLevel == PlatformLogger.Level.INFO) {
 635                     logger.info(format, foo, fooMsg);
 636                     checkLogEvent(provider, desc2, expected);
 637                 } else if (messageLevel == PlatformLogger.Level.WARNING) {
 638                     logger.warning(format, foo, fooMsg);
 639                     checkLogEvent(provider, desc2, expected);
 640                 } else if (messageLevel == PlatformLogger.Level.SEVERE) {
 641                     logger.severe(format, foo, fooMsg);
 642                     checkLogEvent(provider, desc2, expected);
 643                 }
 644             }
 645         }
 646 
 647     }
 648 
 649     final static class PermissionsBuilder {
 650         final Permissions perms;
 651         public PermissionsBuilder() {
 652             this(new Permissions());
 653         }
 654         public PermissionsBuilder(Permissions perms) {
 655             this.perms = perms;
 656         }
 657         public PermissionsBuilder add(Permission p) {
 658             perms.add(p);
 659             return this;
 660         }
 661         public PermissionsBuilder addAll(PermissionCollection col) {
 662             if (col != null) {
 663                 for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
 664                     perms.add(e.nextElement());
 665                 }
 666             }
 667             return this;
 668         }
 669         public Permissions toPermissions() {
 670             final PermissionsBuilder builder = new PermissionsBuilder();
 671             builder.addAll(perms);
 672             return builder.perms;
 673         }
 674     }
 675 
 676     public static class SimplePolicy extends Policy {
 677         final static RuntimePermission CONTROL = LoggerFinder.LOGGERFINDER_PERMISSION;
 678         final static RuntimePermission ACCESS_LOGGING = new RuntimePermission("accessClassInPackage.sun.util.logging");
 679 
 680         final Permissions permissions;
 681         final Permissions allPermissions;
 682         final ThreadLocal<AtomicBoolean> allowControl;
 683         final ThreadLocal<AtomicBoolean> allowAccess;
 684         final ThreadLocal<AtomicBoolean> allowAll;
 685         public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl,
 686                 ThreadLocal<AtomicBoolean> allowAccess,
 687                 ThreadLocal<AtomicBoolean> allowAll) {
 688             this.allowControl = allowControl;
 689             this.allowAccess = allowAccess;
 690             this.allowAll = allowAll;
 691             permissions = new Permissions();
 692             allPermissions = new PermissionsBuilder()
 693                     .add(new java.security.AllPermission())
 694                     .toPermissions();
 695         }
 696 
 697         Permissions getPermissions() {
 698             if (allowControl.get().get() || allowAccess.get().get() || allowAll.get().get()) {
 699                 PermissionsBuilder builder =  new PermissionsBuilder()
 700                         .addAll(permissions);
 701                 if (allowControl.get().get()) {
 702                     builder.add(CONTROL);
 703                 }
 704                 if (allowAccess.get().get()) {
 705                     builder.add(ACCESS_LOGGING);
 706                 }
 707                 if (allowAll.get().get()) {
 708                     builder.addAll(allPermissions);
 709                 }
 710                 return builder.toPermissions();
 711             }
 712             return permissions;
 713         }
 714 
 715         @Override
 716         public boolean implies(ProtectionDomain domain, Permission permission) {
 717             return getPermissions().implies(permission);
 718         }
 719 
 720         @Override
 721         public PermissionCollection getPermissions(CodeSource codesource) {
 722             return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
 723         }
 724 
 725         @Override
 726         public PermissionCollection getPermissions(ProtectionDomain domain) {
 727             return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
 728         }
 729     }
 730 }