1 /*
   2  * Copyright (c) 2014, 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 
  24 /**
  25  * @test
  26  * @bug     8046565
  27  * @author  danielfuchs
  28  * @summary  JDK implementation specific unit test for JDK internal artifacts.
  29  *           This test tests all the public API methods defined in the {@link
  30  *           java.lang.System.Logger} interface, as well as all the JDK
  31  *           internal methods defined in the
  32  *           {@link sun.util.logging.PlatformLoggerBridge}
  33  *           interface, with loggers returned by  {@link
  34  *           java.lang.System.LoggerFinder#getLogger(java.lang.String, java.lang.Class)}
  35  *           and {@link java.lang.System.LoggerFinder#getLocalizedLogger(java.lang.String,
  36  *           java.util.ResourceBundle, java.lang.Class)}
  37  *           (using both a null resource bundle and a non null resource bundle).
  38  *           It calls both the {@link java.lang.System} factory methods and
  39  *           {@link sun.util.logger.LazyLoggers} to obtains those loggers,
  40  *           and configure them with all possible known levels.
  41  * @modules java.base/sun.util.logging
  42  *          java.base/sun.util.logger
  43  * @build LoggerFinderBackendTest SystemClassLoader
  44  * @run  main/othervm -Djava.system.class.loader=SystemClassLoader -Dtest.logger.hidesProvider=true LoggerFinderBackendTest
  45  * @run  main/othervm -Djava.system.class.loader=SystemClassLoader -Dtest.logger.hidesProvider=false LoggerFinderBackendTest
  46  */
  47 
  48 
  49 import java.lang.invoke.MethodHandle;
  50 import java.lang.invoke.MethodHandles;
  51 import java.lang.invoke.MethodHandles.Lookup;
  52 import java.lang.invoke.MethodType;
  53 import java.lang.reflect.InvocationTargetException;
  54 import java.lang.reflect.Method;
  55 import java.util.ArrayList;
  56 import java.util.Arrays;
  57 import java.util.Collections;
  58 import java.util.Enumeration;
  59 import java.util.HashMap;
  60 import java.util.LinkedHashMap;
  61 import java.util.LinkedHashSet;
  62 import java.util.List;
  63 import java.util.Map;
  64 import java.util.Objects;
  65 import java.util.ResourceBundle;
  66 import java.util.concurrent.atomic.AtomicInteger;
  67 import java.util.function.BiFunction;
  68 import java.util.function.BooleanSupplier;
  69 import java.util.function.Function;
  70 import java.util.function.Supplier;
  71 import java.lang.System.LoggerFinder;
  72 import java.util.logging.ConsoleHandler;
  73 import java.util.logging.Handler;
  74 import sun.util.logging.PlatformLogger.Level;
  75 import java.util.logging.LogManager;
  76 import java.util.logging.LogRecord;
  77 import java.util.logging.Logger;
  78 
  79 /**
  80  * @author danielfuchs
  81  */
  82 public class LoggerFinderBackendTest {
  83 
  84     // whether the implementation of Logger try to do a best
  85     // effort for logp... If the provider is not hidden, then
  86     // the logp() implementation comes from LoggerWrapper - which does a
  87     // best effort. Otherwise, it comes from the default provider
  88     // which does support logp.
  89     static final boolean BEST_EFFORT_FOR_LOGP =
  90             !Boolean.getBoolean("test.logger.hidesProvider");
  91     static final boolean VERBOSE = false;
  92 
  93     static final Class<java.lang.System.Logger> spiLoggerClass =
  94             java.lang.System.Logger.class;
  95     static final Class<java.lang.System.Logger> jdkLoggerClass =
  96             java.lang.System.Logger.class;
  97     static final Class<sun.util.logging.PlatformLoggerBridge> bridgeLoggerClass =
  98             sun.util.logging.PlatformLoggerBridge.class;
  99 
 100     /** Use to retrieve the log records that were produced by the JUL backend */
 101     static class LoggerTesterHandler extends Handler {
 102         public final List<LogRecord> records =
 103                 Collections.synchronizedList(new ArrayList<>());
 104 
 105         @Override
 106         public void publish(LogRecord record) {
 107             record.getSourceClassName(); record.getSourceMethodName();
 108             records.add(record);
 109         }
 110 
 111         @Override
 112         public void flush() {
 113         }
 114 
 115         @Override
 116         public void close() throws SecurityException {
 117             records.clear();
 118         }
 119 
 120         public void reset() {
 121             records.clear();
 122         }
 123     }
 124 
 125     /** The {@link LoggerTesterHandler} handler is added to the root logger. */
 126     static final LoggerTesterHandler handler = new LoggerTesterHandler();
 127     static {
 128         for (Handler h : Logger.getLogger("").getHandlers()) {
 129             if (h instanceof ConsoleHandler) {
 130                 Logger.getLogger("").removeHandler(h);
 131             }
 132         }
 133         Logger.getLogger("").addHandler(handler);
 134     }
 135 
 136     /**
 137      * A resource handler parameter that will be used when calling out the
 138      * logrb-like methods - as well as when calling the level-specific
 139      * methods that take a ResourceBundle parameter.
 140      */
 141     public static class ResourceBundeParam extends ResourceBundle {
 142         Map<String, String> map = Collections.synchronizedMap(new LinkedHashMap<>());
 143         @Override
 144         protected Object handleGetObject(String key) {
 145             map.putIfAbsent(key, "${"+key+"}");
 146             return map.get(key);
 147         }
 148 
 149         @Override
 150         public Enumeration<String> getKeys() {
 151             return Collections.enumeration(new LinkedHashSet<>(map.keySet()));
 152         }
 153 
 154     }
 155 
 156     final static ResourceBundle bundleParam =
 157             ResourceBundle.getBundle(ResourceBundeParam.class.getName());
 158 
 159     /**
 160      * A resource handler parameter that will be used when creating localized
 161      * loggers by calling {@link
 162      * LoggerFinder#getLocalizedLogger(java.lang.String, java.util.ResourceBundle, java.lang.Class)}.
 163      */
 164     public static class ResourceBundeLocalized extends ResourceBundle {
 165         Map<String, String> map = Collections.synchronizedMap(new LinkedHashMap<>());
 166         @Override
 167         protected Object handleGetObject(String key) {
 168             map.putIfAbsent(key, "Localized:${"+key+"}");
 169             return map.get(key);
 170         }
 171 
 172         @Override
 173         public Enumeration<String> getKeys() {
 174             return Collections.enumeration(new LinkedHashSet<>(map.keySet()));
 175         }
 176 
 177     }
 178 
 179     /**
 180      * The Levels enum is used to call all the level-specific methods on
 181      * a logger instance. To minimize the amount of code it uses reflection
 182      * to do so.
 183      */
 184     static Lookup lookup = MethodHandles.lookup();
 185     public enum Levels {
 186         /** Used to call all forms of Logger.log?(SEVERE, ...) */
 187         SEVERE("severe", bridgeLoggerClass, Level.SEVERE, null, "error", false),
 188         /** Used to call all forms of Logger.log?(WARNING,...) */
 189         WARNING("warning", bridgeLoggerClass, Level.WARNING, "warning", "warning", false),
 190         /** Used to call all forms of Logger.log?(INFO,...) */
 191         INFO("info", bridgeLoggerClass, Level.INFO, "info", "info", false),
 192         /** Used to call all forms of Logger.log?(CONFIG,...) */
 193         CONFIG("config", bridgeLoggerClass, Level.CONFIG, null, "debug", false),
 194         /** Used to call all forms of Logger.log?(FINE,...) */
 195         FINE("fine", bridgeLoggerClass, Level.FINE, null, "debug", false),
 196         /** Used to call all forms of Logger.log?(FINER,...) */
 197         FINER("finer", bridgeLoggerClass, Level.FINER, null, "trace", false),
 198         /** Used to call all forms of Logger.log?(FINEST,...) */
 199         FINEST("finest", bridgeLoggerClass, Level.FINEST, null, "trace", false),
 200         ;
 201         public final String method;  // The name of the level-specific method to call
 202         public final Class<?> definingClass; // which interface j.u.logger.Logger or j.u.logging.spi.Logger defines it
 203         public final Level platformLevel; // The platform Level it will be mapped to in Jul when Jul is the backend
 204         public final String jdkExtensionToJUL; // The name of the method called on the JUL logger when JUL is the backend
 205         public final String julToJdkExtension; // The name of the method called in the jdk extension by the default impl in jdk.internal.logging.Logger
 206         public final String enableMethod; // The name of the isXxxxEnabled method
 207         public final boolean hasSpecificIsEnabled;
 208         Levels(String method, Class<?> definingClass, Level defaultMapping,
 209                 String jdkExtensionToJUL, String julToJdkExtension,
 210                 boolean hasSpecificIsEnabled) {
 211             this.method = method;
 212             this.definingClass = definingClass;
 213             this.platformLevel = defaultMapping;
 214             this.jdkExtensionToJUL = jdkExtensionToJUL;
 215             this.julToJdkExtension = julToJdkExtension;
 216             this.hasSpecificIsEnabled = hasSpecificIsEnabled;
 217             if (hasSpecificIsEnabled) {
 218                 this.enableMethod = "is" + method.substring(0,1).toUpperCase()
 219                     + method.substring(1) + "Enabled";
 220             } else {
 221                 this.enableMethod = "isLoggable";
 222             }
 223         }
 224 
 225         /*
 226          * calls this level specific method - e.g. if this==INFO: logger.info(msg);
 227          */
 228         public void level(Object logger, String msg) {
 229             MethodType mt = MethodType.methodType(void.class, Level.class, String.class);
 230             invoke("log", logger, mt, platformLevel, msg);
 231         }
 232 
 233         /*
 234          * calls this level specific method - e.g. if this==INFO: logger.info(msgSupplier);
 235          */
 236         public void level(Object logger, Supplier<String> msgSupplier) {
 237             MethodType mt = MethodType.methodType(void.class,  Level.class, Supplier.class);
 238             invoke("log", logger, mt, platformLevel, msgSupplier);
 239         }
 240 
 241         /*
 242          * calls this level specific method - e.g. if this==INFO: logger.info(msg, params);
 243          */
 244         public void level(Object logger, String msg, Object... params) {
 245             MethodType mt = MethodType.methodType(void.class,  Level.class, String.class,
 246                     Object[].class);
 247             invoke("log", logger, mt, platformLevel, msg, params);
 248         }
 249 
 250         /*
 251          * calls this level specific method - e.g. if this==INFO: logger.info(msg, thrown);
 252          */
 253         public void level(Object logger, String msg, Throwable thrown) {
 254             MethodType mt = MethodType.methodType(void.class,  Level.class, String.class,
 255                     Throwable.class);
 256             invoke("log", logger, mt, platformLevel, msg, thrown);
 257         }
 258 
 259         /*
 260          * calls this level specific method - e.g. if this==INFO: logger.info(msgSupplier, thrown);
 261          */
 262         public void level(Object logger, Supplier<String> msgSupplier, Throwable thrown) {
 263             MethodType mt = MethodType.methodType(void.class,  Level.class,
 264                      Throwable.class, Supplier.class);
 265             invoke("log", logger, mt, platformLevel, thrown, msgSupplier);
 266         }
 267 
 268         /*
 269          * calls this level specific method - e.g. if this==INFO: logger.info(bundle, msg);
 270          */
 271         public void level(Object logger, String msg, ResourceBundle bundle) {
 272             MethodType mt = MethodType.methodType(void.class, Level.class,
 273                     ResourceBundle.class, String.class, Object[].class);
 274             invoke("logrb", logger, mt, platformLevel, bundle, msg, null);
 275         }
 276 
 277         public void level(Object logger, String msg, ResourceBundle bundle,
 278                 Object... params) {
 279             MethodType mt = MethodType.methodType(void.class, Level.class,
 280                     ResourceBundle.class, String.class, Object[].class);
 281             invoke("logrb", logger, mt, platformLevel, bundle, msg, params);
 282         }
 283 
 284         public void level(Object logger, String msg, ResourceBundle bundle,
 285                 Throwable thrown) {
 286             MethodType mt = MethodType.methodType(void.class, Level.class,
 287                     ResourceBundle.class, String.class, Throwable.class);
 288             invoke("logrb", logger, mt, platformLevel, bundle, msg, thrown);
 289         }
 290 
 291         public boolean isEnabled(Object logger) {
 292             try {
 293                 if (hasSpecificIsEnabled) {
 294                     MethodType mt = MethodType.methodType(boolean.class);
 295                     final MethodHandle handle = lookup.findVirtual(definingClass,
 296                         enableMethod, mt).bindTo(logger);
 297                     return Boolean.class.cast(handle.invoke());
 298                 } else {
 299                     MethodType mt = MethodType.methodType(boolean.class,
 300                         Level.class);
 301                     final MethodHandle handle = lookup.findVirtual(definingClass,
 302                         enableMethod, mt).bindTo(logger);
 303                     return Boolean.class.cast(handle.invoke(platformLevel));
 304                 }
 305             } catch (Throwable ex) {
 306                 throw new RuntimeException(ex);
 307             }
 308         }
 309 
 310         private void invoke(String method, Object logger, MethodType mt, Object... args) {
 311             try {
 312                 final int last = mt.parameterCount()-1;
 313                 boolean isVarargs = mt.parameterType(last).isArray();
 314                 final MethodHandle handle = lookup.findVirtual(definingClass,
 315                         method, mt).bindTo(logger);
 316 
 317                 final StringBuilder builder = new StringBuilder();
 318                 builder.append(logger.getClass().getSimpleName()).append('.')
 319                         .append(method).append('(');
 320                 String sep = "";
 321                 int offset = 0;
 322                 Object[] params = args;
 323                 for (int i=0; (i-offset) < params.length; i++) {
 324                     if (isVarargs && i == last) {
 325                         offset = last;
 326                         params = (Object[])args[i];
 327                         if (params == null) break;
 328                     }
 329                     Object p = params[i - offset];
 330                     String quote = (p instanceof String) ? "\"" : "";
 331                     builder.append(sep).append(quote).append(p).append(quote);
 332                     sep = ", ";
 333                 }
 334                 builder.append(')');
 335                 if (verbose) {
 336                     System.out.println(builder);
 337                 }
 338                 handle.invokeWithArguments(args);
 339             } catch (Throwable ex) {
 340                 throw new RuntimeException(ex);
 341             }
 342         }
 343 
 344     };
 345 
 346     static interface Checker<LogResult, L> extends BiFunction<LogResult, L, Void> {}
 347     static interface JdkLogTester
 348             extends BiFunction<sun.util.logging.PlatformLoggerBridge, Level, Void> {}
 349     static interface SpiLogTester
 350             extends BiFunction<java.lang.System.Logger, java.lang.System.Logger.Level, Void> {}
 351 
 352     static interface MethodInvoker<LOGGER, LEVEL> {
 353         public void logX(LOGGER logger, LEVEL level, Object... args);
 354     }
 355 
 356     public enum JdkLogMethodInvoker
 357            implements MethodInvoker<sun.util.logging.PlatformLoggerBridge, Level> {
 358         /**
 359          * Tests {@link
 360          * jdk.internal.logging.Logger#log(Level, String, Object...)};
 361          **/
 362         LOG_STRING_PARAMS("log", MethodType.methodType(void.class,
 363                 Level.class, String.class, Object[].class)),
 364         /**
 365          * Tests {@link
 366          * jdk.internal.logging.Logger#log(Level, String, Throwable)};
 367          **/
 368         LOG_STRING_THROWN("log", MethodType.methodType(void.class,
 369                 Level.class, String.class, Throwable.class)),
 370         /**
 371          * Tests {@link
 372          * jdk.internal.logging.Logger#log(Level, Supplier<String>)};
 373          **/
 374         LOG_SUPPLIER("log", MethodType.methodType(void.class,
 375                 Level.class, Supplier.class)),
 376         /**
 377          * Tests {@link
 378          * jdk.internal.logging.Logger#log(Level, Throwable, Supplier<String>)};
 379          **/
 380         LOG_SUPPLIER_THROWN("log", MethodType.methodType(void.class,
 381                 Level.class, Throwable.class, Supplier.class)),
 382         /**
 383          * Tests {@link
 384          * jdk.internal.logging.Logger#logp(Level, String, String, String)};
 385          **/
 386         LOGP_STRING("logp", MethodType.methodType(void.class,
 387                 Level.class, String.class, String.class, String.class)),
 388         /**
 389          * Tests {@link
 390          * jdk.internal.logging.Logger#logp(Level, String, String, String, Object...)};
 391          **/
 392         LOGP_STRING_PARAMS("logp", MethodType.methodType(void.class,
 393                 Level.class, String.class, String.class, String.class, Object[].class)),
 394         /**
 395          * Tests {@link
 396          * jdk.internal.logging.Logger#logp(Level, String, String, String, Throwable)};
 397          **/
 398         LOGP_STRING_THROWN("logp", MethodType.methodType(void.class,
 399                 Level.class, String.class, String.class, String.class, Throwable.class)),
 400         /**
 401          * Tests {@link
 402          * jdk.internal.logging.Logger#logp(Level, String, String, Supplier<String>)};
 403          **/
 404         LOGP_SUPPLIER("logp", MethodType.methodType(void.class,
 405                 Level.class, String.class, String.class, Supplier.class)),
 406         /**
 407          * Tests {@link
 408          * jdk.internal.logging.Logger#logp(Level, String, String, Throwable, Supplier<String>)};
 409          **/
 410         LOGP_SUPPLIER_THROWN("logp", MethodType.methodType(void.class,
 411                 Level.class, String.class, String.class,
 412                 Throwable.class, Supplier.class)),
 413         /**
 414          * Tests {@link
 415          * jdk.internal.logging.Logger#logrb(Level, ResourceBundle, String, Object...)};
 416          **/
 417         LOGRB_STRING_PARAMS("logrb", MethodType.methodType(void.class,
 418                 Level.class, ResourceBundle.class, String.class, Object[].class)),
 419         /**
 420          * Tests {@link
 421          * jdk.internal.logging.Logger#logrb(Level, ResourceBundle, String, Throwable)};
 422          **/
 423         LOGRB_STRING_THROWN("logrb", MethodType.methodType(void.class,
 424                 Level.class, ResourceBundle.class, String.class, Throwable.class)),
 425         /**
 426          * Tests {@link
 427          * jdk.internal.logging.Logger#logrb(Level, String, String, ResourceBundle, String, Object...)};
 428          **/
 429         LOGRBP_STRING_PARAMS("logrb", MethodType.methodType(void.class,
 430                 Level.class, String.class, String.class, ResourceBundle.class,
 431                 String.class, Object[].class)),
 432         /**
 433          * Tests {@link
 434          * jdk.internal.logging.Logger#logrb(Level, String, String, ResourceBundle, String, Throwable)};
 435          **/
 436         LOGRBP_STRING_THROWN("logrb", MethodType.methodType(void.class,
 437                 Level.class, String.class, String.class, ResourceBundle.class,
 438                 String.class, Throwable.class)),
 439         ;
 440         final MethodType mt;
 441         final String method;
 442         JdkLogMethodInvoker(String method, MethodType mt) {
 443             this.mt = mt;
 444             this.method = method;
 445         }
 446         Object[] makeArgs(Level level, Object... rest) {
 447             List<Object> list = new ArrayList<>(rest == null ? 1 : rest.length + 1);
 448             list.add(level);
 449             if (rest != null) {
 450                 list.addAll(Arrays.asList(rest));
 451             }
 452             return list.toArray(new Object[list.size()]);
 453         }
 454 
 455         @Override
 456         public void logX(sun.util.logging.PlatformLoggerBridge logger, Level level, Object... args) {
 457             try {
 458                 MethodHandle handle = lookup.findVirtual(bridgeLoggerClass,
 459                         method, mt).bindTo(logger);
 460                 final int last = mt.parameterCount()-1;
 461                 boolean isVarargs = mt.parameterType(last).isArray();
 462 
 463                 args = makeArgs(level, args);
 464 
 465                 final StringBuilder builder = new StringBuilder();
 466                 builder.append(logger.getClass().getSimpleName()).append('.')
 467                         .append(this.method).append('(');
 468                 String sep = "";
 469                 int offset = 0;
 470                 Object[] params = args;
 471                 for (int i=0; (i-offset) < params.length; i++) {
 472                     if (isVarargs && i == last) {
 473                         offset = last;
 474                         params = (Object[])args[i];
 475                         if (params == null) break;
 476                     }
 477                     Object p = params[i - offset];
 478                     String quote = (p instanceof String) ? "\"" : "";
 479                     p = p instanceof Level ? "Level."+p : p;
 480                     builder.append(sep).append(quote).append(p).append(quote);
 481                     sep = ", ";
 482                 }
 483                 builder.append(')');
 484                 if (verbose) System.out.println(builder);
 485                 handle.invokeWithArguments(args);
 486             } catch (Throwable ex) {
 487                 throw new RuntimeException(ex);
 488             }
 489         }
 490     }
 491 
 492 
 493     public enum SpiLogMethodInvoker implements MethodInvoker<java.lang.System.Logger,
 494             java.lang.System.Logger.Level> {
 495         /**
 496          * Tests {@link
 497          * jdk.internal.logging.Logger#log(Level, String, Object...)};
 498          **/
 499         LOG_STRING_PARAMS("log", MethodType.methodType(void.class,
 500                 java.lang.System.Logger.Level.class, String.class, Object[].class)),
 501         /**
 502          * Tests {@link
 503          * jdk.internal.logging.Logger#log(Level, String, Throwable)};
 504          **/
 505         LOG_STRING_THROWN("log", MethodType.methodType(void.class,
 506                 java.lang.System.Logger.Level.class, String.class, Throwable.class)),
 507         /**
 508          * Tests {@link
 509          * jdk.internal.logging.Logger#log(Level, Supplier<String>)};
 510          **/
 511         LOG_SUPPLIER("log", MethodType.methodType(void.class,
 512                 java.lang.System.Logger.Level.class, Supplier.class)),
 513         /**
 514          * Tests {@link
 515          * jdk.internal.logging.Logger#log(Level, Throwable, Supplier<String>)};
 516          **/
 517         LOG_SUPPLIER_THROWN("log", MethodType.methodType(void.class,
 518                 java.lang.System.Logger.Level.class, Supplier.class, Throwable.class)),
 519         /**
 520          * Tests {@link
 521          * jdk.internal.logging.Logger#log(Level, Supplier<String>)};
 522          **/
 523         LOG_OBJECT("log", MethodType.methodType(void.class,
 524                 java.lang.System.Logger.Level.class, Object.class)),
 525         /**
 526          * Tests {@link
 527          * jdk.internal.logging.Logger#logrb(Level, ResourceBundle, String, Object...)};
 528          **/
 529         LOGRB_STRING_PARAMS("log", MethodType.methodType(void.class,
 530                 java.lang.System.Logger.Level.class, ResourceBundle.class,
 531                 String.class, Object[].class)),
 532         /**
 533          * Tests {@link
 534          * jdk.internal.logging.Logger#logrb(Level, ResourceBundle, String, Throwable)};
 535          **/
 536         LOGRB_STRING_THROWN("log", MethodType.methodType(void.class,
 537                 java.lang.System.Logger.Level.class, ResourceBundle.class,
 538                 String.class, Throwable.class)),
 539         ;
 540         final MethodType mt;
 541         final String method;
 542         SpiLogMethodInvoker(String method, MethodType mt) {
 543             this.mt = mt;
 544             this.method = method;
 545         }
 546         Object[] makeArgs(java.lang.System.Logger.Level level, Object... rest) {
 547             List<Object> list = new ArrayList<>(rest == null ? 1 : rest.length + 1);
 548             list.add(level);
 549             if (rest != null) {
 550                 list.addAll(Arrays.asList(rest));
 551             }
 552             return list.toArray(new Object[list.size()]);
 553         }
 554 
 555         @Override
 556         public void logX(java.lang.System.Logger logger,
 557                 java.lang.System.Logger.Level level, Object... args) {
 558             try {
 559                 MethodHandle handle = lookup.findVirtual(spiLoggerClass,
 560                         method, mt).bindTo(logger);
 561                 final int last = mt.parameterCount()-1;
 562                 boolean isVarargs = mt.parameterType(last).isArray();
 563 
 564                 args = makeArgs(level, args);
 565 
 566                 final StringBuilder builder = new StringBuilder();
 567                 builder.append(logger.getClass().getSimpleName()).append('.')
 568                         .append(this.method).append('(');
 569                 String sep = "";
 570                 int offset = 0;
 571                 Object[] params = args;
 572                 for (int i=0; (i-offset) < params.length; i++) {
 573                     if (isVarargs && i == last) {
 574                         offset = last;
 575                         params = (Object[])args[i];
 576                         if (params == null) break;
 577                     }
 578                     Object p = params[i - offset];
 579                     String quote = (p instanceof String) ? "\"" : "";
 580                     p = p instanceof Level ? "Level."+p : p;
 581                     builder.append(sep).append(quote).append(p).append(quote);
 582                     sep = ", ";
 583                 }
 584                 builder.append(')');
 585                 if (verbose) System.out.println(builder);
 586                 handle.invokeWithArguments(args);
 587             } catch (Throwable ex) {
 588                 throw new RuntimeException(ex);
 589             }
 590         }
 591     }
 592 
 593 
 594     public abstract static class BackendTester<BackendRecord> {
 595         static final Level[] levelMap = {Level.ALL, Level.FINER, Level.FINE,
 596             Level.INFO, Level.WARNING, Level.SEVERE, Level.OFF};
 597 
 598         abstract class BackendAdaptor {
 599             public abstract String getLoggerName(BackendRecord res);
 600             public abstract Object getLevel(BackendRecord res);
 601             public abstract String getMessage(BackendRecord res);
 602             public abstract String getSourceClassName(BackendRecord res);
 603             public abstract String getSourceMethodName(BackendRecord res);
 604             public abstract Throwable getThrown(BackendRecord res);
 605             public abstract ResourceBundle getResourceBundle(BackendRecord res);
 606             public abstract void setLevel(java.lang.System.Logger logger,
 607                     Level level);
 608             public abstract void setLevel(java.lang.System.Logger logger,
 609                     java.lang.System.Logger.Level level);
 610             public abstract List<BackendRecord> getBackendRecords();
 611             public abstract void resetBackendRecords();
 612             public boolean shouldBeLoggable(Levels level, Level loggerLevel) {
 613                 final Level logLevel = level.platformLevel;
 614                 return shouldBeLoggable(logLevel, loggerLevel);
 615             }
 616             public boolean shouldBeLoggable(Level logLevel, Level loggerLevel) {
 617                 return loggerLevel.intValue() != Level.OFF.intValue()
 618                         && logLevel.intValue() >= loggerLevel.intValue();
 619             }
 620             public boolean shouldBeLoggable(java.lang.System.Logger.Level logLevel,
 621                     java.lang.System.Logger.Level loggerLevel) {
 622                 return loggerLevel != java.lang.System.Logger.Level.OFF
 623                         && logLevel.ordinal() >= loggerLevel.ordinal();
 624             }
 625             public boolean isLoggable(java.lang.System.Logger logger, Level l) {
 626                 return bridgeLoggerClass.cast(logger).isLoggable(l);
 627             }
 628             public String getCallerClassName(Levels level, String clazz) {
 629                 return clazz != null ? clazz : Levels.class.getName();
 630             }
 631             public String getCallerClassName(MethodInvoker<?,?> logMethod,
 632                    String clazz) {
 633                 return clazz != null ? clazz : logMethod.getClass().getName();
 634             }
 635             public String getCallerMethodName(Levels level, String method) {
 636                 return method != null ? method : "invoke";
 637             }
 638             public String getCallerMethodName(MethodInvoker<?,?> logMethod,
 639                     String method) {
 640                 return method != null ? method : "logX";
 641             }
 642             public Object getMappedLevel(Object level) {
 643                 return level;
 644             }
 645 
 646             public Level toJUL(java.lang.System.Logger.Level level) {
 647                 return levelMap[level.ordinal()];
 648             }
 649         }
 650 
 651         public final boolean isSystem;
 652         public final Class<? extends java.lang.System.Logger> restrictedTo;
 653         public final ResourceBundle localized;
 654         public BackendTester(boolean isSystem) {
 655             this(isSystem,null,null);
 656         }
 657         public BackendTester(boolean isSystem, ResourceBundle localized) {
 658             this(isSystem,null,localized);
 659         }
 660         public BackendTester(boolean isSystem,
 661                 Class<? extends java.lang.System.Logger> restrictedTo) {
 662             this(isSystem, restrictedTo, null);
 663         }
 664         public BackendTester(boolean isSystem,
 665                 Class<? extends java.lang.System.Logger> restrictedTo,
 666                 ResourceBundle localized) {
 667             this.isSystem = isSystem;
 668             this.restrictedTo = restrictedTo;
 669             this.localized = localized;
 670         }
 671 
 672         public java.lang.System.Logger convert(java.lang.System.Logger logger) {
 673             return logger;
 674         }
 675 
 676         public static Level[] LEVELS = {
 677             Level.OFF,
 678             Level.SEVERE, Level.WARNING, Level.INFO, Level.CONFIG,
 679             Level.FINE, Level.FINER, Level.FINEST,
 680             Level.ALL
 681         };
 682 
 683         abstract BackendAdaptor adaptor();
 684 
 685         protected void checkRecord(Levels test, BackendRecord res, String loggerName,
 686                 Level level, String msg, String className, String methodName,
 687                 Throwable thrown, ResourceBundle bundle, Object... params) {
 688             checkRecord(test, res, loggerName, level, ()->msg, className,
 689                     methodName, thrown, bundle, params);
 690 
 691         }
 692         protected void checkRecord(Levels test, BackendRecord res, String loggerName,
 693                 Level level, Supplier<String> msg, String className, String methodName,
 694                 Throwable thrown, ResourceBundle bundle, Object... params) {
 695             checkRecord(test.method, res, loggerName, level, msg,
 696                     className, methodName, thrown, bundle, params);
 697         }
 698         protected <L> void checkRecord(String logMethod, BackendRecord res, String loggerName,
 699                 L level, Supplier<String> msg, String className, String methodName,
 700                 Throwable thrown, ResourceBundle bundle, Object... params) {
 701             final BackendAdaptor analyzer = adaptor();
 702             if (! Objects.equals(analyzer.getLoggerName(res), loggerName)) {
 703                 throw new RuntimeException(logMethod+": expected logger name "
 704                         + loggerName + " got " + analyzer.getLoggerName(res));
 705             }
 706             if (!Objects.equals(analyzer.getLevel(res), analyzer.getMappedLevel(level))) {
 707                 throw new RuntimeException(logMethod+": expected level "
 708                         + analyzer.getMappedLevel(level) + " got " + analyzer.getLevel(res));
 709             }
 710             if (!Objects.equals(analyzer.getMessage(res), msg.get())) {
 711                 throw new RuntimeException(logMethod+": expected message \""
 712                         + msg.get() + "\" got \"" + analyzer.getMessage(res) +"\"");
 713             }
 714             if (!Objects.equals(analyzer.getSourceClassName(res), className)) {
 715                 throw new RuntimeException(logMethod
 716                         + ": expected class name \"" + className
 717                         + "\" got \"" + analyzer.getSourceClassName(res) +"\"");
 718             }
 719             if (!Objects.equals(analyzer.getSourceMethodName(res), methodName)) {
 720                 throw new RuntimeException(logMethod
 721                         + ": expected method name \"" + methodName
 722                         + "\" got \"" + analyzer.getSourceMethodName(res) +"\"");
 723             }
 724             final Throwable thrownRes = analyzer.getThrown(res);
 725             if (!Objects.equals(thrownRes, thrown)) {
 726                 throw new RuntimeException(logMethod
 727                         + ": expected throwable \"" + thrown
 728                         + "\" got \"" + thrownRes + "\"");
 729             }
 730             if (!Objects.equals(analyzer.getResourceBundle(res), bundle)) {
 731                 throw new RuntimeException(logMethod
 732                         + ": expected bundle \"" + bundle
 733                         + "\" got \"" + analyzer.getResourceBundle(res) +"\"");
 734             }
 735         }
 736 
 737         public void testLevel(Levels level, java.lang.System.Logger logger,
 738                 String msg) {
 739             Runnable test = () -> level.level(logger, msg);
 740             Checker<BackendRecord, Level> check = (res, l) -> {
 741                 checkRecord(level, res, logger.getName(), l, msg,
 742                             adaptor().getCallerClassName(level, Levels.class.getName()),
 743                             adaptor().getCallerMethodName(level, "invoke"),
 744                             null, localized);
 745                 return null;
 746             };
 747             test("msg", level, logger, test, check);
 748         }
 749 
 750         public void testLevel(Levels level, java.lang.System.Logger logger,
 751                 String msg, Object... params) {
 752             Runnable test = () -> level.level(logger, msg, (Object[])params);
 753             Checker<BackendRecord, Level> check = (res, l) -> {
 754                 checkRecord(level, res, logger.getName(), l, msg,
 755                             adaptor().getCallerClassName(level, Levels.class.getName()),
 756                             adaptor().getCallerMethodName(level, "invoke"),
 757                             null, localized, (Object[])params);
 758                 return null;
 759             };
 760             test("msg, params", level, logger, test, check);
 761         }
 762 
 763         public void testLevel(Levels level, java.lang.System.Logger logger,
 764                 String msg, Throwable thrown) {
 765             Runnable test = () -> level.level(logger, msg, thrown);
 766             Checker<BackendRecord, Level> check = (res, l) -> {
 767                 checkRecord(level, res, logger.getName(), l, msg,
 768                             adaptor().getCallerClassName(level, Levels.class.getName()),
 769                             adaptor().getCallerMethodName(level, "invoke"),
 770                             thrown, localized);
 771                 return null;
 772             };
 773             test("msg, thrown", level, logger, test, check);
 774         }
 775 
 776         public void testLevel(Levels level, java.lang.System.Logger logger,
 777                 Supplier<String> msg) {
 778             Runnable test = () -> level.level(logger, msg);
 779             Checker<BackendRecord, Level> check = (res, l) -> {
 780                 checkRecord(level, res, logger.getName(), l, msg,
 781                             adaptor().getCallerClassName(level, Levels.class.getName()),
 782                             adaptor().getCallerMethodName(level, "invoke"),
 783                             null, null);
 784                 return null;
 785             };
 786             test("msgSupplier", level, logger, test, check);
 787         }
 788 
 789         public void testLevel(Levels level, java.lang.System.Logger logger,
 790                 Supplier<String> msg, Throwable thrown) {
 791             Runnable test = () -> level.level(logger, msg, thrown);
 792             Checker<BackendRecord, Level> check = (res, l) -> {
 793                 checkRecord(level, res, logger.getName(), l, msg,
 794                             adaptor().getCallerClassName(level, Levels.class.getName()),
 795                             adaptor().getCallerMethodName(level, "invoke"),
 796                             thrown, null);
 797                 return null;
 798             };
 799             test("throw, msgSupplier", level, logger, test, check);
 800         }
 801 
 802         public void testLevel(Levels level, java.lang.System.Logger logger,
 803                 String msg, ResourceBundle bundle) {
 804             Runnable test = () -> level.level(logger, msg, bundle);
 805             Checker<BackendRecord, Level> check = (res, l) -> {
 806                 checkRecord(level, res, logger.getName(), l, msg,
 807                             adaptor().getCallerClassName(level, Levels.class.getName()),
 808                             adaptor().getCallerMethodName(level, "invoke"),
 809                             null, bundle);
 810                 return null;
 811             };
 812             test("bundle, msg", level, logger, test, check);
 813         }
 814 
 815         public void testLevel(Levels level, java.lang.System.Logger logger,
 816                 String msg, ResourceBundle bundle, Object... params) {
 817             Runnable test = () -> level.level(logger, msg, bundle, (Object[])params);
 818             Checker<BackendRecord, Level> check = (res, l) -> {
 819                 checkRecord(level, res, logger.getName(), l, msg,
 820                             adaptor().getCallerClassName(level, Levels.class.getName()),
 821                             adaptor().getCallerMethodName(level, "invoke"),
 822                             null, bundle, (Object[])params);
 823                 return null;
 824             };
 825             test("bundle, msg, params", level, logger, test, check);
 826         }
 827 
 828         public void testLevel(Levels level, java.lang.System.Logger logger,
 829                 String msg, ResourceBundle bundle, Throwable thrown) {
 830             Runnable test = () -> level.level(logger, msg, bundle, thrown);
 831             Checker<BackendRecord, Level> check = (res, l) -> {
 832                 checkRecord(level, res, logger.getName(), l, msg,
 833                             adaptor().getCallerClassName(level, Levels.class.getName()),
 834                             adaptor().getCallerMethodName(level, "invoke"),
 835                             thrown, bundle);
 836                 return null;
 837             };
 838             test("bundle, msg, throwable", level, logger, test, check);
 839         }
 840 
 841         // System.Logger
 842         public void testSpiLog(java.lang.System.Logger logger, String msg) {
 843             Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
 844                 checkRecord("log", res, logger.getName(), l, () -> msg,
 845                             adaptor().getCallerClassName(
 846                                     SpiLogMethodInvoker.LOG_STRING_PARAMS,
 847                                     SpiLogMethodInvoker.class.getName()),
 848                             adaptor().getCallerMethodName(
 849                                     SpiLogMethodInvoker.LOG_STRING_PARAMS,
 850                                     "logX"), null, localized);
 851                 return null;
 852             };
 853             SpiLogTester tester = (x, level) -> {
 854                 SpiLogMethodInvoker.LOG_STRING_PARAMS.logX(x, level, msg, (Object[])null);
 855                 return null;
 856             };
 857             Function<String, String> nameProducer = (l) -> "log(Level." + l + ", \"" + msg + "\")";
 858             testSpiLog(logger, tester, check, nameProducer);
 859         }
 860 
 861         public void testSpiLog(java.lang.System.Logger logger,
 862                 ResourceBundle bundle, String msg) {
 863             Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
 864                 checkRecord("log", res, logger.getName(), l, () -> msg,
 865                             adaptor().getCallerClassName(
 866                                     SpiLogMethodInvoker.LOGRB_STRING_PARAMS,
 867                                     SpiLogMethodInvoker.class.getName()),
 868                             adaptor().getCallerMethodName(
 869                                     SpiLogMethodInvoker.LOGRB_STRING_PARAMS,
 870                                     "logX"), null, bundle);
 871                 return null;
 872             };
 873             SpiLogTester tester = (x, level) -> {
 874                 SpiLogMethodInvoker.LOGRB_STRING_PARAMS.logX(x, level, bundle, msg, (Object[])null);
 875                 return null;
 876             };
 877             Function<String, String> nameProducer = (l) -> "log(Level." + l
 878                     + ", bundle, \"" + msg + "\")";
 879             testSpiLog(logger, tester, check, nameProducer);
 880         }
 881 
 882         public void testSpiLog(java.lang.System.Logger logger, String msg, Object... params) {
 883             Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
 884                 checkRecord("log", res, logger.getName(), l, () -> msg,
 885                             adaptor().getCallerClassName(
 886                                     SpiLogMethodInvoker.LOG_STRING_PARAMS,
 887                                     SpiLogMethodInvoker.class.getName()),
 888                             adaptor().getCallerMethodName(
 889                                     SpiLogMethodInvoker.LOG_STRING_PARAMS,
 890                                     "logX"), null, localized, params);
 891                 return null;
 892             };
 893             SpiLogTester tester = (x, level) -> {
 894                 SpiLogMethodInvoker.LOG_STRING_PARAMS.logX(x, level, msg, params);
 895                 return null;
 896             };
 897             Function<String, String> nameProducer = (l) -> "log(Level." + l + ", \"" + msg + "\", params...)";
 898             testSpiLog(logger, tester, check, nameProducer);
 899         }
 900 
 901         public void testSpiLog(java.lang.System.Logger logger,
 902                 ResourceBundle bundle, String msg, Object... params) {
 903             Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
 904                 checkRecord("log", res, logger.getName(), l, () -> msg,
 905                             adaptor().getCallerClassName(
 906                                     SpiLogMethodInvoker.LOGRB_STRING_PARAMS,
 907                                     SpiLogMethodInvoker.class.getName()),
 908                             adaptor().getCallerMethodName(
 909                                     SpiLogMethodInvoker.LOGRB_STRING_PARAMS,
 910                                     "logX"), null, bundle, params);
 911                 return null;
 912             };
 913             SpiLogTester tester = (x, level) -> {
 914                 SpiLogMethodInvoker.LOGRB_STRING_PARAMS.logX(x, level, bundle, msg, params);
 915                 return null;
 916             };
 917             Function<String, String> nameProducer = (l) -> "log(Level." + l
 918                     + ", bundle, \"" + msg + "\", params...)";
 919             testSpiLog(logger, tester, check, nameProducer);
 920         }
 921 
 922         public void testSpiLog(java.lang.System.Logger logger, String msg, Throwable thrown) {
 923             Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
 924                 checkRecord("log", res, logger.getName(), l, () -> msg,
 925                            adaptor().getCallerClassName(
 926                                     SpiLogMethodInvoker.LOG_STRING_THROWN,
 927                                     SpiLogMethodInvoker.class.getName()),
 928                             adaptor().getCallerMethodName(
 929                                     SpiLogMethodInvoker.LOG_STRING_THROWN,
 930                                     "logX"), thrown, localized);
 931                 return null;
 932             };
 933             SpiLogTester tester = (x, level) -> {
 934                 SpiLogMethodInvoker.LOG_STRING_THROWN.logX(x, level, msg, thrown);
 935                 return null;
 936             };
 937             Function<String, String> nameProducer = (l) ->
 938                     "log(Level." + l + ", \"" + msg + "\", thrown)";
 939             testSpiLog(logger, tester, check, nameProducer);
 940         }
 941 
 942         public void testSpiLog(java.lang.System.Logger logger,
 943                 ResourceBundle bundle, String msg, Throwable thrown) {
 944             Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
 945                 checkRecord("log", res, logger.getName(), l, () -> msg,
 946                             adaptor().getCallerClassName(
 947                                     SpiLogMethodInvoker.LOGRB_STRING_THROWN,
 948                                     SpiLogMethodInvoker.class.getName()),
 949                             adaptor().getCallerMethodName(
 950                                     SpiLogMethodInvoker.LOGRB_STRING_THROWN,
 951                                     "logX"), thrown, bundle);
 952                 return null;
 953             };
 954             SpiLogTester tester = (x, level) -> {
 955                 SpiLogMethodInvoker.LOGRB_STRING_THROWN.logX(x, level, bundle, msg, thrown);
 956                 return null;
 957             };
 958             Function<String, String> nameProducer = (l) ->
 959                     "log(Level." + l + ", bundle, \"" + msg + "\", thrown)";
 960             testSpiLog(logger, tester, check, nameProducer);
 961         }
 962 
 963         public void testSpiLog(java.lang.System.Logger logger, Supplier<String> msg) {
 964             Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
 965                 checkRecord("log", res, logger.getName(), l, msg,
 966                             adaptor().getCallerClassName(
 967                                     SpiLogMethodInvoker.LOG_SUPPLIER,
 968                                     SpiLogMethodInvoker.class.getName()),
 969                             adaptor().getCallerMethodName(
 970                                     SpiLogMethodInvoker.LOG_SUPPLIER,
 971                                     "logX"), null, null);
 972                 return null;
 973             };
 974             SpiLogTester tester = (x, level) -> {
 975                 SpiLogMethodInvoker.LOG_SUPPLIER.logX(x, level, msg);
 976                 return null;
 977             };
 978             Function<String, String> nameProducer = (l) ->
 979                     "log(Level." + l + ", () -> \"" + msg.get() + "\")";
 980             testSpiLog(logger, tester, check, nameProducer);
 981         }
 982 
 983         public void testSpiLog(java.lang.System.Logger logger, Object obj) {
 984             Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
 985                 checkRecord("log", res, logger.getName(), l, () -> obj.toString(),
 986                             adaptor().getCallerClassName(
 987                                     SpiLogMethodInvoker.LOG_OBJECT,
 988                                     SpiLogMethodInvoker.class.getName()),
 989                             adaptor().getCallerMethodName(
 990                                     SpiLogMethodInvoker.LOG_OBJECT,
 991                                     "logX"), null, null);
 992                 return null;
 993             };
 994             SpiLogTester tester = (x, level) -> {
 995                 SpiLogMethodInvoker.LOG_OBJECT.logX(x, level, obj);
 996                 return null;
 997             };
 998             Function<String, String> nameProducer = (l) ->
 999                     "log(Level." + l + ", new "+obj.getClass().getSimpleName()+"(\""
1000                             + obj.toString() + "\"))";
1001             testSpiLog(logger, tester, check, nameProducer);
1002         }
1003 
1004         public void testSpiLog(java.lang.System.Logger logger, Throwable thrown, Supplier<String> msg) {
1005             Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
1006                 checkRecord("log", res, logger.getName(), l, msg,
1007                             adaptor().getCallerClassName(
1008                                     SpiLogMethodInvoker.LOG_SUPPLIER_THROWN,
1009                                     SpiLogMethodInvoker.class.getName()),
1010                             adaptor().getCallerMethodName(
1011                                     SpiLogMethodInvoker.LOG_SUPPLIER_THROWN,
1012                                     "logX"), thrown, null);
1013                 return null;
1014             };
1015             SpiLogTester tester = (x, level) -> {
1016                 SpiLogMethodInvoker.LOG_SUPPLIER_THROWN.logX(x, level, msg, thrown);
1017                 return null;
1018             };
1019             Function<String, String> nameProducer = (l) ->
1020                     "log(Level." + l + ", () -> \"" + msg.get() + "\", thrown)";
1021             testSpiLog(logger, tester, check, nameProducer);
1022         }
1023 
1024 
1025         // JDK
1026 
1027         public void testLog(java.lang.System.Logger logger, String msg) {
1028             Checker<BackendRecord, Level> check = (res, l) -> {
1029                 checkRecord("log", res, logger.getName(), l, () -> msg,
1030                             adaptor().getCallerClassName(
1031                                     JdkLogMethodInvoker.LOG_STRING_PARAMS,
1032                                     JdkLogMethodInvoker.class.getName()),
1033                             adaptor().getCallerMethodName(
1034                                     JdkLogMethodInvoker.LOG_STRING_PARAMS,
1035                                     "logX"), null, localized);
1036                 return null;
1037             };
1038             JdkLogTester tester = (x, level) -> {
1039                 JdkLogMethodInvoker.LOG_STRING_PARAMS.logX(x, level, msg, (Object[])null);
1040                 return null;
1041             };
1042             Function<String, String> nameProducer = (l) -> "log(Level." + l + ", \"" + msg + "\")";
1043             testJdkLog(logger, tester, check, nameProducer);
1044         }
1045 
1046         public void testLogrb(java.lang.System.Logger logger,
1047                 ResourceBundle bundle, String msg) {
1048             Checker<BackendRecord, Level> check = (res, l) -> {
1049                 checkRecord("log", res, logger.getName(), l, () -> msg,
1050                             adaptor().getCallerClassName(
1051                                     JdkLogMethodInvoker.LOGRB_STRING_PARAMS,
1052                                     JdkLogMethodInvoker.class.getName()),
1053                             adaptor().getCallerMethodName(
1054                                     JdkLogMethodInvoker.LOGRB_STRING_PARAMS,
1055                                     "logX"), null, bundle);
1056                 return null;
1057             };
1058             JdkLogTester tester = (x, level) -> {
1059                 JdkLogMethodInvoker.LOGRB_STRING_PARAMS.logX(x, level, bundle, msg, (Object[])null);
1060                 return null;
1061             };
1062             Function<String, String> nameProducer = (l) -> "logrb(Level." + l
1063                     + ", bundle, \"" + msg + "\")";
1064             testJdkLog(logger, tester, check, nameProducer);
1065         }
1066 
1067         public void testLog(java.lang.System.Logger logger, String msg, Object... params) {
1068             Checker<BackendRecord, Level> check = (res, l) -> {
1069                 checkRecord("log", res, logger.getName(), l, () -> msg,
1070                             adaptor().getCallerClassName(
1071                                     JdkLogMethodInvoker.LOG_STRING_PARAMS,
1072                                     JdkLogMethodInvoker.class.getName()),
1073                             adaptor().getCallerMethodName(
1074                                     JdkLogMethodInvoker.LOG_STRING_PARAMS,
1075                                     "logX"), null, localized, params);
1076                 return null;
1077             };
1078             JdkLogTester tester = (x, level) -> {
1079                 JdkLogMethodInvoker.LOG_STRING_PARAMS.logX(x, level, msg, params);
1080                 return null;
1081             };
1082             Function<String, String> nameProducer = (l) -> "log(Level." + l + ", \"" + msg + "\", params...)";
1083             testJdkLog(logger, tester, check, nameProducer);
1084         }
1085 
1086         public void testLogrb(java.lang.System.Logger logger,
1087                 ResourceBundle bundle, String msg, Object... params) {
1088             Checker<BackendRecord, Level> check = (res, l) -> {
1089                 checkRecord("log", res, logger.getName(), l, () -> msg,
1090                             adaptor().getCallerClassName(
1091                                     JdkLogMethodInvoker.LOGRB_STRING_PARAMS,
1092                                     JdkLogMethodInvoker.class.getName()),
1093                             adaptor().getCallerMethodName(
1094                                     JdkLogMethodInvoker.LOGRB_STRING_PARAMS,
1095                                     "logX"), null, bundle, params);
1096                 return null;
1097             };
1098             JdkLogTester tester = (x, level) -> {
1099                 JdkLogMethodInvoker.LOGRB_STRING_PARAMS.logX(x, level, bundle, msg, params);
1100                 return null;
1101             };
1102             Function<String, String> nameProducer = (l) -> "log(Level." + l
1103                     + ", bundle, \"" + msg + "\", params...)";
1104             testJdkLog(logger, tester, check, nameProducer);
1105         }
1106 
1107         public void testLog(java.lang.System.Logger logger, String msg, Throwable thrown) {
1108             Checker<BackendRecord, Level> check = (res, l) -> {
1109                 checkRecord("log", res, logger.getName(), l, () -> msg,
1110                            adaptor().getCallerClassName(
1111                                     JdkLogMethodInvoker.LOG_STRING_THROWN,
1112                                     JdkLogMethodInvoker.class.getName()),
1113                             adaptor().getCallerMethodName(
1114                                     JdkLogMethodInvoker.LOG_STRING_THROWN,
1115                                     "logX"), thrown, localized);
1116                 return null;
1117             };
1118             JdkLogTester tester = (x, level) -> {
1119                 JdkLogMethodInvoker.LOG_STRING_THROWN.logX(x, level, msg, thrown);
1120                 return null;
1121             };
1122             Function<String, String> nameProducer = (l) ->
1123                     "log(Level." + l + ", \"" + msg + "\", thrown)";
1124             testJdkLog(logger, tester, check, nameProducer);
1125         }
1126 
1127         public void testLogrb(java.lang.System.Logger logger,
1128                 ResourceBundle bundle, String msg, Throwable thrown) {
1129             Checker<BackendRecord, Level> check = (res, l) -> {
1130                 checkRecord("log", res, logger.getName(), l, () -> msg,
1131                             adaptor().getCallerClassName(
1132                                     JdkLogMethodInvoker.LOGRB_STRING_THROWN,
1133                                     JdkLogMethodInvoker.class.getName()),
1134                             adaptor().getCallerMethodName(
1135                                     JdkLogMethodInvoker.LOGRB_STRING_THROWN,
1136                                     "logX"), thrown, bundle);
1137                 return null;
1138             };
1139             JdkLogTester tester = (x, level) -> {
1140                 JdkLogMethodInvoker.LOGRB_STRING_THROWN.logX(x, level, bundle, msg, thrown);
1141                 return null;
1142             };
1143             Function<String, String> nameProducer = (l) ->
1144                     "log(Level." + l + ", bundle, \"" + msg + "\", thrown)";
1145             testJdkLog(logger, tester, check, nameProducer);
1146         }
1147 
1148         public void testLog(java.lang.System.Logger logger, Supplier<String> msg) {
1149             Checker<BackendRecord, Level> check = (res, l) -> {
1150                 checkRecord("log", res, logger.getName(), l, msg,
1151                             adaptor().getCallerClassName(
1152                                     JdkLogMethodInvoker.LOG_SUPPLIER,
1153                                     JdkLogMethodInvoker.class.getName()),
1154                             adaptor().getCallerMethodName(
1155                                     JdkLogMethodInvoker.LOG_SUPPLIER,
1156                                     "logX"), null, null);
1157                 return null;
1158             };
1159             JdkLogTester tester = (x, level) -> {
1160                 JdkLogMethodInvoker.LOG_SUPPLIER.logX(x, level, msg);
1161                 return null;
1162             };
1163             Function<String, String> nameProducer = (l) ->
1164                     "log(Level." + l + ", () -> \"" + msg.get() + "\")";
1165             testJdkLog(logger, tester, check, nameProducer);
1166         }
1167 
1168         public void testLog(java.lang.System.Logger logger, Throwable thrown, Supplier<String> msg) {
1169             Checker<BackendRecord, Level> check = (res, l) -> {
1170                 checkRecord("log", res, logger.getName(), l, msg,
1171                             adaptor().getCallerClassName(
1172                                     JdkLogMethodInvoker.LOG_SUPPLIER_THROWN,
1173                                     JdkLogMethodInvoker.class.getName()),
1174                             adaptor().getCallerMethodName(
1175                                     JdkLogMethodInvoker.LOG_SUPPLIER_THROWN,
1176                                     "logX"), thrown, null);
1177                 return null;
1178             };
1179             JdkLogTester tester = (x, level) -> {
1180                 JdkLogMethodInvoker.LOG_SUPPLIER_THROWN.logX(x, level, thrown, msg);
1181                 return null;
1182             };
1183             Function<String, String> nameProducer = (l) ->
1184                     "log(Level." + l + ", () -> \"" + msg.get() + "\", thrown)";
1185             testJdkLog(logger, tester, check, nameProducer);
1186         }
1187 
1188         static Supplier<String> logpMessage(ResourceBundle bundle,
1189                 String className, String methodName, Supplier<String> msg) {
1190             if (BEST_EFFORT_FOR_LOGP && bundle == null
1191                     && (className != null || methodName != null)) {
1192                 final String cName = className == null ? "" :  className;
1193                 final String mName = methodName == null ? "" : methodName;
1194                 return () -> {
1195                     String m = msg.get();
1196                     return String.format("[%s %s] %s", cName, mName, m == null ? "" : m);
1197                 };
1198             } else {
1199                 return msg;
1200             }
1201         }
1202 
1203         public void testLogp(java.lang.System.Logger logger, String className,
1204                 String methodName, String msg) {
1205             Checker<BackendRecord, Level> check = (res, l) -> {
1206                 checkRecord("logp", res, logger.getName(), l,
1207                             logpMessage(localized, className, methodName, () -> msg),
1208                             adaptor().getCallerClassName(
1209                                     JdkLogMethodInvoker.LOGP_STRING, className),
1210                             adaptor().getCallerClassName(
1211                                     JdkLogMethodInvoker.LOGP_STRING, methodName),
1212                             null, localized);
1213                 return null;
1214             };
1215             JdkLogTester tester = (x, level) -> {
1216                 JdkLogMethodInvoker.LOGP_STRING.logX(x, level,
1217                         className, methodName, msg);
1218                 return null;
1219             };
1220             Function<String, String> nameProducer = (l) ->
1221                     "logp(Level." + l + ", class, method, \"" + msg + "\")";
1222             testJdkLog(logger, tester, check, nameProducer);
1223         }
1224 
1225         public void testLogrb(java.lang.System.Logger logger, String className,
1226                 String methodName, ResourceBundle bundle, String msg) {
1227             Checker<BackendRecord, Level> check = (res, l) -> {
1228                 checkRecord("logp", res, logger.getName(), l, () -> msg,
1229                             adaptor().getCallerClassName(
1230                                     JdkLogMethodInvoker.LOGRBP_STRING_PARAMS, className),
1231                             adaptor().getCallerClassName(
1232                                     JdkLogMethodInvoker.LOGRBP_STRING_PARAMS, methodName),
1233                             null, bundle);
1234                 return null;
1235             };
1236             JdkLogTester tester = (x, level) -> {
1237                 JdkLogMethodInvoker.LOGRBP_STRING_PARAMS.logX(x, level,
1238                         className, methodName, bundle, msg, (Object[])null);
1239                 return null;
1240             };
1241             Function<String, String> nameProducer = (l) ->
1242                     "logp(Level." + l + ", class, method, bundle, \"" + msg + "\")";
1243             testJdkLog(logger, tester, check, nameProducer);
1244         }
1245 
1246         public void testLogp(java.lang.System.Logger logger, String className,
1247                 String methodName, String msg, Object... params) {
1248             Checker<BackendRecord, Level> check = (res, l) -> {
1249                 checkRecord("logp", res, logger.getName(), l,
1250                             logpMessage(localized, className, methodName, () -> msg),
1251                             adaptor().getCallerClassName(
1252                                     JdkLogMethodInvoker.LOGP_STRING_PARAMS, className),
1253                             adaptor().getCallerClassName(
1254                                     JdkLogMethodInvoker.LOGP_STRING_PARAMS, methodName),
1255                             null, localized, params);
1256                 return null;
1257             };
1258             JdkLogTester tester = (x, level) -> {
1259                 JdkLogMethodInvoker.LOGP_STRING_PARAMS.logX(x, level,
1260                         className, methodName, msg, params);
1261                 return null;
1262             };
1263             Function<String, String> nameProducer = (l) ->
1264                     "log(Level." + l + ", class, method, \"" + msg + "\", params...)";
1265             testJdkLog(logger, tester, check, nameProducer);
1266         }
1267 
1268         public void testLogrb(java.lang.System.Logger logger, String className,
1269                 String methodName, ResourceBundle bundle, String msg,
1270                 Object... params) {
1271             Checker<BackendRecord, Level> check = (res, l) -> {
1272                 checkRecord("logp", res, logger.getName(), l, () -> msg,
1273                             adaptor().getCallerClassName(
1274                                     JdkLogMethodInvoker.LOGRBP_STRING_PARAMS, className),
1275                             adaptor().getCallerClassName(
1276                                     JdkLogMethodInvoker.LOGRBP_STRING_PARAMS, methodName),
1277                             null, bundle, params);
1278                 return null;
1279             };
1280             JdkLogTester tester = (x, level) -> {
1281                 JdkLogMethodInvoker.LOGRBP_STRING_PARAMS.logX(x, level,
1282                         className, methodName, bundle, msg, params);
1283                 return null;
1284             };
1285             Function<String, String> nameProducer = (l) ->
1286                     "log(Level." + l + ", class, method, bundle, \""
1287                             + msg + "\", params...)";
1288             testJdkLog(logger, tester, check, nameProducer);
1289         }
1290 
1291         public void testLogp(java.lang.System.Logger logger, String className,
1292                 String methodName, String msg, Throwable thrown) {
1293             Checker<BackendRecord, Level> check = (res, l) -> {
1294                 checkRecord("log", res, logger.getName(), l,
1295                             logpMessage(localized, className, methodName, () -> msg),
1296                             adaptor().getCallerClassName(
1297                                     JdkLogMethodInvoker.LOGP_STRING_THROWN, className),
1298                             adaptor().getCallerClassName(
1299                                     JdkLogMethodInvoker.LOGP_STRING_THROWN, methodName),
1300                             thrown, localized);
1301                 return null;
1302             };
1303             JdkLogTester tester = (x, level) -> {
1304                 JdkLogMethodInvoker.LOGP_STRING_THROWN.logX(x, level,
1305                         className, methodName, msg, thrown);
1306                 return null;
1307             };
1308             Function<String, String> nameProducer = (l) ->
1309                     "log(Level." + l + ", class, method, \"" + msg + "\", thrown)";
1310             testJdkLog(logger, tester, check, nameProducer);
1311         }
1312 
1313         public void testLogrb(java.lang.System.Logger logger, String className,
1314                 String methodName, ResourceBundle bundle,
1315                 String msg, Throwable thrown) {
1316             Checker<BackendRecord, Level> check = (res, l) -> {
1317                 checkRecord("log", res, logger.getName(), l, () -> msg,
1318                             adaptor().getCallerClassName(
1319                                     JdkLogMethodInvoker.LOGRBP_STRING_THROWN, className),
1320                             adaptor().getCallerClassName(
1321                                     JdkLogMethodInvoker.LOGRBP_STRING_THROWN, methodName),
1322                             thrown, bundle);
1323                 return null;
1324             };
1325             JdkLogTester tester = (x, level) -> {
1326                 JdkLogMethodInvoker.LOGRBP_STRING_THROWN.logX(x, level,
1327                         className, methodName, bundle, msg, thrown);
1328                 return null;
1329             };
1330             Function<String, String> nameProducer = (l) ->
1331                     "log(Level." + l + ", class, method, bundle, \"" + msg + "\", thrown)";
1332             testJdkLog(logger, tester, check, nameProducer);
1333 
1334         }
1335 
1336         public void testLogp(java.lang.System.Logger logger, String className,
1337                 String methodName, Supplier<String> msg) {
1338             Checker<BackendRecord, Level> check = (res, l) -> {
1339                 checkRecord("log", res, logger.getName(), l,
1340                             logpMessage(null, className, methodName, msg),
1341                             adaptor().getCallerClassName(
1342                                     JdkLogMethodInvoker.LOGP_SUPPLIER, className),
1343                             adaptor().getCallerClassName(
1344                                     JdkLogMethodInvoker.LOGP_SUPPLIER, methodName),
1345                             null, null);
1346                 return null;
1347             };
1348             JdkLogTester tester = (x, level) -> {
1349                 JdkLogMethodInvoker.LOGP_SUPPLIER.logX(x, level,
1350                         className, methodName, msg);
1351                 return null;
1352             };
1353             Function<String, String> nameProducer = (l) ->
1354                     "log(Level." + l + ", class, method, () -> \"" + msg.get() + "\")";
1355             testJdkLog(logger, tester, check, nameProducer);
1356         }
1357 
1358         public void testLogp(java.lang.System.Logger logger, String className,
1359                 String methodName, Throwable thrown, Supplier<String> msg) {
1360             Checker<BackendRecord, Level> check = (res, l) -> {
1361                 checkRecord("log", res, logger.getName(), l,
1362                             logpMessage(null, className, methodName, msg),
1363                             adaptor().getCallerClassName(
1364                                     JdkLogMethodInvoker.LOGP_SUPPLIER_THROWN, className),
1365                             adaptor().getCallerClassName(
1366                                     JdkLogMethodInvoker.LOGP_SUPPLIER_THROWN, methodName),
1367                             thrown, null);
1368                 return null;
1369             };
1370             JdkLogTester tester = (x, level) -> {
1371                 JdkLogMethodInvoker.LOGP_SUPPLIER_THROWN.logX(x, level,
1372                         className, methodName, thrown, msg);
1373                 return null;
1374             };
1375             Function<String, String> nameProducer = (l) ->
1376                     "log(Level." + l + ", class, method, () -> \"" + msg.get() + "\", thrown)";
1377             testJdkLog(logger, tester, check, nameProducer);
1378         }
1379 
1380         private void testJdkLog(java.lang.System.Logger logger,
1381                 JdkLogTester log, Checker<BackendRecord,Level> check,
1382                 Function<String, String> nameProducer) {
1383             if (restrictedTo != null) {
1384                 if (!bridgeLoggerClass.isAssignableFrom(restrictedTo)) {
1385                     if (VERBOSE) {
1386                         System.out.println("Skipping method from "
1387                             + bridgeLoggerClass);
1388                     }
1389                     return;
1390                 }
1391             }
1392             System.out.println("Testing Logger." + nameProducer.apply("*")
1393                      + " on " + logger);
1394             final BackendAdaptor adaptor = adaptor();
1395             for (Level loggerLevel : LEVELS) {
1396                 adaptor.setLevel(logger, loggerLevel);
1397                 for (Level l : LEVELS) {
1398                     check(logger, () -> log.apply(bridgeLoggerClass.cast(logger), l),
1399                           check, () -> adaptor.isLoggable(logger, l),
1400                           () -> adaptor.shouldBeLoggable(l, loggerLevel),
1401                           l, loggerLevel, nameProducer.apply(l.toString()));
1402                 }
1403             }
1404         }
1405 
1406         private void testSpiLog(java.lang.System.Logger logger,
1407                 SpiLogTester log, Checker<BackendRecord, java.lang.System.Logger.Level> check,
1408                 Function<String, String> nameProducer) {
1409             System.out.println("Testing System.Logger." + nameProducer.apply("*")
1410                      + " on " + logger);
1411             final BackendAdaptor adaptor = adaptor();
1412             for (java.lang.System.Logger.Level loggerLevel : java.lang.System.Logger.Level.values()) {
1413 
1414                 adaptor.setLevel(logger, loggerLevel);
1415                 for (java.lang.System.Logger.Level l : java.lang.System.Logger.Level.values()) {
1416                     check(logger, () -> log.apply(logger, l),
1417                           check, () -> logger.isLoggable(l),
1418                           () -> adaptor.shouldBeLoggable(l, loggerLevel),
1419                           l, loggerLevel, nameProducer.apply(l.toString()));
1420                 }
1421             }
1422         }
1423 
1424         private void test(String args, Levels level, java.lang.System.Logger logger,
1425                 Runnable test, Checker<BackendRecord, Level> check) {
1426             if (restrictedTo != null) {
1427                 if (!level.definingClass.isAssignableFrom(restrictedTo)) {
1428                     if (VERBOSE) {
1429                         System.out.println("Skipping method from "
1430                             + level.definingClass);
1431                     }
1432                     return;
1433                 }
1434             }
1435             String method = args.contains("bundle") ? "logrb" : "log";
1436             System.out.println("Testing Logger."
1437                     + method + "(Level." + level.platformLevel
1438                     + ", "+ args + ")" + " on " + logger);
1439             final BackendAdaptor adaptor = adaptor();
1440             for (Level loggerLevel : LEVELS) {
1441                 adaptor.setLevel(logger, loggerLevel);
1442                 check(logger, test, check,
1443                         () -> level.isEnabled(logger),
1444                         () -> adaptor.shouldBeLoggable(level, loggerLevel),
1445                         level.platformLevel, loggerLevel, level.method);
1446             }
1447         }
1448 
1449         private <L> void check(java.lang.System.Logger logger,
1450                 Runnable test, Checker<BackendRecord,L> check,
1451                 BooleanSupplier checkLevelEnabled,
1452                 BooleanSupplier shouldBeLoggable,
1453                 L logLevel, L loggerLevel, String logMethod) {
1454             final BackendAdaptor adaptor = adaptor();
1455             adaptor.resetBackendRecords();
1456             test.run();
1457             final List<BackendRecord> records = adaptor.getBackendRecords();
1458             if (shouldBeLoggable.getAsBoolean()) {
1459                 if (!checkLevelEnabled.getAsBoolean()) {
1460                     throw new RuntimeException("Logger is not enabled for "
1461                             + logMethod
1462                             + " although logger level is " + loggerLevel);
1463                 }
1464                 if (records.size() != 1) {
1465                     throw new RuntimeException(loggerLevel + " [" +
1466                             logLevel + "] : Unexpected record sizes: "
1467                         + records.toString());
1468                 }
1469                 BackendRecord res = records.get(0);
1470                 check.apply(res, logLevel);
1471             } else {
1472                 if (checkLevelEnabled.getAsBoolean()) {
1473                     throw new RuntimeException("Logger is enabled for "
1474                             + logMethod
1475                             + " although logger level is " + loggerLevel);
1476                 }
1477                 if (!records.isEmpty()) {
1478                     throw new RuntimeException(loggerLevel + " [" +
1479                             logLevel + "] : Unexpected record sizes: "
1480                         + records.toString());
1481                 }
1482             }
1483         }
1484     }
1485 
1486     public static class JULBackendTester extends BackendTester<LogRecord>{
1487 
1488         public JULBackendTester(boolean isSystem) {
1489             this(isSystem,null,null);
1490         }
1491         public JULBackendTester(boolean isSystem, ResourceBundle localized) {
1492             this(isSystem,null,localized);
1493         }
1494         public JULBackendTester(boolean isSystem,
1495                 Class<? extends java.lang.System.Logger> restrictedTo) {
1496             this(isSystem, restrictedTo, null);
1497         }
1498         public JULBackendTester(boolean isSystem,
1499                 Class<? extends java.lang.System.Logger> restrictedTo,
1500                 ResourceBundle localized) {
1501             super(isSystem, restrictedTo, localized);
1502         }
1503 
1504         Logger getBackendLogger(String name) {
1505             if (isSystem) {
1506                 return LogManager.demandLoggerFor(name, Thread.class);
1507             } else {
1508                 return Logger.getLogger(name);
1509             }
1510         }
1511 
1512         class JULBackendAdaptor extends BackendAdaptor {
1513             @Override
1514             public String getLoggerName(LogRecord res) {
1515                 return res.getLoggerName();
1516             }
1517             @Override
1518             public Level getLevel(LogRecord res) {
1519                 return Level.valueOf(res.getLevel().getName());
1520             }
1521             @Override
1522             public String getMessage(LogRecord res) {
1523                 return res.getMessage();
1524             }
1525             @Override
1526             public String getSourceClassName(LogRecord res) {
1527                 return res.getSourceClassName();
1528             }
1529             @Override
1530             public String getSourceMethodName(LogRecord res) {
1531                 return res.getSourceMethodName();
1532             }
1533             @Override
1534             public Throwable getThrown(LogRecord res) {
1535                 return res.getThrown();
1536             }
1537             @Override
1538             public ResourceBundle getResourceBundle(LogRecord res) {
1539                 return res.getResourceBundle();
1540             }
1541             @Override
1542             public void setLevel(java.lang.System.Logger logger, Level level) {
1543                 Logger backend = getBackendLogger(logger.getName());
1544                 backend.setLevel(java.util.logging.Level.parse(level.name()));
1545             }
1546             @Override
1547             public void setLevel(java.lang.System.Logger logger, java.lang.System.Logger.Level level) {
1548                 setLevel(logger, toJUL(level));
1549             }
1550             @Override
1551             public List<LogRecord> getBackendRecords() {
1552                 return handler.records;
1553             }
1554             @Override
1555             public void resetBackendRecords() {
1556                 handler.reset();
1557             }
1558             @Override
1559             public Level getMappedLevel(Object level) {
1560                 if (level instanceof java.lang.System.Logger.Level) {
1561                     return toJUL((java.lang.System.Logger.Level)level);
1562                 }
1563                 return (Level)level;
1564             }
1565         }
1566 
1567         final JULBackendAdaptor julAdaptor = new JULBackendAdaptor();
1568 
1569         @Override
1570         BackendAdaptor adaptor() {
1571             return julAdaptor;
1572         }
1573 
1574     }
1575 
1576     public abstract static class BackendTesterFactory {
1577         public abstract BackendTester createBackendTester(boolean isSystem);
1578         public abstract  BackendTester createBackendTester(boolean isSystem,
1579                 Class<? extends java.lang.System.Logger> restrictedTo);
1580         public abstract  BackendTester createBackendTester(boolean isSystem,
1581                 Class<? extends java.lang.System.Logger> restrictedTo,
1582                 ResourceBundle bundle);
1583         public abstract  BackendTester createBackendTester(boolean isSystem,
1584                 ResourceBundle bundle);
1585     }
1586 
1587     public static class JULBackendTesterFactory extends BackendTesterFactory {
1588 
1589         @Override
1590         public BackendTester createBackendTester(boolean isSystem) {
1591             return new JULBackendTester(isSystem);
1592         }
1593 
1594         @Override
1595         public BackendTester createBackendTester(boolean isSystem,
1596                 Class<? extends java.lang.System.Logger> restrictedTo) {
1597             return new JULBackendTester(isSystem, restrictedTo);
1598         }
1599 
1600         @Override
1601         public BackendTester createBackendTester(boolean isSystem,
1602                 Class<? extends java.lang.System.Logger> restrictedTo,
1603                 ResourceBundle bundle) {
1604             return new JULBackendTester(isSystem, restrictedTo, bundle);
1605         }
1606 
1607         @Override
1608         public BackendTester createBackendTester(boolean isSystem,
1609                 ResourceBundle bundle) {
1610             return new JULBackendTester(isSystem, bundle);
1611         }
1612     }
1613 
1614     public static class CustomLoggerFinder extends LoggerFinder {
1615 
1616         static enum CustomLevel { OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL };
1617         static CustomLevel[] customLevelMap = { CustomLevel.ALL,
1618             CustomLevel.TRACE, CustomLevel.DEBUG, CustomLevel.INFO,
1619             CustomLevel.WARN, CustomLevel.ERROR, CustomLevel.OFF
1620         };
1621         static class CustomLogRecord {
1622             public final CustomLevel logLevel;
1623             public final java.lang.System.Logger logger;
1624             public final String msg;
1625             public final Object[] params;
1626             public final Throwable thrown;
1627             public final ResourceBundle bundle;
1628 
1629             CustomLogRecord(java.lang.System.Logger producer,
1630                     CustomLevel level, String msg) {
1631                 this(producer, level, msg, (ResourceBundle)null, (Throwable)null, (Object[])null);
1632             }
1633 
1634             CustomLogRecord(java.lang.System.Logger producer,
1635                     CustomLevel level, String msg, ResourceBundle bundle,
1636                     Throwable thrown, Object... params) {
1637                 this.logger   = producer;
1638                 this.logLevel = level;
1639                 this.msg = msg;
1640                 this.params = params;
1641                 this.thrown = thrown;
1642                 this.bundle = bundle;
1643             }
1644         }
1645 
1646         static final List<CustomLogRecord>  records =
1647                 Collections.synchronizedList(new ArrayList<>());
1648 
1649         static class CustomLogger implements java.lang.System.Logger {
1650 
1651             final String name;
1652             volatile CustomLevel level;
1653             CustomLogger(String name) {
1654                 this.name = name;
1655                 this.level = CustomLevel.INFO;
1656             }
1657 
1658             @Override
1659             public String getName() {
1660                 return name;
1661             }
1662 
1663             public void setLevel(CustomLevel level) {
1664                 this.level = level;
1665             }
1666 
1667 
1668             @Override
1669             public boolean isLoggable(java.lang.System.Logger.Level level) {
1670 
1671                 return this.level != CustomLevel.OFF && this.level.ordinal()
1672                         >= customLevelMap[level.ordinal()].ordinal();
1673             }
1674 
1675             @Override
1676             public void log(java.lang.System.Logger.Level level, ResourceBundle bundle, String key, Throwable thrown) {
1677                 if (isLoggable(level)) {
1678                     records.add(new CustomLogRecord(this, customLevelMap[level.ordinal()],
1679                               key, bundle, thrown));
1680                 }
1681             }
1682 
1683             @Override
1684             public void log(java.lang.System.Logger.Level level, ResourceBundle bundle, String format, Object... params) {
1685                 if (isLoggable(level)) {
1686                     records.add(new CustomLogRecord(this, customLevelMap[level.ordinal()],
1687                               format, bundle, null, params));
1688                 }
1689             }
1690 
1691         }
1692 
1693         final Map<String, java.lang.System.Logger> applicationLoggers =
1694                 Collections.synchronizedMap(new HashMap<>());
1695         final Map<String, java.lang.System.Logger> systemLoggers =
1696                 Collections.synchronizedMap(new HashMap<>());
1697 
1698         @Override
1699         public java.lang.System.Logger getLogger(String name, Class<?> caller) {
1700             ClassLoader callerLoader = caller.getClassLoader();
1701             if (callerLoader == null) {
1702                 systemLoggers.putIfAbsent(name, new CustomLogger(name));
1703                 return systemLoggers.get(name);
1704             } else {
1705                 applicationLoggers.putIfAbsent(name, new CustomLogger(name));
1706                 return applicationLoggers.get(name);
1707             }
1708         }
1709 
1710         CustomLevel fromJul(Level level) {
1711             if (level.intValue() == Level.OFF.intValue()) {
1712                 return CustomLevel.OFF;
1713             } else if (level.intValue() > Level.SEVERE.intValue()) {
1714                 return CustomLevel.ERROR;
1715             } else if (level.intValue() > Level.WARNING.intValue()) {
1716                 return CustomLevel.ERROR;
1717             } else if (level.intValue() > Level.INFO.intValue()) {
1718                 return CustomLevel.WARN;
1719             } else if (level.intValue() > Level.CONFIG.intValue()) {
1720                 return CustomLevel.INFO;
1721             } else if (level.intValue() > Level.FINER.intValue()) {
1722                 return CustomLevel.DEBUG;
1723             } else if (level.intValue() > Level.FINEST.intValue()) {
1724                 return CustomLevel.TRACE;
1725             } else if (level.intValue() == Level.ALL.intValue()) {
1726                 return CustomLevel.ALL;
1727             } else {
1728                 return CustomLevel.TRACE;
1729             }
1730         }
1731 
1732         Level toJul(CustomLevel level) {
1733             switch(level) {
1734                 case OFF: return Level.OFF;
1735                 case FATAL: return Level.SEVERE;
1736                 case ERROR: return Level.SEVERE;
1737                 case WARN: return Level.WARNING;
1738                 case INFO: return Level.INFO;
1739                 case DEBUG: return Level.FINE;
1740                 case TRACE: return Level.FINER;
1741                 case ALL: return Level.ALL;
1742                 default: throw new InternalError("No such level: "+level);
1743             }
1744         }
1745 
1746     }
1747 
1748     public static class CustomBackendTester extends
1749             BackendTester<CustomLoggerFinder.CustomLogRecord> {
1750 
1751         public final CustomLoggerFinder provider;
1752 
1753         public CustomBackendTester(boolean isSystem) {
1754             this(isSystem, null, null);
1755         }
1756 
1757         public CustomBackendTester(boolean isSystem,
1758                 Class<? extends java.lang.System.Logger> restrictedTo) {
1759             this(isSystem, restrictedTo, null);
1760         }
1761 
1762         public CustomBackendTester(boolean isSystem,
1763                 ResourceBundle localized) {
1764             this(isSystem, null, localized);
1765         }
1766 
1767         public CustomBackendTester(boolean isSystem,
1768                 Class<? extends java.lang.System.Logger> restrictedTo,
1769                 ResourceBundle localized) {
1770             super(isSystem, restrictedTo, localized);
1771             provider = (CustomLoggerFinder)java.lang.System.LoggerFinder.getLoggerFinder();
1772         }
1773 
1774         @Override
1775         public java.lang.System.Logger convert(java.lang.System.Logger logger) {
1776             if (restrictedTo != null && restrictedTo.isInstance(logger)) {
1777                 return logger;
1778             } else if (restrictedTo == jdkLoggerClass) {
1779                 return logger;
1780             } else {
1781                 return java.lang.System.Logger.class.cast(
1782                         sun.util.logging.PlatformLoggerBridge.convert(logger));
1783             }
1784         }
1785 
1786         class CustomBackendAdaptor extends BackendAdaptor {
1787 
1788             @Override
1789             public String getLoggerName(CustomLoggerFinder.CustomLogRecord res) {
1790                 return res.logger.getName();
1791             }
1792 
1793             @Override
1794             public CustomLoggerFinder.CustomLevel getLevel(CustomLoggerFinder.CustomLogRecord res) {
1795                 return res.logLevel;
1796             }
1797 
1798             @Override
1799             public String getMessage(CustomLoggerFinder.CustomLogRecord res) {
1800                 return res.msg;
1801             }
1802 
1803             @Override // we don't support source class name in our custom provider implementation
1804             public String getSourceClassName(CustomLoggerFinder.CustomLogRecord res) {
1805                 return null;
1806             }
1807 
1808             @Override // we don't support source method name in our custom provider implementation
1809             public String getSourceMethodName(CustomLoggerFinder.CustomLogRecord res) {
1810                 return null;
1811             }
1812 
1813             @Override
1814             public Throwable getThrown(CustomLoggerFinder.CustomLogRecord res) {
1815                 return res.thrown;
1816             }
1817 
1818             @Override
1819             public ResourceBundle getResourceBundle(CustomLoggerFinder.CustomLogRecord res) {
1820                 return res.bundle;
1821             }
1822 
1823             @Override
1824             public void setLevel(java.lang.System.Logger logger, Level level) {
1825                 final CustomLoggerFinder.CustomLogger l =
1826                         (CustomLoggerFinder.CustomLogger)
1827                         (isSystem ? provider.getLogger(logger.getName(), Thread.class) :
1828                         provider.getLogger(logger.getName(), LoggerFinderBackendTest.class));
1829                 l.setLevel(provider.fromJul(level));
1830             }
1831             @Override
1832             public void setLevel(java.lang.System.Logger logger,
1833                     java.lang.System.Logger.Level level) {
1834                 setLevel(logger, toJUL(level));
1835             }
1836 
1837             CustomLoggerFinder.CustomLevel getLevel(java.lang.System.Logger logger) {
1838                 final CustomLoggerFinder.CustomLogger l =
1839                         (CustomLoggerFinder.CustomLogger)
1840                         (isSystem ? provider.getLogger(logger.getName(), Thread.class) :
1841                         provider.getLogger(logger.getName(), LoggerFinderBackendTest.class));
1842                 return l.level;
1843             }
1844 
1845             @Override
1846             public List<CustomLoggerFinder.CustomLogRecord> getBackendRecords() {
1847                 return CustomLoggerFinder.records;
1848             }
1849 
1850             @Override
1851             public void resetBackendRecords() {
1852                 CustomLoggerFinder.records.clear();
1853             }
1854 
1855             @Override
1856             public boolean shouldBeLoggable(Levels level, Level loggerLevel) {
1857                 return loggerLevel != Level.OFF &&
1858                        fromLevels(level).ordinal() <= provider.fromJul(loggerLevel).ordinal();
1859             }
1860 
1861             @Override
1862             public boolean isLoggable(java.lang.System.Logger logger, Level l) {
1863                 return super.isLoggable(logger, l);
1864             }
1865 
1866             @Override
1867             public boolean shouldBeLoggable(Level logLevel, Level loggerLevel) {
1868                 return loggerLevel != Level.OFF &&
1869                         provider.fromJul(logLevel).ordinal() <= provider.fromJul(loggerLevel).ordinal();
1870             }
1871 
1872             @Override // we don't support source class name in our custom provider implementation
1873             public String getCallerClassName(Levels level, String clazz) {
1874                 return null;
1875             }
1876 
1877             @Override // we don't support source method name in our custom provider implementation
1878             public String getCallerMethodName(Levels level, String method) {
1879                 return null;
1880             }
1881 
1882             @Override // we don't support source class name in our custom provider implementation
1883             public String getCallerClassName(MethodInvoker<?,?> logMethod, String clazz) {
1884                 return null;
1885             }
1886 
1887             @Override // we don't support source method name in our custom provider implementation
1888             public String getCallerMethodName(MethodInvoker<?,?> logMethod, String method) {
1889                 return null;
1890             }
1891 
1892             @Override
1893             public CustomLoggerFinder.CustomLevel getMappedLevel(Object level) {
1894                 if (level instanceof java.lang.System.Logger.Level) {
1895                     final int index = ((java.lang.System.Logger.Level)level).ordinal();
1896                     return CustomLoggerFinder.customLevelMap[index];
1897                 } else if (level instanceof Level) {
1898                     return provider.fromJul((Level)level);
1899                 }
1900                 return (CustomLoggerFinder.CustomLevel) level;
1901             }
1902 
1903             CustomLoggerFinder.CustomLevel fromLevels(Levels level) {
1904                 switch(level) {
1905                     case SEVERE:
1906                         return CustomLoggerFinder.CustomLevel.ERROR;
1907                     case WARNING:
1908                         return CustomLoggerFinder.CustomLevel.WARN;
1909                     case INFO:
1910                         return CustomLoggerFinder.CustomLevel.INFO;
1911                     case CONFIG: case FINE:
1912                         return CustomLoggerFinder.CustomLevel.DEBUG;
1913                     case FINER:  case FINEST:
1914                         return CustomLoggerFinder.CustomLevel.TRACE;
1915                 }
1916                 throw new InternalError("No such level "+level);
1917             }
1918 
1919         }
1920 
1921         @Override
1922         BackendAdaptor adaptor() {
1923             return new CustomBackendAdaptor();
1924         }
1925 
1926     }
1927 
1928     public static class CustomBackendTesterFactory extends BackendTesterFactory {
1929 
1930         @Override
1931         public BackendTester createBackendTester(boolean isSystem) {
1932             return new CustomBackendTester(isSystem);
1933         }
1934 
1935         @Override
1936         public BackendTester createBackendTester(boolean isSystem,
1937                 Class<? extends java.lang.System.Logger> restrictedTo) {
1938             return new CustomBackendTester(isSystem, restrictedTo);
1939         }
1940 
1941         @Override
1942         public BackendTester createBackendTester(boolean isSystem,
1943                 Class<? extends java.lang.System.Logger> restrictedTo,
1944                 ResourceBundle bundle) {
1945             return new CustomBackendTester(isSystem, restrictedTo, bundle);
1946         }
1947 
1948         @Override
1949         public BackendTester createBackendTester(boolean isSystem,
1950                 ResourceBundle bundle) {
1951             return new CustomBackendTester(isSystem, bundle);
1952         }
1953     }
1954 
1955     static final Method getLazyLogger;
1956     static final Method accessLoggerFinder;
1957     static {
1958         // sun.util.logger.LazyLoggers.getLazyLogger(name, caller);
1959         try {
1960             Class<?> lazyLoggers = sun.util.logger.LazyLoggers.class;
1961             getLazyLogger = lazyLoggers.getMethod("getLazyLogger",
1962                     String.class, Class.class);
1963             getLazyLogger.setAccessible(true);
1964             Class<?> loggerFinderLoader =
1965                     Class.forName("java.lang.System$LoggerFinder$LoggerFinderLoader");
1966             accessLoggerFinder = loggerFinderLoader.getDeclaredMethod("spi");
1967             accessLoggerFinder.setAccessible(true);
1968         } catch (Throwable ex) {
1969             throw new ExceptionInInitializerError(ex);
1970         }
1971     }
1972 
1973     static java.lang.System.Logger getSystemLogger(String name, Class<?> caller) throws Exception {
1974         try {
1975             return java.lang.System.Logger.class.cast(getLazyLogger.invoke(null, name, caller));
1976         } catch (InvocationTargetException x) {
1977             Throwable t = x.getTargetException();
1978             if (t instanceof Exception) {
1979                 throw (Exception)t;
1980             } else {
1981                 throw (Error)t;
1982             }
1983         }
1984     }
1985     static java.lang.System.Logger getSystemLogger(String name,
1986             ResourceBundle bundle, Class<?> caller) throws Exception {
1987         try {
1988             LoggerFinder provider = LoggerFinder.class.cast(accessLoggerFinder.invoke(null));
1989             return provider.getLocalizedLogger(name, bundle, caller);
1990         } catch (InvocationTargetException x) {
1991             Throwable t = x.getTargetException();
1992             if (t instanceof Exception) {
1993                 throw (Exception)t;
1994             } else {
1995                 throw (Error)t;
1996             }
1997         }
1998     }
1999 
2000     // Change this to 'true' to get more traces...
2001     public static boolean verbose = false;
2002 
2003     public static void main(String[] argv) throws Exception {
2004 
2005         final AtomicInteger nb = new AtomicInteger(0);
2006         final boolean hidesProvider = Boolean.getBoolean("test.logger.hidesProvider");
2007         System.out.println(ClassLoader.getSystemClassLoader());
2008         final BackendTesterFactory factory;
2009         if (java.lang.System.LoggerFinder.getLoggerFinder() instanceof CustomLoggerFinder) {
2010             if (hidesProvider) {
2011                 System.err.println("Custom backend "
2012                         + java.lang.System.LoggerFinder.getLoggerFinder()
2013                         + " should have been hidden!");
2014                 throw new RuntimeException(
2015                         "Custom backend should have been hidden: "
2016                         + "check value of java.system.class.loader property");
2017             }
2018             System.out.println("Using custom backend");
2019             factory = new CustomBackendTesterFactory();
2020         } else {
2021             if (!hidesProvider) {
2022                 System.err.println("Default JUL backend "
2023                         + java.lang.System.LoggerFinder.getLoggerFinder()
2024                         + " should have been hidden!");
2025                 throw new RuntimeException(
2026                         "Default JUL backend should have been hidden: "
2027                         + "check value of java.system.class.loader property");
2028             }
2029             System.out.println("Using JUL backend");
2030             factory = new JULBackendTesterFactory();
2031         }
2032 
2033         testBackend(nb, factory);
2034     }
2035 
2036     public static void testBackend(AtomicInteger nb, BackendTesterFactory factory) throws Exception {
2037 
2038         // Tests all level specifics methods with loggers configured with
2039         // all possible levels and loggers obtained with all possible
2040         // entry points from LoggerFactory and JdkLoggerFactory, with
2041         // JUL as backend.
2042 
2043         // Test a simple application logger with JUL backend
2044         final BackendTester tester = factory.createBackendTester(false);
2045         final java.lang.System.Logger logger =
2046                 java.lang.System.LoggerFinder.getLoggerFinder()
2047                         .getLogger("foo", LoggerFinderBackendTest.class);
2048 
2049         testLogger(tester, logger, nb);
2050 
2051         // Test a simple system logger with JUL backend
2052         final java.lang.System.Logger system =
2053                 java.lang.System.LoggerFinder.getLoggerFinder()
2054                         .getLogger("bar", Thread.class);
2055         final BackendTester systemTester = factory.createBackendTester(true);
2056         testLogger(systemTester, system, nb);
2057 
2058         // Test a localized application logger with null resource bundle and
2059         // JUL backend
2060         final java.lang.System.Logger noBundleLogger =
2061                 java.lang.System.LoggerFinder.getLoggerFinder()
2062                         .getLocalizedLogger("baz", null, LoggerFinderBackendTest.class);
2063         final BackendTester noBundleTester =
2064                 factory.createBackendTester(false, spiLoggerClass);
2065         testLogger(noBundleTester, noBundleLogger, nb);
2066 
2067         // Test a localized system logger with null resource bundle and JUL
2068         // backend
2069         final java.lang.System.Logger noBundleSysLogger =
2070                 java.lang.System.LoggerFinder.getLoggerFinder()
2071                         .getLocalizedLogger("oof", null, Thread.class);
2072         final BackendTester noBundleSysTester =
2073                 factory.createBackendTester(true, spiLoggerClass);
2074         testLogger(noBundleSysTester, noBundleSysLogger, nb);
2075 
2076         // Test a localized application logger with null resource bundle and
2077         // JUL backend
2078         try {
2079             System.getLogger("baz", null);
2080             throw new RuntimeException("Expected NullPointerException not thrown");
2081         } catch (NullPointerException x) {
2082             System.out.println("System.Loggers.getLogger(\"baz\", null): got expected " + x);
2083         }
2084         final java.lang.System.Logger noBundleExtensionLogger =
2085                 getSystemLogger("baz", null, LoggerFinderBackendTest.class);
2086         final BackendTester noBundleExtensionTester =
2087                 factory.createBackendTester(false, jdkLoggerClass);
2088         testLogger(noBundleExtensionTester, noBundleExtensionLogger, nb);
2089 
2090         // Test a simple system logger with JUL backend
2091         final java.lang.System.Logger sysExtensionLogger =
2092                 getSystemLogger("oof", Thread.class);
2093         final BackendTester sysExtensionTester =
2094                 factory.createBackendTester(true, jdkLoggerClass);
2095         testLogger(sysExtensionTester, sysExtensionLogger, nb);
2096 
2097         // Test a localized system logger with null resource bundle and JUL
2098         // backend
2099         final java.lang.System.Logger noBundleSysExtensionLogger =
2100                 getSystemLogger("oof", null, Thread.class);
2101         final BackendTester noBundleSysExtensionTester =
2102                 factory.createBackendTester(true, jdkLoggerClass);
2103         testLogger(noBundleSysExtensionTester, noBundleSysExtensionLogger, nb);
2104 
2105         // Test a localized application logger converted to JDK with null
2106         // resource bundle and JUL backend
2107         final java.lang.System.Logger noBundleConvertedLogger =
2108                 (java.lang.System.Logger)
2109                 sun.util.logging.PlatformLoggerBridge.convert(noBundleLogger);
2110         final BackendTester noBundleJdkTester = factory.createBackendTester(false);
2111         testLogger(noBundleJdkTester, noBundleConvertedLogger, nb);
2112 
2113         // Test a localized system logger converted to JDK with null resource
2114         // bundle and JUL backend
2115         final java.lang.System.Logger noBundleConvertedSysLogger =
2116                 (java.lang.System.Logger)
2117                 sun.util.logging.PlatformLoggerBridge.convert(noBundleSysLogger);
2118         final BackendTester noBundleJdkSysTester = factory.createBackendTester(true);
2119         testLogger(noBundleJdkSysTester, noBundleConvertedSysLogger, nb);
2120 
2121         // Test a localized application logger with resource bundle and JUL
2122         // backend
2123         final ResourceBundle bundle =
2124                 ResourceBundle.getBundle(ResourceBundeLocalized.class.getName());
2125         final java.lang.System.Logger bundleLogger =
2126                 java.lang.System.LoggerFinder.getLoggerFinder()
2127                         .getLocalizedLogger("toto", bundle, LoggerFinderBackendTest.class);
2128         final BackendTester bundleTester =
2129                 factory.createBackendTester(false, spiLoggerClass, bundle);
2130         testLogger(bundleTester, bundleLogger, nb);
2131 
2132         // Test a localized system logger with resource bundle and JUL backend
2133         final java.lang.System.Logger bundleSysLogger =
2134                 java.lang.System.LoggerFinder.getLoggerFinder()
2135                         .getLocalizedLogger("titi", bundle, Thread.class);
2136         final BackendTester bundleSysTester =
2137                 factory.createBackendTester(true, spiLoggerClass, bundle);
2138         testLogger(bundleSysTester, bundleSysLogger, nb);
2139 
2140         // Test a localized Jdk application logger with resource bundle and JUL
2141         // backend
2142         final java.lang.System.Logger bundleExtensionLogger =
2143                 System.getLogger("tita", bundle);
2144         final BackendTester bundleExtensionTester =
2145                 factory.createBackendTester(false, jdkLoggerClass, bundle);
2146         testLogger(bundleExtensionTester, bundleExtensionLogger, nb);
2147 
2148         // Test a localized Jdk system logger with resource bundle and JUL
2149         // backend
2150         final java.lang.System.Logger bundleExtensionSysLogger =
2151                 getSystemLogger("titu", bundle, Thread.class);
2152         final BackendTester bundleExtensionSysTester =
2153                 factory.createBackendTester(true, jdkLoggerClass, bundle);
2154         testLogger(bundleExtensionSysTester, bundleExtensionSysLogger, nb);
2155 
2156         // Test a localized application logger converted to JDK with resource
2157         // bundle and JUL backend
2158         final BackendTester bundleJdkTester =
2159                 factory.createBackendTester(false, bundle);
2160         final java.lang.System.Logger bundleConvertedLogger =
2161                 (java.lang.System.Logger)
2162                 sun.util.logging.PlatformLoggerBridge.convert(bundleLogger);
2163         testLogger(bundleJdkTester, bundleConvertedLogger, nb);
2164 
2165         // Test a localized Jdk system logger converted to JDK with resource
2166         // bundle and JUL backend
2167         final BackendTester bundleJdkSysTester =
2168                 factory.createBackendTester(true, bundle);
2169         final java.lang.System.Logger bundleConvertedSysLogger =
2170                 (java.lang.System.Logger)
2171                 sun.util.logging.PlatformLoggerBridge.convert(bundleSysLogger);
2172         testLogger(bundleJdkSysTester, bundleConvertedSysLogger, nb);
2173 
2174         // Now need to add tests for all the log/logp/logrb methods...
2175 
2176     }
2177 
2178     private static class FooObj {
2179         final String s;
2180         FooObj(String s) {
2181             this.s = s;
2182         }
2183 
2184         @Override
2185         public String toString() {
2186             return super.toString() +": "+s;
2187         }
2188 
2189     }
2190 
2191     public static void testLogger(BackendTester tester,
2192             java.lang.System.Logger spiLogger, AtomicInteger nb) {
2193 
2194         // Test all level-specific method forms:
2195         // fatal(...) error(...) severe(...) etc...
2196         java.lang.System.Logger jdkLogger = tester.convert(spiLogger);
2197         for (Levels l : Levels.values()) {
2198             java.lang.System.Logger logger =
2199                     l.definingClass.equals(spiLoggerClass) ? spiLogger : jdkLogger;
2200             tester.testLevel(l, logger, l.method + "[" + logger.getName()+ "]-"
2201                     + nb.incrementAndGet());
2202             tester.testLevel(l, logger, l.method + "[" + logger.getName()+ "]-"
2203                     + nb.incrementAndGet(),
2204                     bundleParam);
2205             final int nbb = nb.incrementAndGet();
2206             tester.testLevel(l, logger, () -> l.method + "[" + logger.getName()
2207                     + "]-" + nbb);
2208         }
2209         for (Levels l : Levels.values()) {
2210             java.lang.System.Logger logger =
2211                     l.definingClass.equals(spiLoggerClass) ? spiLogger : jdkLogger;
2212             tester.testLevel(l, logger,
2213                     l.method + "[" + logger.getName()+ "]({0},{1})-"
2214                     + nb.incrementAndGet(),
2215                     "One", "Two");
2216             tester.testLevel(l, logger,
2217                     l.method + "[" + logger.getName()+ "]({0},{1})-"
2218                     + nb.incrementAndGet(),
2219                     bundleParam, "One", "Two");
2220         }
2221         final Throwable thrown = new RuntimeException("Test");
2222         for (Levels l : Levels.values()) {
2223             java.lang.System.Logger logger =
2224                     l.definingClass.equals(spiLoggerClass) ? spiLogger : jdkLogger;
2225             tester.testLevel(l, logger, l.method + "[" + logger.getName()+ "]-"
2226                     + nb.incrementAndGet(),
2227                     thrown);
2228             tester.testLevel(l, logger, l.method + "[" + logger.getName()+ "]-"
2229                     + nb.incrementAndGet(),
2230                     bundleParam, thrown);
2231             final int nbb = nb.incrementAndGet();
2232             tester.testLevel(l, logger, ()->l.method + "[" + logger.getName()+ "]-"
2233                     + nbb, thrown);
2234         }
2235 
2236         java.lang.System.Logger logger = jdkLogger;
2237 
2238          // test System.Logger methods
2239        tester.testSpiLog(logger, "[" + logger.getName()+ "]-"
2240                 + nb.incrementAndGet());
2241         tester.testSpiLog(logger, bundleParam, "[" + logger.getName()+ "]-"
2242                 + nb.incrementAndGet());
2243         tester.testSpiLog(logger, "[" + logger.getName()+ "]-({0},{1})"
2244                 + nb.incrementAndGet(), "One", "Two");
2245         tester.testSpiLog(logger, bundleParam, "[" + logger.getName()+ "]-({0},{1})"
2246                 + nb.incrementAndGet(), "One", "Two");
2247         tester.testSpiLog(logger, "[" + logger.getName()+ "]-"
2248                 + nb.incrementAndGet(), thrown);
2249         tester.testSpiLog(logger, bundleParam, "[" + logger.getName()+ "]-"
2250                 + nb.incrementAndGet(), thrown);
2251         final int nbb01 = nb.incrementAndGet();
2252         tester.testSpiLog(logger, () -> "[" + logger.getName()+ "]-" + nbb01);
2253         final int nbb02 = nb.incrementAndGet();
2254         tester.testSpiLog(logger, thrown, () -> "[" + logger.getName()+ "]-" + nbb02);
2255         final int nbb03 = nb.incrementAndGet();
2256         tester.testSpiLog(logger, new FooObj("[" + logger.getName()+ "]-" + nbb03));
2257 
2258         // Test all log method forms:
2259         // jdk.internal.logging.Logger.log(...)
2260         tester.testLog(logger, "[" + logger.getName()+ "]-"
2261                 + nb.incrementAndGet());
2262         tester.testLogrb(logger, bundleParam, "[" + logger.getName()+ "]-"
2263                 + nb.incrementAndGet());
2264         tester.testLog(logger, "[" + logger.getName()+ "]-({0},{1})"
2265                 + nb.incrementAndGet(), "One", "Two");
2266         tester.testLogrb(logger, bundleParam, "[" + logger.getName()+ "]-({0},{1})"
2267                 + nb.incrementAndGet(), "One", "Two");
2268         tester.testLog(logger, "[" + logger.getName()+ "]-"
2269                 + nb.incrementAndGet(), thrown);
2270         tester.testLogrb(logger, bundleParam, "[" + logger.getName()+ "]-"
2271                 + nb.incrementAndGet(), thrown);
2272         final int nbb1 = nb.incrementAndGet();
2273         tester.testLog(logger, () -> "[" + logger.getName()+ "]-" + nbb1);
2274         final int nbb2 = nb.incrementAndGet();
2275         tester.testLog(logger, thrown, () -> "[" + logger.getName()+ "]-" + nbb2);
2276 
2277         // Test all logp method forms
2278         // jdk.internal.logging.Logger.logp(...)
2279         tester.testLogp(logger, "clazz" + nb.incrementAndGet(),
2280                 "method" + nb.incrementAndGet(),
2281                 "[" + logger.getName()+ "]-"
2282                 + nb.incrementAndGet());
2283         tester.testLogrb(logger, "clazz" + nb.incrementAndGet(),
2284                 "method" + nb.incrementAndGet(), bundleParam,
2285                 "[" + logger.getName()+ "]-"
2286                 + nb.incrementAndGet());
2287         tester.testLogp(logger, "clazz" + nb.incrementAndGet(),
2288                 "method" + nb.incrementAndGet(),
2289                 "[" + logger.getName()+ "]-({0},{1})"
2290                 + nb.incrementAndGet(), "One", "Two");
2291         tester.testLogrb(logger, "clazz" + nb.incrementAndGet(),
2292                 "method" + nb.incrementAndGet(), bundleParam,
2293                 "[" + logger.getName()+ "]-({0},{1})"
2294                 + nb.incrementAndGet(), "One", "Two");
2295         tester.testLogp(logger, "clazz" + nb.incrementAndGet(),
2296                 "method" + nb.incrementAndGet(),
2297                 "[" + logger.getName()+ "]-"
2298                 + nb.incrementAndGet(), thrown);
2299         tester.testLogrb(logger, "clazz" + nb.incrementAndGet(),
2300                 "method" + nb.incrementAndGet(), bundleParam,
2301                 "[" + logger.getName()+ "]-"
2302                 + nb.incrementAndGet(), thrown);
2303         final int nbb3 = nb.incrementAndGet();
2304         tester.testLogp(logger, "clazz" + nb.incrementAndGet(),
2305                 "method" + nb.incrementAndGet(),
2306                 () -> "[" + logger.getName()+ "]-" + nbb3);
2307         final int nbb4 = nb.incrementAndGet();
2308         tester.testLogp(logger, "clazz" + nb.incrementAndGet(),
2309                 "method" + nb.incrementAndGet(),
2310                 thrown, () -> "[" + logger.getName()+ "]-" + nbb4);
2311     }
2312 
2313 }