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