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