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