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