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