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, Module caller);
 331     }
 332 
 333     public static class BaseLoggerFinder extends LoggerFinder implements TestLoggerFinder {
 334         @Override
 335         public Logger getLogger(String name, Module 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.getModule()));
 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(
 446                         provider.getLogger("foo", Thread.class.getModule()));
 447         } finally {
 448             allowControl.get().set(before);
 449         }
 450 
 451         if (hasRequiredPermissions && appSink == sysSink) {
 452             throw new RuntimeException("identical loggers");
 453         }
 454 
 455         if (provider.system.contains(appSink)) {
 456             throw new RuntimeException("app logger in system map");
 457         }
 458         if (!provider.user.contains(appSink)) {
 459             throw new RuntimeException("app logger not in appplication map");
 460         }
 461         if (hasRequiredPermissions && provider.user.contains(sysSink)) {
 462             throw new RuntimeException("sys logger in appplication map");
 463         }
 464         if (hasRequiredPermissions && !provider.system.contains(sysSink)) {
 465             throw new RuntimeException("sys logger not in system map");
 466         }
 467 
 468         PlatformLogger platform = getPlatformLogger("foo");
 469         loggerDescMap.put(platform, "PlatformLogger.getLogger(\"foo\")");
 470 
 471         testLogger(provider, loggerDescMap, "foo", null, platform, sysSink);
 472     }
 473 
 474     public static class Foo {
 475 
 476     }
 477 
 478     static void verbose(String msg) {
 479        if (VERBOSE) {
 480            System.out.println(msg);
 481        }
 482     }
 483 
 484     static void checkLogEvent(TestLoggerFinder provider, String desc,
 485             TestLoggerFinder.LogEvent expected) {
 486         TestLoggerFinder.LogEvent actual =  provider.eventQueue.poll();
 487         if (!expected.equals(actual)) {
 488             throw new RuntimeException("mismatch for " + desc
 489                     + "\n\texpected=" + expected
 490                     + "\n\t  actual=" + actual);
 491         } else {
 492             verbose("Got expected results for "
 493                     + desc + "\n\t" + expected);
 494         }
 495     }
 496 
 497     static void checkLogEvent(TestLoggerFinder provider, String desc,
 498             TestLoggerFinder.LogEvent expected, boolean expectNotNull) {
 499         TestLoggerFinder.LogEvent actual =  provider.eventQueue.poll();
 500         if (actual == null && !expectNotNull) return;
 501         if (actual != null && !expectNotNull) {
 502             throw new RuntimeException("Unexpected log event found for " + desc
 503                 + "\n\tgot: " + actual);
 504         }
 505         if (!expected.equals(actual)) {
 506             throw new RuntimeException("mismatch for " + desc
 507                     + "\n\texpected=" + expected
 508                     + "\n\t  actual=" + actual);
 509         } else {
 510             verbose("Got expected results for "
 511                     + desc + "\n\t" + expected);
 512         }
 513     }
 514 
 515     // Calls the methods defined on LogProducer and verify the
 516     // parameters received by the underlying TestLoggerFinder.LoggerImpl
 517     // logger.
 518     private static void testLogger(TestLoggerFinder provider,
 519             Map<PlatformLogger, String> loggerDescMap,
 520             String name,
 521             ResourceBundle loggerBundle,
 522             PlatformLogger logger,
 523             TestLoggerFinder.LoggerImpl sink) {
 524 
 525         System.out.println("Testing " + loggerDescMap.get(logger));
 526 
 527         Foo foo = new Foo();
 528         String fooMsg = foo.toString();
 529         System.out.println("\tlogger.<level>(fooMsg)");
 530         for (Level loggerLevel : Level.values()) {
 531             sink.level = loggerLevel;
 532             for (PlatformLogger.Level messageLevel :julLevels) {
 533                 Level expectedMessageLevel = julToSpiMap.get(messageLevel);
 534                 TestLoggerFinder.LogEvent expected =
 535                         TestLoggerFinder.LogEvent.of(
 536                             sequencer.get(),
 537                             loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
 538                             name, expectedMessageLevel, loggerBundle,
 539                             fooMsg, null, (Throwable)null, (Object[])null);
 540                 String desc2 = "logger." + messageLevel.toString().toLowerCase()
 541                         + "(fooMsg): loggerLevel="
 542                         + loggerLevel+", messageLevel="+messageLevel;
 543                 if (messageLevel == PlatformLogger.Level.FINEST) {
 544                     logger.finest(fooMsg);
 545                     checkLogEvent(provider, desc2, expected);
 546                 } else if (messageLevel == PlatformLogger.Level.FINER) {
 547                     logger.finer(fooMsg);
 548                     checkLogEvent(provider, desc2, expected);
 549                 } else if (messageLevel == PlatformLogger.Level.FINE) {
 550                     logger.fine(fooMsg);
 551                     checkLogEvent(provider, desc2, expected);
 552                 } else if (messageLevel == PlatformLogger.Level.CONFIG) {
 553                     logger.config(fooMsg);
 554                     checkLogEvent(provider, desc2, expected);
 555                 } else if (messageLevel == PlatformLogger.Level.INFO) {
 556                     logger.info(fooMsg);
 557                     checkLogEvent(provider, desc2, expected);
 558                 } else if (messageLevel == PlatformLogger.Level.WARNING) {
 559                     logger.warning(fooMsg);
 560                     checkLogEvent(provider, desc2, expected);
 561                 } else if (messageLevel == PlatformLogger.Level.SEVERE) {
 562                     logger.severe(fooMsg);
 563                     checkLogEvent(provider, desc2, expected);
 564                 }
 565             }
 566         }
 567 
 568         Throwable thrown = new Exception("OK: log me!");
 569         System.out.println("\tlogger.<level>(msg, thrown)");
 570         for (Level loggerLevel : Level.values()) {
 571             sink.level = loggerLevel;
 572             for (PlatformLogger.Level messageLevel :julLevels) {
 573                 Level expectedMessageLevel = julToSpiMap.get(messageLevel);
 574                 TestLoggerFinder.LogEvent expected =
 575                         TestLoggerFinder.LogEvent.of(
 576                             sequencer.get(),
 577                             loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
 578                             name, expectedMessageLevel, (ResourceBundle) null,
 579                             fooMsg, null, (Throwable)thrown, (Object[])null);
 580                 String desc2 = "logger." + messageLevel.toString().toLowerCase()
 581                         + "(msg, thrown): loggerLevel="
 582                         + loggerLevel+", messageLevel="+messageLevel;
 583                 if (messageLevel == PlatformLogger.Level.FINEST) {
 584                     logger.finest(fooMsg, thrown);
 585                     checkLogEvent(provider, desc2, expected);
 586                 } else if (messageLevel == PlatformLogger.Level.FINER) {
 587                     logger.finer(fooMsg, thrown);
 588                     checkLogEvent(provider, desc2, expected);
 589                 } else if (messageLevel == PlatformLogger.Level.FINE) {
 590                     logger.fine(fooMsg, thrown);
 591                     checkLogEvent(provider, desc2, expected);
 592                 } else if (messageLevel == PlatformLogger.Level.CONFIG) {
 593                     logger.config(fooMsg, thrown);
 594                     checkLogEvent(provider, desc2, expected);
 595                 } else if (messageLevel == PlatformLogger.Level.INFO) {
 596                     logger.info(fooMsg, thrown);
 597                     checkLogEvent(provider, desc2, expected);
 598                 } else if (messageLevel == PlatformLogger.Level.WARNING) {
 599                     logger.warning(fooMsg, thrown);
 600                     checkLogEvent(provider, desc2, expected);
 601                 } else if (messageLevel == PlatformLogger.Level.SEVERE) {
 602                     logger.severe(fooMsg, thrown);
 603                     checkLogEvent(provider, desc2, expected);
 604                 }
 605             }
 606         }
 607 
 608         String format = "two params [{1} {2}]";
 609         Object arg1 = foo;
 610         Object arg2 = fooMsg;
 611         System.out.println("\tlogger.<level>(format, arg1, arg2)");
 612         for (Level loggerLevel : Level.values()) {
 613             sink.level = loggerLevel;
 614             for (PlatformLogger.Level messageLevel :julLevels) {
 615                 Level expectedMessageLevel = julToSpiMap.get(messageLevel);
 616                 TestLoggerFinder.LogEvent expected =
 617                         TestLoggerFinder.LogEvent.of(
 618                             sequencer.get(),
 619                             loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
 620                             name, expectedMessageLevel, (ResourceBundle) null,
 621                             format, null, (Throwable)null, foo, fooMsg);
 622                 String desc2 = "logger." + messageLevel.toString().toLowerCase()
 623                         + "(format, foo, fooMsg): loggerLevel="
 624                         + loggerLevel+", messageLevel="+messageLevel;
 625                 if (messageLevel == PlatformLogger.Level.FINEST) {
 626                     logger.finest(format, foo, fooMsg);
 627                     checkLogEvent(provider, desc2, expected);
 628                 } else if (messageLevel == PlatformLogger.Level.FINER) {
 629                     logger.finer(format, foo, fooMsg);
 630                     checkLogEvent(provider, desc2, expected);
 631                 } else if (messageLevel == PlatformLogger.Level.FINE) {
 632                     logger.fine(format, foo, fooMsg);
 633                     checkLogEvent(provider, desc2, expected);
 634                 } else if (messageLevel == PlatformLogger.Level.CONFIG) {
 635                     logger.config(format, foo, fooMsg);
 636                     checkLogEvent(provider, desc2, expected);
 637                 } else if (messageLevel == PlatformLogger.Level.INFO) {
 638                     logger.info(format, foo, fooMsg);
 639                     checkLogEvent(provider, desc2, expected);
 640                 } else if (messageLevel == PlatformLogger.Level.WARNING) {
 641                     logger.warning(format, foo, fooMsg);
 642                     checkLogEvent(provider, desc2, expected);
 643                 } else if (messageLevel == PlatformLogger.Level.SEVERE) {
 644                     logger.severe(format, foo, fooMsg);
 645                     checkLogEvent(provider, desc2, expected);
 646                 }
 647             }
 648         }
 649 
 650     }
 651 
 652     final static class PermissionsBuilder {
 653         final Permissions perms;
 654         public PermissionsBuilder() {
 655             this(new Permissions());
 656         }
 657         public PermissionsBuilder(Permissions perms) {
 658             this.perms = perms;
 659         }
 660         public PermissionsBuilder add(Permission p) {
 661             perms.add(p);
 662             return this;
 663         }
 664         public PermissionsBuilder addAll(PermissionCollection col) {
 665             if (col != null) {
 666                 for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
 667                     perms.add(e.nextElement());
 668                 }
 669             }
 670             return this;
 671         }
 672         public Permissions toPermissions() {
 673             final PermissionsBuilder builder = new PermissionsBuilder();
 674             builder.addAll(perms);
 675             return builder.perms;
 676         }
 677     }
 678 
 679     public static class SimplePolicy extends Policy {
 680         final static RuntimePermission CONTROL = LOGGERFINDER_PERMISSION;
 681         final static RuntimePermission ACCESS_LOGGING = new RuntimePermission("accessClassInPackage.sun.util.logging");
 682 
 683         final Permissions permissions;
 684         final Permissions allPermissions;
 685         final ThreadLocal<AtomicBoolean> allowControl;
 686         final ThreadLocal<AtomicBoolean> allowAccess;
 687         final ThreadLocal<AtomicBoolean> allowAll;
 688         public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl,
 689                 ThreadLocal<AtomicBoolean> allowAccess,
 690                 ThreadLocal<AtomicBoolean> allowAll) {
 691             this.allowControl = allowControl;
 692             this.allowAccess = allowAccess;
 693             this.allowAll = allowAll;
 694             permissions = new Permissions();
 695             allPermissions = new PermissionsBuilder()
 696                     .add(new java.security.AllPermission())
 697                     .toPermissions();
 698         }
 699 
 700         Permissions getPermissions() {
 701             if (allowControl.get().get() || allowAccess.get().get() || allowAll.get().get()) {
 702                 PermissionsBuilder builder =  new PermissionsBuilder()
 703                         .addAll(permissions);
 704                 if (allowControl.get().get()) {
 705                     builder.add(CONTROL);
 706                 }
 707                 if (allowAccess.get().get()) {
 708                     builder.add(ACCESS_LOGGING);
 709                 }
 710                 if (allowAll.get().get()) {
 711                     builder.addAll(allPermissions);
 712                 }
 713                 return builder.toPermissions();
 714             }
 715             return permissions;
 716         }
 717 
 718         @Override
 719         public boolean implies(ProtectionDomain domain, Permission permission) {
 720             return getPermissions().implies(permission);
 721         }
 722 
 723         @Override
 724         public PermissionCollection getPermissions(CodeSource codesource) {
 725             return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
 726         }
 727 
 728         @Override
 729         public PermissionCollection getPermissions(ProtectionDomain domain) {
 730             return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
 731         }
 732     }
 733 }