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