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