Logger.java revision 16177:89ef4b822745
1/*
2 * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26
27package java.util.logging;
28
29import java.lang.ref.WeakReference;
30import java.lang.reflect.Module;
31import java.security.AccessController;
32import java.security.PrivilegedAction;
33import java.util.ArrayList;
34import java.util.Iterator;
35import java.util.Locale;
36import java.util.MissingResourceException;
37import java.util.Objects;
38import java.util.ResourceBundle;
39import java.util.concurrent.CopyOnWriteArrayList;
40import java.util.function.Supplier;
41
42import jdk.internal.misc.JavaUtilResourceBundleAccess;
43import jdk.internal.misc.SharedSecrets;
44import jdk.internal.reflect.CallerSensitive;
45import jdk.internal.reflect.Reflection;
46import static jdk.internal.logger.DefaultLoggerFinder.isSystem;
47
48/**
49 * A Logger object is used to log messages for a specific
50 * system or application component.  Loggers are normally named,
51 * using a hierarchical dot-separated namespace.  Logger names
52 * can be arbitrary strings, but they should normally be based on
53 * the package name or class name of the logged component, such
54 * as java.net or javax.swing.  In addition it is possible to create
55 * "anonymous" Loggers that are not stored in the Logger namespace.
56 * <p>
57 * Logger objects may be obtained by calls on one of the getLogger
58 * factory methods.  These will either create a new Logger or
59 * return a suitable existing Logger. It is important to note that
60 * the Logger returned by one of the {@code getLogger} factory methods
61 * may be garbage collected at any time if a strong reference to the
62 * Logger is not kept.
63 * <p>
64 * Logging messages will be forwarded to registered Handler
65 * objects, which can forward the messages to a variety of
66 * destinations, including consoles, files, OS logs, etc.
67 * <p>
68 * Each Logger keeps track of a "parent" Logger, which is its
69 * nearest existing ancestor in the Logger namespace.
70 * <p>
71 * Each Logger has a "Level" associated with it.  This reflects
72 * a minimum Level that this logger cares about.  If a Logger's
73 * level is set to {@code null}, then its effective level is inherited
74 * from its parent, which may in turn obtain it recursively from its
75 * parent, and so on up the tree.
76 * <p>
77 * The log level can be configured based on the properties from the
78 * logging configuration file, as described in the description
79 * of the LogManager class.  However it may also be dynamically changed
80 * by calls on the Logger.setLevel method.  If a logger's level is
81 * changed the change may also affect child loggers, since any child
82 * logger that has {@code null} as its level will inherit its
83 * effective level from its parent.
84 * <p>
85 * On each logging call the Logger initially performs a cheap
86 * check of the request level (e.g., SEVERE or FINE) against the
87 * effective log level of the logger.  If the request level is
88 * lower than the log level, the logging call returns immediately.
89 * <p>
90 * After passing this initial (cheap) test, the Logger will allocate
91 * a LogRecord to describe the logging message.  It will then call a
92 * Filter (if present) to do a more detailed check on whether the
93 * record should be published.  If that passes it will then publish
94 * the LogRecord to its output Handlers.  By default, loggers also
95 * publish to their parent's Handlers, recursively up the tree.
96 * <p>
97 * Each Logger may have a {@code ResourceBundle} associated with it.
98 * The {@code ResourceBundle} may be specified by name, using the
99 * {@link #getLogger(java.lang.String, java.lang.String)} factory
100 * method, or by value - using the {@link
101 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method.
102 * This bundle will be used for localizing logging messages.
103 * If a Logger does not have its own {@code ResourceBundle} or resource bundle
104 * name, then it will inherit the {@code ResourceBundle} or resource bundle name
105 * from its parent, recursively up the tree.
106 * <p>
107 * Most of the logger output methods take a "msg" argument.  This
108 * msg argument may be either a raw value or a localization key.
109 * During formatting, if the logger has (or inherits) a localization
110 * {@code ResourceBundle} and if the {@code ResourceBundle} has a mapping for
111 * the msg string, then the msg string is replaced by the localized value.
112 * Otherwise the original msg string is used.  Typically, formatters use
113 * java.text.MessageFormat style formatting to format parameters, so
114 * for example a format string "{0} {1}" would format two parameters
115 * as strings.
116 * <p>
117 * A set of methods alternatively take a "msgSupplier" instead of a "msg"
118 * argument.  These methods take a {@link Supplier}{@code <String>} function
119 * which is invoked to construct the desired log message only when the message
120 * actually is to be logged based on the effective log level thus eliminating
121 * unnecessary message construction. For example, if the developer wants to
122 * log system health status for diagnosis, with the String-accepting version,
123 * the code would look like:
124 * <pre>{@code
125 *
126 *  class DiagnosisMessages {
127 *    static String systemHealthStatus() {
128 *      // collect system health information
129 *      ...
130 *    }
131 *  }
132 *  ...
133 *  logger.log(Level.FINER, DiagnosisMessages.systemHealthStatus());
134 * }</pre>
135 * With the above code, the health status is collected unnecessarily even when
136 * the log level FINER is disabled. With the Supplier-accepting version as
137 * below, the status will only be collected when the log level FINER is
138 * enabled.
139 * <pre>{@code
140 *
141 *  logger.log(Level.FINER, DiagnosisMessages::systemHealthStatus);
142 * }</pre>
143 * <p>
144 * When looking for a {@code ResourceBundle}, the logger will first look at
145 * whether a bundle was specified using {@link
146 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle}, and then
147 * only whether a resource bundle name was specified through the {@link
148 * #getLogger(java.lang.String, java.lang.String) getLogger} factory method.
149 * If no {@code ResourceBundle} or no resource bundle name is found,
150 * then it will use the nearest {@code ResourceBundle} or resource bundle
151 * name inherited from its parent tree.<br>
152 * When a {@code ResourceBundle} was inherited or specified through the
153 * {@link
154 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method, then
155 * that {@code ResourceBundle} will be used. Otherwise if the logger only
156 * has or inherited a resource bundle name, then that resource bundle name
157 * will be mapped to a {@code ResourceBundle} object, using the default Locale
158 * at the time of logging.
159 * <br id="ResourceBundleMapping">When mapping resource bundle names to
160 * {@code ResourceBundle} objects, the logger will first try to use the
161 * Thread's {@linkplain java.lang.Thread#getContextClassLoader() context class
162 * loader} to map the given resource bundle name to a {@code ResourceBundle}.
163 * If the thread context class loader is {@code null}, it will try the
164 * {@linkplain java.lang.ClassLoader#getSystemClassLoader() system class loader}
165 * instead.  If the {@code ResourceBundle} is still not found, it will use the
166 * class loader of the first caller of the {@link
167 * #getLogger(java.lang.String, java.lang.String) getLogger} factory method.
168 * <p>
169 * Formatting (including localization) is the responsibility of
170 * the output Handler, which will typically call a Formatter.
171 * <p>
172 * Note that formatting need not occur synchronously.  It may be delayed
173 * until a LogRecord is actually written to an external sink.
174 * <p>
175 * The logging methods are grouped in five main categories:
176 * <ul>
177 * <li><p>
178 *     There are a set of "log" methods that take a log level, a message
179 *     string, and optionally some parameters to the message string.
180 * <li><p>
181 *     There are a set of "logp" methods (for "log precise") that are
182 *     like the "log" methods, but also take an explicit source class name
183 *     and method name.
184 * <li><p>
185 *     There are a set of "logrb" method (for "log with resource bundle")
186 *     that are like the "logp" method, but also take an explicit resource
187 *     bundle object for use in localizing the log message.
188 * <li><p>
189 *     There are convenience methods for tracing method entries (the
190 *     "entering" methods), method returns (the "exiting" methods) and
191 *     throwing exceptions (the "throwing" methods).
192 * <li><p>
193 *     Finally, there are a set of convenience methods for use in the
194 *     very simplest cases, when a developer simply wants to log a
195 *     simple string at a given log level.  These methods are named
196 *     after the standard Level names ("severe", "warning", "info", etc.)
197 *     and take a single argument, a message string.
198 * </ul>
199 * <p>
200 * For the methods that do not take an explicit source name and
201 * method name, the Logging framework will make a "best effort"
202 * to determine which class and method called into the logging method.
203 * However, it is important to realize that this automatically inferred
204 * information may only be approximate (or may even be quite wrong!).
205 * Virtual machines are allowed to do extensive optimizations when
206 * JITing and may entirely remove stack frames, making it impossible
207 * to reliably locate the calling class and method.
208 * <P>
209 * All methods on Logger are multi-thread safe.
210 * <p>
211 * <b>Subclassing Information:</b> Note that a LogManager class may
212 * provide its own implementation of named Loggers for any point in
213 * the namespace.  Therefore, any subclasses of Logger (unless they
214 * are implemented in conjunction with a new LogManager class) should
215 * take care to obtain a Logger instance from the LogManager class and
216 * should delegate operations such as "isLoggable" and "log(LogRecord)"
217 * to that instance.  Note that in order to intercept all logging
218 * output, subclasses need only override the log(LogRecord) method.
219 * All the other logging methods are implemented as calls on this
220 * log(LogRecord) method.
221 *
222 * @since 1.4
223 */
224public class Logger {
225    private static final Handler emptyHandlers[] = new Handler[0];
226    private static final int offValue = Level.OFF.intValue();
227
228    static final String SYSTEM_LOGGER_RB_NAME = "sun.util.logging.resources.logging";
229
230    // This class is immutable and it is important that it remains so.
231    private static final class LoggerBundle {
232        final String resourceBundleName; // Base name of the bundle.
233        final ResourceBundle userBundle; // Bundle set through setResourceBundle.
234        private LoggerBundle(String resourceBundleName, ResourceBundle bundle) {
235            this.resourceBundleName = resourceBundleName;
236            this.userBundle = bundle;
237        }
238        boolean isSystemBundle() {
239            return SYSTEM_LOGGER_RB_NAME.equals(resourceBundleName);
240        }
241        static LoggerBundle get(String name, ResourceBundle bundle) {
242            if (name == null && bundle == null) {
243                return NO_RESOURCE_BUNDLE;
244            } else if (SYSTEM_LOGGER_RB_NAME.equals(name) && bundle == null) {
245                return SYSTEM_BUNDLE;
246            } else {
247                return new LoggerBundle(name, bundle);
248            }
249        }
250    }
251
252    // This instance will be shared by all loggers created by the system
253    // code
254    private static final LoggerBundle SYSTEM_BUNDLE =
255            new LoggerBundle(SYSTEM_LOGGER_RB_NAME, null);
256
257    // This instance indicates that no resource bundle has been specified yet,
258    // and it will be shared by all loggers which have no resource bundle.
259    private static final LoggerBundle NO_RESOURCE_BUNDLE =
260            new LoggerBundle(null, null);
261
262    private static final JavaUtilResourceBundleAccess RB_ACCESS =
263            SharedSecrets.getJavaUtilResourceBundleAccess();
264
265    // A value class that holds the logger configuration data.
266    // This configuration can be shared between an application logger
267    // and a system logger of the same name.
268    private static final class ConfigurationData {
269
270        // The delegate field is used to avoid races while
271        // merging configuration. This will ensure that any pending
272        // configuration action on an application logger will either
273        // be finished before the merge happens, or will be forwarded
274        // to the system logger configuration after the merge is completed.
275        // By default delegate=this.
276        private volatile ConfigurationData delegate;
277
278        volatile boolean useParentHandlers;
279        volatile Filter filter;
280        volatile Level levelObject;
281        volatile int levelValue;  // current effective level value
282        final CopyOnWriteArrayList<Handler> handlers =
283            new CopyOnWriteArrayList<>();
284
285        ConfigurationData() {
286            delegate = this;
287            useParentHandlers = true;
288            levelValue = Level.INFO.intValue();
289        }
290
291        void setUseParentHandlers(boolean flag) {
292            useParentHandlers = flag;
293            if (delegate != this) {
294                // merge in progress - propagate value to system peer.
295                final ConfigurationData system = delegate;
296                synchronized (system) {
297                    system.useParentHandlers = useParentHandlers;
298                }
299            }
300        }
301
302        void setFilter(Filter f) {
303            filter = f;
304            if (delegate != this) {
305                // merge in progress - propagate value to system peer.
306                final ConfigurationData system = delegate;
307                synchronized (system) {
308                    system.filter = filter;
309                }
310            }
311        }
312
313        void setLevelObject(Level l) {
314            levelObject = l;
315            if (delegate != this) {
316                // merge in progress - propagate value to system peer.
317                final ConfigurationData system = delegate;
318                synchronized (system) {
319                    system.levelObject = levelObject;
320                }
321            }
322        }
323
324        void setLevelValue(int v) {
325            levelValue = v;
326            if (delegate != this) {
327                // merge in progress - propagate value to system peer.
328                final ConfigurationData system = delegate;
329                synchronized (system) {
330                    system.levelValue = levelValue;
331                }
332            }
333        }
334
335        void addHandler(Handler h) {
336            if (handlers.add(h)) {
337                if (delegate != this) {
338                    // merge in progress - propagate value to system peer.
339                    final ConfigurationData system = delegate;
340                    synchronized (system) {
341                        system.handlers.addIfAbsent(h);
342                    }
343                }
344            }
345        }
346
347        void removeHandler(Handler h) {
348            if (handlers.remove(h)) {
349                if (delegate != this) {
350                    // merge in progress - propagate value to system peer.
351                    final ConfigurationData system = delegate;
352                    synchronized (system) {
353                        system.handlers.remove(h);
354                    }
355                }
356            }
357        }
358
359        ConfigurationData merge(Logger systemPeer) {
360            if (!systemPeer.isSystemLogger) {
361                // should never come here
362                throw new InternalError("not a system logger");
363            }
364
365            ConfigurationData system = systemPeer.config;
366
367            if (system == this) {
368                // nothing to do
369                return system;
370            }
371
372            synchronized (system) {
373                // synchronize before checking on delegate to counter
374                // race conditions where two threads might attempt to
375                // merge concurrently
376                if (delegate == system) {
377                    // merge already performed;
378                    return system;
379                }
380
381                // publish system as the temporary delegate configuration.
382                // This should take care of potential race conditions where
383                // an other thread might attempt to call e.g. setlevel on
384                // the application logger while merge is in progress.
385                // (see implementation of ConfigurationData::setLevel)
386                delegate = system;
387
388                // merge this config object data into the system config
389                system.useParentHandlers = useParentHandlers;
390                system.filter = filter;
391                system.levelObject = levelObject;
392                system.levelValue = levelValue;
393
394                // Prevent race condition in case two threads attempt to merge
395                // configuration and add handlers at the same time. We don't want
396                // to add the same handlers twice.
397                //
398                // Handlers are created and loaded by LogManager.addLogger. If we
399                // reach here, then it means that the application logger has
400                // been created first and added with LogManager.addLogger, and the
401                // system logger was created after - and no handler has been added
402                // to it by LogManager.addLogger. Therefore, system.handlers
403                // should be empty.
404                //
405                // A non empty cfg.handlers list indicates a race condition
406                // where two threads might attempt to merge the configuration
407                // or add handlers concurrently. Though of no consequence for
408                // the other data (level etc...) this would be an issue if we
409                // added the same handlers twice.
410                //
411                for (Handler h : handlers) {
412                    if (!system.handlers.contains(h)) {
413                        systemPeer.addHandler(h);
414                    }
415                }
416                system.handlers.retainAll(handlers);
417                system.handlers.addAllAbsent(handlers);
418            }
419
420            // sanity: update effective level after merging
421            synchronized(treeLock) {
422                systemPeer.updateEffectiveLevel();
423            }
424
425            return system;
426        }
427
428    }
429
430    // The logger configuration data. Ideally, this should be final
431    // for system loggers, and replace-once for application loggers.
432    // When an application requests a logger by name, we do not know a-priori
433    // whether that corresponds to a system logger name or not.
434    // So if no system logger by that name already exists, we simply return an
435    // application logger.
436    // If a system class later requests a system logger of the same name, then
437    // the application logger and system logger configurations will be merged
438    // in a single instance of ConfigurationData that both loggers will share.
439    private volatile ConfigurationData config;
440
441    private volatile LogManager manager;
442    private String name;
443    private volatile LoggerBundle loggerBundle = NO_RESOURCE_BUNDLE;
444    private boolean anonymous;
445
446    // Cache to speed up behavior of findResourceBundle:
447    private ResourceBundle catalog;     // Cached resource bundle
448    private String catalogName;         // name associated with catalog
449    private Locale catalogLocale;       // locale associated with catalog
450
451    // The fields relating to parent-child relationships and levels
452    // are managed under a separate lock, the treeLock.
453    private static final Object treeLock = new Object();
454    // We keep weak references from parents to children, but strong
455    // references from children to parents.
456    private volatile Logger parent;    // our nearest parent.
457    private ArrayList<LogManager.LoggerWeakRef> kids;   // WeakReferences to loggers that have us as parent
458    private WeakReference<Module> callerModuleRef;
459    private final boolean isSystemLogger;
460
461    /**
462     * GLOBAL_LOGGER_NAME is a name for the global logger.
463     *
464     * @since 1.6
465     */
466    public static final String GLOBAL_LOGGER_NAME = "global";
467
468    /**
469     * Return global logger object with the name Logger.GLOBAL_LOGGER_NAME.
470     *
471     * @return global logger object
472     * @since 1.7
473     */
474    public static final Logger getGlobal() {
475        // In order to break a cyclic dependence between the LogManager
476        // and Logger static initializers causing deadlocks, the global
477        // logger is created with a special constructor that does not
478        // initialize its log manager.
479        //
480        // If an application calls Logger.getGlobal() before any logger
481        // has been initialized, it is therefore possible that the
482        // LogManager class has not been initialized yet, and therefore
483        // Logger.global.manager will be null.
484        //
485        // In order to finish the initialization of the global logger, we
486        // will therefore call LogManager.getLogManager() here.
487        //
488        // To prevent race conditions we also need to call
489        // LogManager.getLogManager() unconditionally here.
490        // Indeed we cannot rely on the observed value of global.manager,
491        // because global.manager will become not null somewhere during
492        // the initialization of LogManager.
493        // If two threads are calling getGlobal() concurrently, one thread
494        // will see global.manager null and call LogManager.getLogManager(),
495        // but the other thread could come in at a time when global.manager
496        // is already set although ensureLogManagerInitialized is not finished
497        // yet...
498        // Calling LogManager.getLogManager() unconditionally will fix that.
499
500        LogManager.getLogManager();
501
502        // Now the global LogManager should be initialized,
503        // and the global logger should have been added to
504        // it, unless we were called within the constructor of a LogManager
505        // subclass installed as LogManager, in which case global.manager
506        // would still be null, and global will be lazily initialized later on.
507
508        return global;
509    }
510
511    /**
512     * The "global" Logger object is provided as a convenience to developers
513     * who are making casual use of the Logging package.  Developers
514     * who are making serious use of the logging package (for example
515     * in products) should create and use their own Logger objects,
516     * with appropriate names, so that logging can be controlled on a
517     * suitable per-Logger granularity. Developers also need to keep a
518     * strong reference to their Logger objects to prevent them from
519     * being garbage collected.
520     *
521     * @deprecated Initialization of this field is prone to deadlocks.
522     * The field must be initialized by the Logger class initialization
523     * which may cause deadlocks with the LogManager class initialization.
524     * In such cases two class initialization wait for each other to complete.
525     * The preferred way to get the global logger object is via the call
526     * {@code Logger.getGlobal()}.
527     * For compatibility with old JDK versions where the
528     * {@code Logger.getGlobal()} is not available use the call
529     * {@code Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)}
530     * or {@code Logger.getLogger("global")}.
531     */
532    @Deprecated
533    public static final Logger global = new Logger(GLOBAL_LOGGER_NAME);
534
535    /**
536     * Protected method to construct a logger for a named subsystem.
537     * <p>
538     * The logger will be initially configured with a null Level
539     * and with useParentHandlers set to true.
540     *
541     * @param   name    A name for the logger.  This should
542     *                          be a dot-separated name and should normally
543     *                          be based on the package name or class name
544     *                          of the subsystem, such as java.net
545     *                          or javax.swing.  It may be null for anonymous Loggers.
546     * @param   resourceBundleName  name of ResourceBundle to be used for localizing
547     *                          messages for this logger.  May be null if none
548     *                          of the messages require localization.
549     * @throws MissingResourceException if the resourceBundleName is non-null and
550     *             no corresponding resource can be found.
551     */
552    protected Logger(String name, String resourceBundleName) {
553        this(name, resourceBundleName, null, LogManager.getLogManager(), false);
554    }
555
556    Logger(String name, String resourceBundleName, Module caller,
557           LogManager manager, boolean isSystemLogger) {
558        this.manager = manager;
559        this.isSystemLogger = isSystemLogger;
560        this.config = new ConfigurationData();
561        this.name = name;
562        setupResourceInfo(resourceBundleName, caller);
563    }
564
565    // Called by LogManager when a system logger is created
566    // after a user logger of the same name.
567    // Ensure that both loggers will share the same
568    // configuration.
569    final void mergeWithSystemLogger(Logger system) {
570        // sanity checks
571        if (!system.isSystemLogger
572                || anonymous
573                || name == null
574                || !name.equals(system.name)) {
575            // should never come here
576            throw new InternalError("invalid logger merge");
577        }
578        checkPermission();
579        final ConfigurationData cfg = config;
580        if (cfg != system.config) {
581            config = cfg.merge(system);
582        }
583    }
584
585    private void setCallerModuleRef(Module callerModule) {
586        if (callerModule != null) {
587            this.callerModuleRef = new WeakReference<>(callerModule);
588        }
589    }
590
591    private Module getCallerModule() {
592        return (callerModuleRef != null)
593                ? callerModuleRef.get()
594                : null;
595    }
596
597    // This constructor is used only to create the global Logger.
598    // It is needed to break a cyclic dependence between the LogManager
599    // and Logger static initializers causing deadlocks.
600    private Logger(String name) {
601        // The manager field is not initialized here.
602        this.name = name;
603        this.isSystemLogger = true;
604        config = new ConfigurationData();
605    }
606
607    // It is called from LoggerContext.addLocalLogger() when the logger
608    // is actually added to a LogManager.
609    void setLogManager(LogManager manager) {
610        this.manager = manager;
611    }
612
613    private void checkPermission() throws SecurityException {
614        if (!anonymous) {
615            if (manager == null) {
616                // Complete initialization of the global Logger.
617                manager = LogManager.getLogManager();
618            }
619            manager.checkPermission();
620        }
621    }
622
623    // Until all JDK code converted to call sun.util.logging.PlatformLogger
624    // (see 7054233), we need to determine if Logger.getLogger is to add
625    // a system logger or user logger.
626    //
627    // As an interim solution, if the immediate caller whose caller loader is
628    // null, we assume it's a system logger and add it to the system context.
629    // These system loggers only set the resource bundle to the given
630    // resource bundle name (rather than the default system resource bundle).
631    private static class SystemLoggerHelper {
632        static boolean disableCallerCheck = getBooleanProperty("sun.util.logging.disableCallerCheck");
633        private static boolean getBooleanProperty(final String key) {
634            String s = AccessController.doPrivileged(new PrivilegedAction<String>() {
635                @Override
636                public String run() {
637                    return System.getProperty(key);
638                }
639            });
640            return Boolean.valueOf(s);
641        }
642    }
643
644    private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
645        LogManager manager = LogManager.getLogManager();
646        if (!SystemLoggerHelper.disableCallerCheck) {
647            if (isSystem(caller.getModule())) {
648                return manager.demandSystemLogger(name, resourceBundleName, caller);
649            }
650        }
651        return manager.demandLogger(name, resourceBundleName, caller);
652        // ends up calling new Logger(name, resourceBundleName, caller)
653        // iff the logger doesn't exist already
654    }
655
656    /**
657     * Find or create a logger for a named subsystem.  If a logger has
658     * already been created with the given name it is returned.  Otherwise
659     * a new logger is created.
660     * <p>
661     * If a new logger is created its log level will be configured
662     * based on the LogManager configuration and it will configured
663     * to also send logging output to its parent's Handlers.  It will
664     * be registered in the LogManager global namespace.
665     * <p>
666     * Note: The LogManager may only retain a weak reference to the newly
667     * created Logger. It is important to understand that a previously
668     * created Logger with the given name may be garbage collected at any
669     * time if there is no strong reference to the Logger. In particular,
670     * this means that two back-to-back calls like
671     * {@code getLogger("MyLogger").log(...)} may use different Logger
672     * objects named "MyLogger" if there is no strong reference to the
673     * Logger named "MyLogger" elsewhere in the program.
674     *
675     * @param   name            A name for the logger.  This should
676     *                          be a dot-separated name and should normally
677     *                          be based on the package name or class name
678     *                          of the subsystem, such as java.net
679     *                          or javax.swing
680     * @return a suitable Logger
681     * @throws NullPointerException if the name is null.
682     */
683
684    // Synchronization is not required here. All synchronization for
685    // adding a new Logger object is handled by LogManager.addLogger().
686    @CallerSensitive
687    public static Logger getLogger(String name) {
688        // This method is intentionally not a wrapper around a call
689        // to getLogger(name, resourceBundleName). If it were then
690        // this sequence:
691        //
692        //     getLogger("Foo", "resourceBundleForFoo");
693        //     getLogger("Foo");
694        //
695        // would throw an IllegalArgumentException in the second call
696        // because the wrapper would result in an attempt to replace
697        // the existing "resourceBundleForFoo" with null.
698        return Logger.getLogger(name, Reflection.getCallerClass());
699    }
700
701    /**
702     * Find or create a logger for a named subsystem on behalf
703     * of the given caller.
704     *
705     * This method is called by {@link #getLogger(java.lang.String)} after
706     * it has obtained a reference to its caller's class.
707     *
708     * @param   name            A name for the logger.
709     * @param   callerClass     The class that called {@link
710     *                          #getLogger(java.lang.String)}.
711     * @return a suitable Logger for {@code callerClass}.
712     */
713    private static Logger getLogger(String name, Class<?> callerClass) {
714        return demandLogger(name, null, callerClass);
715    }
716
717    /**
718     * Find or create a logger for a named subsystem.  If a logger has
719     * already been created with the given name it is returned.  Otherwise
720     * a new logger is created.
721     *
722     * <p>
723     * If a new logger is created its log level will be configured
724     * based on the LogManager and it will configured to also send logging
725     * output to its parent's Handlers.  It will be registered in
726     * the LogManager global namespace.
727     * <p>
728     * Note: The LogManager may only retain a weak reference to the newly
729     * created Logger. It is important to understand that a previously
730     * created Logger with the given name may be garbage collected at any
731     * time if there is no strong reference to the Logger. In particular,
732     * this means that two back-to-back calls like
733     * {@code getLogger("MyLogger", ...).log(...)} may use different Logger
734     * objects named "MyLogger" if there is no strong reference to the
735     * Logger named "MyLogger" elsewhere in the program.
736     * <p>
737     * If the named Logger already exists and does not yet have a
738     * localization resource bundle then the given resource bundle
739     * name is used. If the named Logger already exists and has
740     * a different resource bundle name then an IllegalArgumentException
741     * is thrown.
742     *
743     * @param   name    A name for the logger.  This should
744     *                          be a dot-separated name and should normally
745     *                          be based on the package name or class name
746     *                          of the subsystem, such as java.net
747     *                          or javax.swing
748     * @param   resourceBundleName  name of ResourceBundle to be used for localizing
749     *                          messages for this logger. May be {@code null}
750     *                          if none of the messages require localization.
751     * @return a suitable Logger
752     * @throws MissingResourceException if the resourceBundleName is non-null and
753     *             no corresponding resource can be found.
754     * @throws IllegalArgumentException if the Logger already exists and uses
755     *             a different resource bundle name; or if
756     *             {@code resourceBundleName} is {@code null} but the named
757     *             logger has a resource bundle set.
758     * @throws NullPointerException if the name is null.
759     */
760
761    // Synchronization is not required here. All synchronization for
762    // adding a new Logger object is handled by LogManager.addLogger().
763    @CallerSensitive
764    public static Logger getLogger(String name, String resourceBundleName) {
765        return Logger.getLogger(name, resourceBundleName, Reflection.getCallerClass());
766    }
767
768    /**
769     * Find or create a logger for a named subsystem on behalf
770     * of the given caller.
771     *
772     * This method is called by {@link
773     * #getLogger(java.lang.String, java.lang.String)} after
774     * it has obtained a reference to its caller's class.
775     *
776     * @param   name            A name for the logger.
777     * @param   resourceBundleName  name of ResourceBundle to be used for localizing
778     *                          messages for this logger. May be {@code null}
779     *                          if none of the messages require localization.
780     * @param   callerClass     The class that called {@link
781     *                          #getLogger(java.lang.String, java.lang.String)}.
782     *                          This class will also be used for locating the
783     *                          resource bundle if {@code resourceBundleName} is
784     *                          not {@code null}.
785     * @return a suitable Logger for {@code callerClass}.
786     */
787    private static Logger getLogger(String name, String resourceBundleName,
788                                    Class<?> callerClass) {
789        Logger result = demandLogger(name, resourceBundleName, callerClass);
790
791        // MissingResourceException or IllegalArgumentException can be
792        // thrown by setupResourceInfo().
793        // We have to set the callers ClassLoader here in case demandLogger
794        // above found a previously created Logger.  This can happen, for
795        // example, if Logger.getLogger(name) is called and subsequently
796        // Logger.getLogger(name, resourceBundleName) is called.  In this case
797        // we won't necessarily have the correct classloader saved away, so
798        // we need to set it here, too.
799
800        result.setupResourceInfo(resourceBundleName, callerClass);
801        return result;
802    }
803
804    // package-private
805    // Add a platform logger to the system context.
806    // i.e. caller of sun.util.logging.PlatformLogger.getLogger
807    static Logger getPlatformLogger(String name) {
808        LogManager manager = LogManager.getLogManager();
809
810        // all loggers in the system context will default to
811        // the system logger's resource bundle - therefore the caller won't
812        // be needed and can be null.
813        Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME, (Module)null);
814        return result;
815    }
816
817    /**
818     * Create an anonymous Logger.  The newly created Logger is not
819     * registered in the LogManager namespace.  There will be no
820     * access checks on updates to the logger.
821     * <p>
822     * This factory method is primarily intended for use from applets.
823     * Because the resulting Logger is anonymous it can be kept private
824     * by the creating class.  This removes the need for normal security
825     * checks, which in turn allows untrusted applet code to update
826     * the control state of the Logger.  For example an applet can do
827     * a setLevel or an addHandler on an anonymous Logger.
828     * <p>
829     * Even although the new logger is anonymous, it is configured
830     * to have the root logger ("") as its parent.  This means that
831     * by default it inherits its effective level and handlers
832     * from the root logger. Changing its parent via the
833     * {@link #setParent(java.util.logging.Logger) setParent} method
834     * will still require the security permission specified by that method.
835     *
836     * @return a newly created private Logger
837     */
838    public static Logger getAnonymousLogger() {
839        return getAnonymousLogger(null);
840    }
841
842    /**
843     * Create an anonymous Logger.  The newly created Logger is not
844     * registered in the LogManager namespace.  There will be no
845     * access checks on updates to the logger.
846     * <p>
847     * This factory method is primarily intended for use from applets.
848     * Because the resulting Logger is anonymous it can be kept private
849     * by the creating class.  This removes the need for normal security
850     * checks, which in turn allows untrusted applet code to update
851     * the control state of the Logger.  For example an applet can do
852     * a setLevel or an addHandler on an anonymous Logger.
853     * <p>
854     * Even although the new logger is anonymous, it is configured
855     * to have the root logger ("") as its parent.  This means that
856     * by default it inherits its effective level and handlers
857     * from the root logger.  Changing its parent via the
858     * {@link #setParent(java.util.logging.Logger) setParent} method
859     * will still require the security permission specified by that method.
860     *
861     * @param   resourceBundleName  name of ResourceBundle to be used for localizing
862     *                          messages for this logger.
863     *          May be null if none of the messages require localization.
864     * @return a newly created private Logger
865     * @throws MissingResourceException if the resourceBundleName is non-null and
866     *             no corresponding resource can be found.
867     */
868
869    // Synchronization is not required here. All synchronization for
870    // adding a new anonymous Logger object is handled by doSetParent().
871    @CallerSensitive
872    public static Logger getAnonymousLogger(String resourceBundleName) {
873        LogManager manager = LogManager.getLogManager();
874        // cleanup some Loggers that have been GC'ed
875        manager.drainLoggerRefQueueBounded();
876        final Class<?> callerClass = Reflection.getCallerClass();
877        final Module module = callerClass.getModule();
878        Logger result = new Logger(null, resourceBundleName,
879                                   module, manager, false);
880        result.anonymous = true;
881        Logger root = manager.getLogger("");
882        result.doSetParent(root);
883        return result;
884    }
885
886    /**
887     * Retrieve the localization resource bundle for this
888     * logger.
889     * This method will return a {@code ResourceBundle} that was either
890     * set by the {@link
891     * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method or
892     * <a href="#ResourceBundleMapping">mapped from the
893     * the resource bundle name</a> set via the {@link
894     * Logger#getLogger(java.lang.String, java.lang.String) getLogger} factory
895     * method for the current default locale.
896     * <br>Note that if the result is {@code null}, then the Logger will use a resource
897     * bundle or resource bundle name inherited from its parent.
898     *
899     * @return localization bundle (may be {@code null})
900     */
901    public ResourceBundle getResourceBundle() {
902        return findResourceBundle(getResourceBundleName(), true);
903    }
904
905    /**
906     * Retrieve the localization resource bundle name for this
907     * logger.
908     * This is either the name specified through the {@link
909     * #getLogger(java.lang.String, java.lang.String) getLogger} factory method,
910     * or the {@linkplain ResourceBundle#getBaseBundleName() base name} of the
911     * ResourceBundle set through {@link
912     * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method.
913     * <br>Note that if the result is {@code null}, then the Logger will use a resource
914     * bundle or resource bundle name inherited from its parent.
915     *
916     * @return localization bundle name (may be {@code null})
917     */
918    public String getResourceBundleName() {
919        return loggerBundle.resourceBundleName;
920    }
921
922    /**
923     * Set a filter to control output on this Logger.
924     * <P>
925     * After passing the initial "level" check, the Logger will
926     * call this Filter to check if a log record should really
927     * be published.
928     *
929     * @param   newFilter  a filter object (may be null)
930     * @throws  SecurityException if a security manager exists,
931     *          this logger is not anonymous, and the caller
932     *          does not have LoggingPermission("control").
933     */
934    public void setFilter(Filter newFilter) throws SecurityException {
935        checkPermission();
936        config.setFilter(newFilter);
937    }
938
939    /**
940     * Get the current filter for this Logger.
941     *
942     * @return  a filter object (may be null)
943     */
944    public Filter getFilter() {
945        return config.filter;
946    }
947
948    /**
949     * Log a LogRecord.
950     * <p>
951     * All the other logging methods in this class call through
952     * this method to actually perform any logging.  Subclasses can
953     * override this single method to capture all log activity.
954     *
955     * @param record the LogRecord to be published
956     */
957    public void log(LogRecord record) {
958        if (!isLoggable(record.getLevel())) {
959            return;
960        }
961        Filter theFilter = config.filter;
962        if (theFilter != null && !theFilter.isLoggable(record)) {
963            return;
964        }
965
966        // Post the LogRecord to all our Handlers, and then to
967        // our parents' handlers, all the way up the tree.
968
969        Logger logger = this;
970        while (logger != null) {
971            final Handler[] loggerHandlers = isSystemLogger
972                ? logger.accessCheckedHandlers()
973                : logger.getHandlers();
974
975            for (Handler handler : loggerHandlers) {
976                handler.publish(record);
977            }
978
979            final boolean useParentHdls = isSystemLogger
980                ? logger.config.useParentHandlers
981                : logger.getUseParentHandlers();
982
983            if (!useParentHdls) {
984                break;
985            }
986
987            logger = isSystemLogger ? logger.parent : logger.getParent();
988        }
989    }
990
991    // private support method for logging.
992    // We fill in the logger name, resource bundle name, and
993    // resource bundle and then call "void log(LogRecord)".
994    private void doLog(LogRecord lr) {
995        lr.setLoggerName(name);
996        final LoggerBundle lb = getEffectiveLoggerBundle();
997        final ResourceBundle  bundle = lb.userBundle;
998        final String ebname = lb.resourceBundleName;
999        if (ebname != null && bundle != null) {
1000            lr.setResourceBundleName(ebname);
1001            lr.setResourceBundle(bundle);
1002        }
1003        log(lr);
1004    }
1005
1006
1007    //================================================================
1008    // Start of convenience methods WITHOUT className and methodName
1009    //================================================================
1010
1011    /**
1012     * Log a message, with no arguments.
1013     * <p>
1014     * If the logger is currently enabled for the given message
1015     * level then the given message is forwarded to all the
1016     * registered output Handler objects.
1017     *
1018     * @param   level   One of the message level identifiers, e.g., SEVERE
1019     * @param   msg     The string message (or a key in the message catalog)
1020     */
1021    public void log(Level level, String msg) {
1022        if (!isLoggable(level)) {
1023            return;
1024        }
1025        LogRecord lr = new LogRecord(level, msg);
1026        doLog(lr);
1027    }
1028
1029    /**
1030     * Log a message, which is only to be constructed if the logging level
1031     * is such that the message will actually be logged.
1032     * <p>
1033     * If the logger is currently enabled for the given message
1034     * level then the message is constructed by invoking the provided
1035     * supplier function and forwarded to all the registered output
1036     * Handler objects.
1037     *
1038     * @param   level   One of the message level identifiers, e.g., SEVERE
1039     * @param   msgSupplier   A function, which when called, produces the
1040     *                        desired log message
1041     * @since 1.8
1042     */
1043    public void log(Level level, Supplier<String> msgSupplier) {
1044        if (!isLoggable(level)) {
1045            return;
1046        }
1047        LogRecord lr = new LogRecord(level, msgSupplier.get());
1048        doLog(lr);
1049    }
1050
1051    /**
1052     * Log a message, with one object parameter.
1053     * <p>
1054     * If the logger is currently enabled for the given message
1055     * level then a corresponding LogRecord is created and forwarded
1056     * to all the registered output Handler objects.
1057     *
1058     * @param   level   One of the message level identifiers, e.g., SEVERE
1059     * @param   msg     The string message (or a key in the message catalog)
1060     * @param   param1  parameter to the message
1061     */
1062    public void log(Level level, String msg, Object param1) {
1063        if (!isLoggable(level)) {
1064            return;
1065        }
1066        LogRecord lr = new LogRecord(level, msg);
1067        Object params[] = { param1 };
1068        lr.setParameters(params);
1069        doLog(lr);
1070    }
1071
1072    /**
1073     * Log a message, with an array of object arguments.
1074     * <p>
1075     * If the logger is currently enabled for the given message
1076     * level then a corresponding LogRecord is created and forwarded
1077     * to all the registered output Handler objects.
1078     *
1079     * @param   level   One of the message level identifiers, e.g., SEVERE
1080     * @param   msg     The string message (or a key in the message catalog)
1081     * @param   params  array of parameters to the message
1082     */
1083    public void log(Level level, String msg, Object params[]) {
1084        if (!isLoggable(level)) {
1085            return;
1086        }
1087        LogRecord lr = new LogRecord(level, msg);
1088        lr.setParameters(params);
1089        doLog(lr);
1090    }
1091
1092    /**
1093     * Log a message, with associated Throwable information.
1094     * <p>
1095     * If the logger is currently enabled for the given message
1096     * level then the given arguments are stored in a LogRecord
1097     * which is forwarded to all registered output handlers.
1098     * <p>
1099     * Note that the thrown argument is stored in the LogRecord thrown
1100     * property, rather than the LogRecord parameters property.  Thus it is
1101     * processed specially by output Formatters and is not treated
1102     * as a formatting parameter to the LogRecord message property.
1103     *
1104     * @param   level   One of the message level identifiers, e.g., SEVERE
1105     * @param   msg     The string message (or a key in the message catalog)
1106     * @param   thrown  Throwable associated with log message.
1107     */
1108    public void log(Level level, String msg, Throwable thrown) {
1109        if (!isLoggable(level)) {
1110            return;
1111        }
1112        LogRecord lr = new LogRecord(level, msg);
1113        lr.setThrown(thrown);
1114        doLog(lr);
1115    }
1116
1117    /**
1118     * Log a lazily constructed message, with associated Throwable information.
1119     * <p>
1120     * If the logger is currently enabled for the given message level then the
1121     * message is constructed by invoking the provided supplier function. The
1122     * message and the given {@link Throwable} are then stored in a {@link
1123     * LogRecord} which is forwarded to all registered output handlers.
1124     * <p>
1125     * Note that the thrown argument is stored in the LogRecord thrown
1126     * property, rather than the LogRecord parameters property.  Thus it is
1127     * processed specially by output Formatters and is not treated
1128     * as a formatting parameter to the LogRecord message property.
1129     *
1130     * @param   level   One of the message level identifiers, e.g., SEVERE
1131     * @param   thrown  Throwable associated with log message.
1132     * @param   msgSupplier   A function, which when called, produces the
1133     *                        desired log message
1134     * @since   1.8
1135     */
1136    public void log(Level level, Throwable thrown, Supplier<String> msgSupplier) {
1137        if (!isLoggable(level)) {
1138            return;
1139        }
1140        LogRecord lr = new LogRecord(level, msgSupplier.get());
1141        lr.setThrown(thrown);
1142        doLog(lr);
1143    }
1144
1145    //================================================================
1146    // Start of convenience methods WITH className and methodName
1147    //================================================================
1148
1149    /**
1150     * Log a message, specifying source class and method,
1151     * with no arguments.
1152     * <p>
1153     * If the logger is currently enabled for the given message
1154     * level then the given message is forwarded to all the
1155     * registered output Handler objects.
1156     *
1157     * @param   level   One of the message level identifiers, e.g., SEVERE
1158     * @param   sourceClass    name of class that issued the logging request
1159     * @param   sourceMethod   name of method that issued the logging request
1160     * @param   msg     The string message (or a key in the message catalog)
1161     */
1162    public void logp(Level level, String sourceClass, String sourceMethod, String msg) {
1163        if (!isLoggable(level)) {
1164            return;
1165        }
1166        LogRecord lr = new LogRecord(level, msg);
1167        lr.setSourceClassName(sourceClass);
1168        lr.setSourceMethodName(sourceMethod);
1169        doLog(lr);
1170    }
1171
1172    /**
1173     * Log a lazily constructed message, specifying source class and method,
1174     * with no arguments.
1175     * <p>
1176     * If the logger is currently enabled for the given message
1177     * level then the message is constructed by invoking the provided
1178     * supplier function and forwarded to all the registered output
1179     * Handler objects.
1180     *
1181     * @param   level   One of the message level identifiers, e.g., SEVERE
1182     * @param   sourceClass    name of class that issued the logging request
1183     * @param   sourceMethod   name of method that issued the logging request
1184     * @param   msgSupplier   A function, which when called, produces the
1185     *                        desired log message
1186     * @since   1.8
1187     */
1188    public void logp(Level level, String sourceClass, String sourceMethod,
1189                     Supplier<String> msgSupplier) {
1190        if (!isLoggable(level)) {
1191            return;
1192        }
1193        LogRecord lr = new LogRecord(level, msgSupplier.get());
1194        lr.setSourceClassName(sourceClass);
1195        lr.setSourceMethodName(sourceMethod);
1196        doLog(lr);
1197    }
1198
1199    /**
1200     * Log a message, specifying source class and method,
1201     * with a single object parameter to the log message.
1202     * <p>
1203     * If the logger is currently enabled for the given message
1204     * level then a corresponding LogRecord is created and forwarded
1205     * to all the registered output Handler objects.
1206     *
1207     * @param   level   One of the message level identifiers, e.g., SEVERE
1208     * @param   sourceClass    name of class that issued the logging request
1209     * @param   sourceMethod   name of method that issued the logging request
1210     * @param   msg      The string message (or a key in the message catalog)
1211     * @param   param1    Parameter to the log message.
1212     */
1213    public void logp(Level level, String sourceClass, String sourceMethod,
1214                                                String msg, Object param1) {
1215        if (!isLoggable(level)) {
1216            return;
1217        }
1218        LogRecord lr = new LogRecord(level, msg);
1219        lr.setSourceClassName(sourceClass);
1220        lr.setSourceMethodName(sourceMethod);
1221        Object params[] = { param1 };
1222        lr.setParameters(params);
1223        doLog(lr);
1224    }
1225
1226    /**
1227     * Log a message, specifying source class and method,
1228     * with an array of object arguments.
1229     * <p>
1230     * If the logger is currently enabled for the given message
1231     * level then a corresponding LogRecord is created and forwarded
1232     * to all the registered output Handler objects.
1233     *
1234     * @param   level   One of the message level identifiers, e.g., SEVERE
1235     * @param   sourceClass    name of class that issued the logging request
1236     * @param   sourceMethod   name of method that issued the logging request
1237     * @param   msg     The string message (or a key in the message catalog)
1238     * @param   params  Array of parameters to the message
1239     */
1240    public void logp(Level level, String sourceClass, String sourceMethod,
1241                                                String msg, Object params[]) {
1242        if (!isLoggable(level)) {
1243            return;
1244        }
1245        LogRecord lr = new LogRecord(level, msg);
1246        lr.setSourceClassName(sourceClass);
1247        lr.setSourceMethodName(sourceMethod);
1248        lr.setParameters(params);
1249        doLog(lr);
1250    }
1251
1252    /**
1253     * Log a message, specifying source class and method,
1254     * with associated Throwable information.
1255     * <p>
1256     * If the logger is currently enabled for the given message
1257     * level then the given arguments are stored in a LogRecord
1258     * which is forwarded to all registered output handlers.
1259     * <p>
1260     * Note that the thrown argument is stored in the LogRecord thrown
1261     * property, rather than the LogRecord parameters property.  Thus it is
1262     * processed specially by output Formatters and is not treated
1263     * as a formatting parameter to the LogRecord message property.
1264     *
1265     * @param   level   One of the message level identifiers, e.g., SEVERE
1266     * @param   sourceClass    name of class that issued the logging request
1267     * @param   sourceMethod   name of method that issued the logging request
1268     * @param   msg     The string message (or a key in the message catalog)
1269     * @param   thrown  Throwable associated with log message.
1270     */
1271    public void logp(Level level, String sourceClass, String sourceMethod,
1272                     String msg, Throwable thrown) {
1273        if (!isLoggable(level)) {
1274            return;
1275        }
1276        LogRecord lr = new LogRecord(level, msg);
1277        lr.setSourceClassName(sourceClass);
1278        lr.setSourceMethodName(sourceMethod);
1279        lr.setThrown(thrown);
1280        doLog(lr);
1281    }
1282
1283    /**
1284     * Log a lazily constructed message, specifying source class and method,
1285     * with associated Throwable information.
1286     * <p>
1287     * If the logger is currently enabled for the given message level then the
1288     * message is constructed by invoking the provided supplier function. The
1289     * message and the given {@link Throwable} are then stored in a {@link
1290     * LogRecord} which is forwarded to all registered output handlers.
1291     * <p>
1292     * Note that the thrown argument is stored in the LogRecord thrown
1293     * property, rather than the LogRecord parameters property.  Thus it is
1294     * processed specially by output Formatters and is not treated
1295     * as a formatting parameter to the LogRecord message property.
1296     *
1297     * @param   level   One of the message level identifiers, e.g., SEVERE
1298     * @param   sourceClass    name of class that issued the logging request
1299     * @param   sourceMethod   name of method that issued the logging request
1300     * @param   thrown  Throwable associated with log message.
1301     * @param   msgSupplier   A function, which when called, produces the
1302     *                        desired log message
1303     * @since   1.8
1304     */
1305    public void logp(Level level, String sourceClass, String sourceMethod,
1306                     Throwable thrown, Supplier<String> msgSupplier) {
1307        if (!isLoggable(level)) {
1308            return;
1309        }
1310        LogRecord lr = new LogRecord(level, msgSupplier.get());
1311        lr.setSourceClassName(sourceClass);
1312        lr.setSourceMethodName(sourceMethod);
1313        lr.setThrown(thrown);
1314        doLog(lr);
1315    }
1316
1317
1318    //=========================================================================
1319    // Start of convenience methods WITH className, methodName and bundle name.
1320    //=========================================================================
1321
1322    // Private support method for logging for "logrb" methods.
1323    // We fill in the logger name, resource bundle name, and
1324    // resource bundle and then call "void log(LogRecord)".
1325    private void doLog(LogRecord lr, String rbname) {
1326        lr.setLoggerName(name);
1327        if (rbname != null) {
1328            lr.setResourceBundleName(rbname);
1329            lr.setResourceBundle(findResourceBundle(rbname, false));
1330        }
1331        log(lr);
1332    }
1333
1334    // Private support method for logging for "logrb" methods.
1335    private void doLog(LogRecord lr, ResourceBundle rb) {
1336        lr.setLoggerName(name);
1337        if (rb != null) {
1338            lr.setResourceBundleName(rb.getBaseBundleName());
1339            lr.setResourceBundle(rb);
1340        }
1341        log(lr);
1342    }
1343
1344    /**
1345     * Log a message, specifying source class, method, and resource bundle name
1346     * with no arguments.
1347     * <p>
1348     * If the logger is currently enabled for the given message
1349     * level then the given message is forwarded to all the
1350     * registered output Handler objects.
1351     * <p>
1352     * The msg string is localized using the named resource bundle.  If the
1353     * resource bundle name is null, or an empty String or invalid
1354     * then the msg string is not localized.
1355     *
1356     * @param   level   One of the message level identifiers, e.g., SEVERE
1357     * @param   sourceClass    name of class that issued the logging request
1358     * @param   sourceMethod   name of method that issued the logging request
1359     * @param   bundleName     name of resource bundle to localize msg,
1360     *                         can be null
1361     * @param   msg     The string message (or a key in the message catalog)
1362     * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
1363     * java.lang.String, java.util.ResourceBundle, java.lang.String,
1364     * java.lang.Object...)} instead.
1365     */
1366    @Deprecated
1367    public void logrb(Level level, String sourceClass, String sourceMethod,
1368                                String bundleName, String msg) {
1369        if (!isLoggable(level)) {
1370            return;
1371        }
1372        LogRecord lr = new LogRecord(level, msg);
1373        lr.setSourceClassName(sourceClass);
1374        lr.setSourceMethodName(sourceMethod);
1375        doLog(lr, bundleName);
1376    }
1377
1378    /**
1379     * Log a message, specifying source class, method, and resource bundle name,
1380     * with a single object parameter to the log message.
1381     * <p>
1382     * If the logger is currently enabled for the given message
1383     * level then a corresponding LogRecord is created and forwarded
1384     * to all the registered output Handler objects.
1385     * <p>
1386     * The msg string is localized using the named resource bundle.  If the
1387     * resource bundle name is null, or an empty String or invalid
1388     * then the msg string is not localized.
1389     *
1390     * @param   level   One of the message level identifiers, e.g., SEVERE
1391     * @param   sourceClass    name of class that issued the logging request
1392     * @param   sourceMethod   name of method that issued the logging request
1393     * @param   bundleName     name of resource bundle to localize msg,
1394     *                         can be null
1395     * @param   msg      The string message (or a key in the message catalog)
1396     * @param   param1    Parameter to the log message.
1397     * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
1398     *   java.lang.String, java.util.ResourceBundle, java.lang.String,
1399     *   java.lang.Object...)} instead
1400     */
1401    @Deprecated
1402    public void logrb(Level level, String sourceClass, String sourceMethod,
1403                                String bundleName, String msg, Object param1) {
1404        if (!isLoggable(level)) {
1405            return;
1406        }
1407        LogRecord lr = new LogRecord(level, msg);
1408        lr.setSourceClassName(sourceClass);
1409        lr.setSourceMethodName(sourceMethod);
1410        Object params[] = { param1 };
1411        lr.setParameters(params);
1412        doLog(lr, bundleName);
1413    }
1414
1415    /**
1416     * Log a message, specifying source class, method, and resource bundle name,
1417     * with an array of object arguments.
1418     * <p>
1419     * If the logger is currently enabled for the given message
1420     * level then a corresponding LogRecord is created and forwarded
1421     * to all the registered output Handler objects.
1422     * <p>
1423     * The msg string is localized using the named resource bundle.  If the
1424     * resource bundle name is null, or an empty String or invalid
1425     * then the msg string is not localized.
1426     *
1427     * @param   level   One of the message level identifiers, e.g., SEVERE
1428     * @param   sourceClass    name of class that issued the logging request
1429     * @param   sourceMethod   name of method that issued the logging request
1430     * @param   bundleName     name of resource bundle to localize msg,
1431     *                         can be null.
1432     * @param   msg     The string message (or a key in the message catalog)
1433     * @param   params  Array of parameters to the message
1434     * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
1435     *      java.lang.String, java.util.ResourceBundle, java.lang.String,
1436     *      java.lang.Object...)} instead.
1437     */
1438    @Deprecated
1439    public void logrb(Level level, String sourceClass, String sourceMethod,
1440                                String bundleName, String msg, Object params[]) {
1441        if (!isLoggable(level)) {
1442            return;
1443        }
1444        LogRecord lr = new LogRecord(level, msg);
1445        lr.setSourceClassName(sourceClass);
1446        lr.setSourceMethodName(sourceMethod);
1447        lr.setParameters(params);
1448        doLog(lr, bundleName);
1449    }
1450
1451    /**
1452     * Log a message, specifying source class, method, and resource bundle,
1453     * with an optional list of message parameters.
1454     * <p>
1455     * If the logger is currently enabled for the given message
1456     * {@code level} then a corresponding {@code LogRecord} is created and
1457     * forwarded to all the registered output {@code Handler} objects.
1458     * <p>
1459     * The {@code msg} string is localized using the given resource bundle.
1460     * If the resource bundle is {@code null}, then the {@code msg} string is not
1461     * localized.
1462     *
1463     * @param   level   One of the message level identifiers, e.g., {@code SEVERE}
1464     * @param   sourceClass    Name of the class that issued the logging request
1465     * @param   sourceMethod   Name of the method that issued the logging request
1466     * @param   bundle         Resource bundle to localize {@code msg},
1467     *                         can be {@code null}.
1468     * @param   msg     The string message (or a key in the message catalog)
1469     * @param   params  Parameters to the message (optional, may be none).
1470     * @since 1.8
1471     */
1472    public void logrb(Level level, String sourceClass, String sourceMethod,
1473                      ResourceBundle bundle, String msg, Object... params) {
1474        if (!isLoggable(level)) {
1475            return;
1476        }
1477        LogRecord lr = new LogRecord(level, msg);
1478        lr.setSourceClassName(sourceClass);
1479        lr.setSourceMethodName(sourceMethod);
1480        if (params != null && params.length != 0) {
1481            lr.setParameters(params);
1482        }
1483        doLog(lr, bundle);
1484    }
1485
1486    /**
1487     * Log a message, specifying source class, method, and resource bundle,
1488     * with an optional list of message parameters.
1489     * <p>
1490     * If the logger is currently enabled for the given message
1491     * {@code level} then a corresponding {@code LogRecord} is created
1492     * and forwarded to all the registered output {@code Handler} objects.
1493     * <p>
1494     * The {@code msg} string is localized using the given resource bundle.
1495     * If the resource bundle is {@code null}, then the {@code msg} string is not
1496     * localized.
1497     * <p>
1498     * @param   level   One of the message level identifiers, e.g., {@code SEVERE}
1499     * @param   bundle  Resource bundle to localize {@code msg};
1500     *                  can be {@code null}.
1501     * @param   msg     The string message (or a key in the message catalog)
1502     * @param   params  Parameters to the message (optional, may be none).
1503     * @since 9
1504     */
1505    public void logrb(Level level, ResourceBundle bundle, String msg, Object... params) {
1506        if (!isLoggable(level)) {
1507            return;
1508        }
1509        LogRecord lr = new LogRecord(level, msg);
1510        if (params != null && params.length != 0) {
1511            lr.setParameters(params);
1512        }
1513        doLog(lr, bundle);
1514    }
1515
1516    /**
1517     * Log a message, specifying source class, method, and resource bundle name,
1518     * with associated Throwable information.
1519     * <p>
1520     * If the logger is currently enabled for the given message
1521     * level then the given arguments are stored in a LogRecord
1522     * which is forwarded to all registered output handlers.
1523     * <p>
1524     * The msg string is localized using the named resource bundle.  If the
1525     * resource bundle name is null, or an empty String or invalid
1526     * then the msg string is not localized.
1527     * <p>
1528     * Note that the thrown argument is stored in the LogRecord thrown
1529     * property, rather than the LogRecord parameters property.  Thus it is
1530     * processed specially by output Formatters and is not treated
1531     * as a formatting parameter to the LogRecord message property.
1532     *
1533     * @param   level   One of the message level identifiers, e.g., SEVERE
1534     * @param   sourceClass    name of class that issued the logging request
1535     * @param   sourceMethod   name of method that issued the logging request
1536     * @param   bundleName     name of resource bundle to localize msg,
1537     *                         can be null
1538     * @param   msg     The string message (or a key in the message catalog)
1539     * @param   thrown  Throwable associated with log message.
1540     * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
1541     *     java.lang.String, java.util.ResourceBundle, java.lang.String,
1542     *     java.lang.Throwable)} instead.
1543     */
1544    @Deprecated
1545    public void logrb(Level level, String sourceClass, String sourceMethod,
1546                                        String bundleName, String msg, Throwable thrown) {
1547        if (!isLoggable(level)) {
1548            return;
1549        }
1550        LogRecord lr = new LogRecord(level, msg);
1551        lr.setSourceClassName(sourceClass);
1552        lr.setSourceMethodName(sourceMethod);
1553        lr.setThrown(thrown);
1554        doLog(lr, bundleName);
1555    }
1556
1557    /**
1558     * Log a message, specifying source class, method, and resource bundle,
1559     * with associated Throwable information.
1560     * <p>
1561     * If the logger is currently enabled for the given message
1562     * {@code level} then the given arguments are stored in a {@code LogRecord}
1563     * which is forwarded to all registered output handlers.
1564     * <p>
1565     * The {@code msg} string is localized using the given resource bundle.
1566     * If the resource bundle is {@code null}, then the {@code msg} string is not
1567     * localized.
1568     * <p>
1569     * Note that the {@code thrown} argument is stored in the {@code LogRecord}
1570     * {@code thrown} property, rather than the {@code LogRecord}
1571     * {@code parameters} property.  Thus it is
1572     * processed specially by output {@code Formatter} objects and is not treated
1573     * as a formatting parameter to the {@code LogRecord} {@code message} property.
1574     *
1575     * @param   level   One of the message level identifiers, e.g., {@code SEVERE}
1576     * @param   sourceClass    Name of the class that issued the logging request
1577     * @param   sourceMethod   Name of the method that issued the logging request
1578     * @param   bundle         Resource bundle to localize {@code msg},
1579     *                         can be {@code null}
1580     * @param   msg     The string message (or a key in the message catalog)
1581     * @param   thrown  Throwable associated with the log message.
1582     * @since 1.8
1583     */
1584    public void logrb(Level level, String sourceClass, String sourceMethod,
1585                      ResourceBundle bundle, String msg, Throwable thrown) {
1586        if (!isLoggable(level)) {
1587            return;
1588        }
1589        LogRecord lr = new LogRecord(level, msg);
1590        lr.setSourceClassName(sourceClass);
1591        lr.setSourceMethodName(sourceMethod);
1592        lr.setThrown(thrown);
1593        doLog(lr, bundle);
1594    }
1595
1596    /**
1597     * Log a message, specifying source class, method, and resource bundle,
1598     * with associated Throwable information.
1599     * <p>
1600     * If the logger is currently enabled for the given message
1601     * {@code level} then the given arguments are stored in a {@code LogRecord}
1602     * which is forwarded to all registered output handlers.
1603     * <p>
1604     * The {@code msg} string is localized using the given resource bundle.
1605     * If the resource bundle is {@code null}, then the {@code msg} string is not
1606     * localized.
1607     * <p>
1608     * Note that the {@code thrown} argument is stored in the {@code LogRecord}
1609     * {@code thrown} property, rather than the {@code LogRecord}
1610     * {@code parameters} property.  Thus it is
1611     * processed specially by output {@code Formatter} objects and is not treated
1612     * as a formatting parameter to the {@code LogRecord} {@code message}
1613     * property.
1614     * <p>
1615     * @param   level   One of the message level identifiers, e.g., {@code SEVERE}
1616     * @param   bundle  Resource bundle to localize {@code msg};
1617     *                  can be {@code null}.
1618     * @param   msg     The string message (or a key in the message catalog)
1619     * @param   thrown  Throwable associated with the log message.
1620     * @since 9
1621     */
1622    public void logrb(Level level, ResourceBundle bundle, String msg,
1623            Throwable thrown) {
1624        if (!isLoggable(level)) {
1625            return;
1626        }
1627        LogRecord lr = new LogRecord(level, msg);
1628        lr.setThrown(thrown);
1629        doLog(lr, bundle);
1630    }
1631
1632    //======================================================================
1633    // Start of convenience methods for logging method entries and returns.
1634    //======================================================================
1635
1636    /**
1637     * Log a method entry.
1638     * <p>
1639     * This is a convenience method that can be used to log entry
1640     * to a method.  A LogRecord with message "ENTRY", log level
1641     * FINER, and the given sourceMethod and sourceClass is logged.
1642     *
1643     * @param   sourceClass    name of class that issued the logging request
1644     * @param   sourceMethod   name of method that is being entered
1645     */
1646    public void entering(String sourceClass, String sourceMethod) {
1647        logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
1648    }
1649
1650    /**
1651     * Log a method entry, with one parameter.
1652     * <p>
1653     * This is a convenience method that can be used to log entry
1654     * to a method.  A LogRecord with message "ENTRY {0}", log level
1655     * FINER, and the given sourceMethod, sourceClass, and parameter
1656     * is logged.
1657     *
1658     * @param   sourceClass    name of class that issued the logging request
1659     * @param   sourceMethod   name of method that is being entered
1660     * @param   param1         parameter to the method being entered
1661     */
1662    public void entering(String sourceClass, String sourceMethod, Object param1) {
1663        logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param1);
1664    }
1665
1666    /**
1667     * Log a method entry, with an array of parameters.
1668     * <p>
1669     * This is a convenience method that can be used to log entry
1670     * to a method.  A LogRecord with message "ENTRY" (followed by a
1671     * format {N} indicator for each entry in the parameter array),
1672     * log level FINER, and the given sourceMethod, sourceClass, and
1673     * parameters is logged.
1674     *
1675     * @param   sourceClass    name of class that issued the logging request
1676     * @param   sourceMethod   name of method that is being entered
1677     * @param   params         array of parameters to the method being entered
1678     */
1679    public void entering(String sourceClass, String sourceMethod, Object params[]) {
1680        String msg = "ENTRY";
1681        if (params == null ) {
1682           logp(Level.FINER, sourceClass, sourceMethod, msg);
1683           return;
1684        }
1685        if (!isLoggable(Level.FINER)) return;
1686        if (params.length > 0) {
1687            final StringBuilder b = new StringBuilder(msg);
1688            for (int i = 0; i < params.length; i++) {
1689                b.append(' ').append('{').append(i).append('}');
1690            }
1691            msg = b.toString();
1692        }
1693        logp(Level.FINER, sourceClass, sourceMethod, msg, params);
1694    }
1695
1696    /**
1697     * Log a method return.
1698     * <p>
1699     * This is a convenience method that can be used to log returning
1700     * from a method.  A LogRecord with message "RETURN", log level
1701     * FINER, and the given sourceMethod and sourceClass is logged.
1702     *
1703     * @param   sourceClass    name of class that issued the logging request
1704     * @param   sourceMethod   name of the method
1705     */
1706    public void exiting(String sourceClass, String sourceMethod) {
1707        logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
1708    }
1709
1710
1711    /**
1712     * Log a method return, with result object.
1713     * <p>
1714     * This is a convenience method that can be used to log returning
1715     * from a method.  A LogRecord with message "RETURN {0}", log level
1716     * FINER, and the gives sourceMethod, sourceClass, and result
1717     * object is logged.
1718     *
1719     * @param   sourceClass    name of class that issued the logging request
1720     * @param   sourceMethod   name of the method
1721     * @param   result  Object that is being returned
1722     */
1723    public void exiting(String sourceClass, String sourceMethod, Object result) {
1724        logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
1725    }
1726
1727    /**
1728     * Log throwing an exception.
1729     * <p>
1730     * This is a convenience method to log that a method is
1731     * terminating by throwing an exception.  The logging is done
1732     * using the FINER level.
1733     * <p>
1734     * If the logger is currently enabled for the given message
1735     * level then the given arguments are stored in a LogRecord
1736     * which is forwarded to all registered output handlers.  The
1737     * LogRecord's message is set to "THROW".
1738     * <p>
1739     * Note that the thrown argument is stored in the LogRecord thrown
1740     * property, rather than the LogRecord parameters property.  Thus it is
1741     * processed specially by output Formatters and is not treated
1742     * as a formatting parameter to the LogRecord message property.
1743     *
1744     * @param   sourceClass    name of class that issued the logging request
1745     * @param   sourceMethod  name of the method.
1746     * @param   thrown  The Throwable that is being thrown.
1747     */
1748    public void throwing(String sourceClass, String sourceMethod, Throwable thrown) {
1749        if (!isLoggable(Level.FINER)) {
1750            return;
1751        }
1752        LogRecord lr = new LogRecord(Level.FINER, "THROW");
1753        lr.setSourceClassName(sourceClass);
1754        lr.setSourceMethodName(sourceMethod);
1755        lr.setThrown(thrown);
1756        doLog(lr);
1757    }
1758
1759    //=======================================================================
1760    // Start of simple convenience methods using level names as method names
1761    //=======================================================================
1762
1763    /**
1764     * Log a SEVERE message.
1765     * <p>
1766     * If the logger is currently enabled for the SEVERE message
1767     * level then the given message is forwarded to all the
1768     * registered output Handler objects.
1769     *
1770     * @param   msg     The string message (or a key in the message catalog)
1771     */
1772    public void severe(String msg) {
1773        log(Level.SEVERE, msg);
1774    }
1775
1776    /**
1777     * Log a WARNING message.
1778     * <p>
1779     * If the logger is currently enabled for the WARNING message
1780     * level then the given message is forwarded to all the
1781     * registered output Handler objects.
1782     *
1783     * @param   msg     The string message (or a key in the message catalog)
1784     */
1785    public void warning(String msg) {
1786        log(Level.WARNING, msg);
1787    }
1788
1789    /**
1790     * Log an INFO message.
1791     * <p>
1792     * If the logger is currently enabled for the INFO message
1793     * level then the given message is forwarded to all the
1794     * registered output Handler objects.
1795     *
1796     * @param   msg     The string message (or a key in the message catalog)
1797     */
1798    public void info(String msg) {
1799        log(Level.INFO, msg);
1800    }
1801
1802    /**
1803     * Log a CONFIG message.
1804     * <p>
1805     * If the logger is currently enabled for the CONFIG message
1806     * level then the given message is forwarded to all the
1807     * registered output Handler objects.
1808     *
1809     * @param   msg     The string message (or a key in the message catalog)
1810     */
1811    public void config(String msg) {
1812        log(Level.CONFIG, msg);
1813    }
1814
1815    /**
1816     * Log a FINE message.
1817     * <p>
1818     * If the logger is currently enabled for the FINE message
1819     * level then the given message is forwarded to all the
1820     * registered output Handler objects.
1821     *
1822     * @param   msg     The string message (or a key in the message catalog)
1823     */
1824    public void fine(String msg) {
1825        log(Level.FINE, msg);
1826    }
1827
1828    /**
1829     * Log a FINER message.
1830     * <p>
1831     * If the logger is currently enabled for the FINER message
1832     * level then the given message is forwarded to all the
1833     * registered output Handler objects.
1834     *
1835     * @param   msg     The string message (or a key in the message catalog)
1836     */
1837    public void finer(String msg) {
1838        log(Level.FINER, msg);
1839    }
1840
1841    /**
1842     * Log a FINEST message.
1843     * <p>
1844     * If the logger is currently enabled for the FINEST message
1845     * level then the given message is forwarded to all the
1846     * registered output Handler objects.
1847     *
1848     * @param   msg     The string message (or a key in the message catalog)
1849     */
1850    public void finest(String msg) {
1851        log(Level.FINEST, msg);
1852    }
1853
1854    //=======================================================================
1855    // Start of simple convenience methods using level names as method names
1856    // and use Supplier<String>
1857    //=======================================================================
1858
1859    /**
1860     * Log a SEVERE message, which is only to be constructed if the logging
1861     * level is such that the message will actually be logged.
1862     * <p>
1863     * If the logger is currently enabled for the SEVERE message
1864     * level then the message is constructed by invoking the provided
1865     * supplier function and forwarded to all the registered output
1866     * Handler objects.
1867     *
1868     * @param   msgSupplier   A function, which when called, produces the
1869     *                        desired log message
1870     * @since   1.8
1871     */
1872    public void severe(Supplier<String> msgSupplier) {
1873        log(Level.SEVERE, msgSupplier);
1874    }
1875
1876    /**
1877     * Log a WARNING message, which is only to be constructed if the logging
1878     * level is such that the message will actually be logged.
1879     * <p>
1880     * If the logger is currently enabled for the WARNING message
1881     * level then the message is constructed by invoking the provided
1882     * supplier function and forwarded to all the registered output
1883     * Handler objects.
1884     *
1885     * @param   msgSupplier   A function, which when called, produces the
1886     *                        desired log message
1887     * @since   1.8
1888     */
1889    public void warning(Supplier<String> msgSupplier) {
1890        log(Level.WARNING, msgSupplier);
1891    }
1892
1893    /**
1894     * Log a INFO message, which is only to be constructed if the logging
1895     * level is such that the message will actually be logged.
1896     * <p>
1897     * If the logger is currently enabled for the INFO message
1898     * level then the message is constructed by invoking the provided
1899     * supplier function and forwarded to all the registered output
1900     * Handler objects.
1901     *
1902     * @param   msgSupplier   A function, which when called, produces the
1903     *                        desired log message
1904     * @since   1.8
1905     */
1906    public void info(Supplier<String> msgSupplier) {
1907        log(Level.INFO, msgSupplier);
1908    }
1909
1910    /**
1911     * Log a CONFIG message, which is only to be constructed if the logging
1912     * level is such that the message will actually be logged.
1913     * <p>
1914     * If the logger is currently enabled for the CONFIG message
1915     * level then the message is constructed by invoking the provided
1916     * supplier function and forwarded to all the registered output
1917     * Handler objects.
1918     *
1919     * @param   msgSupplier   A function, which when called, produces the
1920     *                        desired log message
1921     * @since   1.8
1922     */
1923    public void config(Supplier<String> msgSupplier) {
1924        log(Level.CONFIG, msgSupplier);
1925    }
1926
1927    /**
1928     * Log a FINE message, which is only to be constructed if the logging
1929     * level is such that the message will actually be logged.
1930     * <p>
1931     * If the logger is currently enabled for the FINE message
1932     * level then the message is constructed by invoking the provided
1933     * supplier function and forwarded to all the registered output
1934     * Handler objects.
1935     *
1936     * @param   msgSupplier   A function, which when called, produces the
1937     *                        desired log message
1938     * @since   1.8
1939     */
1940    public void fine(Supplier<String> msgSupplier) {
1941        log(Level.FINE, msgSupplier);
1942    }
1943
1944    /**
1945     * Log a FINER message, which is only to be constructed if the logging
1946     * level is such that the message will actually be logged.
1947     * <p>
1948     * If the logger is currently enabled for the FINER message
1949     * level then the message is constructed by invoking the provided
1950     * supplier function and forwarded to all the registered output
1951     * Handler objects.
1952     *
1953     * @param   msgSupplier   A function, which when called, produces the
1954     *                        desired log message
1955     * @since   1.8
1956     */
1957    public void finer(Supplier<String> msgSupplier) {
1958        log(Level.FINER, msgSupplier);
1959    }
1960
1961    /**
1962     * Log a FINEST message, which is only to be constructed if the logging
1963     * level is such that the message will actually be logged.
1964     * <p>
1965     * If the logger is currently enabled for the FINEST message
1966     * level then the message is constructed by invoking the provided
1967     * supplier function and forwarded to all the registered output
1968     * Handler objects.
1969     *
1970     * @param   msgSupplier   A function, which when called, produces the
1971     *                        desired log message
1972     * @since   1.8
1973     */
1974    public void finest(Supplier<String> msgSupplier) {
1975        log(Level.FINEST, msgSupplier);
1976    }
1977
1978    //================================================================
1979    // End of convenience methods
1980    //================================================================
1981
1982    /**
1983     * Set the log level specifying which message levels will be
1984     * logged by this logger.  Message levels lower than this
1985     * value will be discarded.  The level value Level.OFF
1986     * can be used to turn off logging.
1987     * <p>
1988     * If the new level is null, it means that this node should
1989     * inherit its level from its nearest ancestor with a specific
1990     * (non-null) level value.
1991     *
1992     * @param newLevel   the new value for the log level (may be null)
1993     * @throws  SecurityException if a security manager exists,
1994     *          this logger is not anonymous, and the caller
1995     *          does not have LoggingPermission("control").
1996     */
1997    public void setLevel(Level newLevel) throws SecurityException {
1998        checkPermission();
1999        synchronized (treeLock) {
2000            config.setLevelObject(newLevel);
2001            updateEffectiveLevel();
2002        }
2003    }
2004
2005    final boolean isLevelInitialized() {
2006        return config.levelObject != null;
2007    }
2008
2009    /**
2010     * Get the log Level that has been specified for this Logger.
2011     * The result may be null, which means that this logger's
2012     * effective level will be inherited from its parent.
2013     *
2014     * @return  this Logger's level
2015     */
2016    public Level getLevel() {
2017        return config.levelObject;
2018    }
2019
2020    /**
2021     * Check if a message of the given level would actually be logged
2022     * by this logger.  This check is based on the Loggers effective level,
2023     * which may be inherited from its parent.
2024     *
2025     * @param   level   a message logging level
2026     * @return  true if the given message level is currently being logged.
2027     */
2028    public boolean isLoggable(Level level) {
2029        int levelValue = config.levelValue;
2030        if (level.intValue() < levelValue || levelValue == offValue) {
2031            return false;
2032        }
2033        return true;
2034    }
2035
2036    /**
2037     * Get the name for this logger.
2038     * @return logger name.  Will be null for anonymous Loggers.
2039     */
2040    public String getName() {
2041        return name;
2042    }
2043
2044    /**
2045     * Add a log Handler to receive logging messages.
2046     * <p>
2047     * By default, Loggers also send their output to their parent logger.
2048     * Typically the root Logger is configured with a set of Handlers
2049     * that essentially act as default handlers for all loggers.
2050     *
2051     * @param   handler a logging Handler
2052     * @throws  SecurityException if a security manager exists,
2053     *          this logger is not anonymous, and the caller
2054     *          does not have LoggingPermission("control").
2055     */
2056    public void addHandler(Handler handler) throws SecurityException {
2057        Objects.requireNonNull(handler);
2058        checkPermission();
2059        config.addHandler(handler);
2060    }
2061
2062    /**
2063     * Remove a log Handler.
2064     * <P>
2065     * Returns silently if the given Handler is not found or is null
2066     *
2067     * @param   handler a logging Handler
2068     * @throws  SecurityException if a security manager exists,
2069     *          this logger is not anonymous, and the caller
2070     *          does not have LoggingPermission("control").
2071     */
2072    public void removeHandler(Handler handler) throws SecurityException {
2073        checkPermission();
2074        if (handler == null) {
2075            return;
2076        }
2077        config.removeHandler(handler);
2078    }
2079
2080    /**
2081     * Get the Handlers associated with this logger.
2082     *
2083     * @return  an array of all registered Handlers
2084     */
2085    public Handler[] getHandlers() {
2086        return accessCheckedHandlers();
2087    }
2088
2089    // This method should ideally be marked final - but unfortunately
2090    // it needs to be overridden by LogManager.RootLogger
2091    Handler[] accessCheckedHandlers() {
2092        return config.handlers.toArray(emptyHandlers);
2093    }
2094
2095    /**
2096     * Specify whether or not this logger should send its output
2097     * to its parent Logger.  This means that any LogRecords will
2098     * also be written to the parent's Handlers, and potentially
2099     * to its parent, recursively up the namespace.
2100     *
2101     * @param useParentHandlers   true if output is to be sent to the
2102     *          logger's parent.
2103     * @throws  SecurityException if a security manager exists,
2104     *          this logger is not anonymous, and the caller
2105     *          does not have LoggingPermission("control").
2106     */
2107    public void setUseParentHandlers(boolean useParentHandlers) {
2108        checkPermission();
2109        config.setUseParentHandlers(useParentHandlers);
2110    }
2111
2112    /**
2113     * Discover whether or not this logger is sending its output
2114     * to its parent logger.
2115     *
2116     * @return  true if output is to be sent to the logger's parent
2117     */
2118    public boolean getUseParentHandlers() {
2119        return config.useParentHandlers;
2120    }
2121
2122    /**
2123     * Private utility method to map a resource bundle name to an
2124     * actual resource bundle, using a simple one-entry cache.
2125     * Returns null for a null name.
2126     * May also return null if we can't find the resource bundle and
2127     * there is no suitable previous cached value.
2128     *
2129     * @param name the ResourceBundle to locate
2130     * @param useCallersModule if true search using the caller's module.
2131     * @return ResourceBundle specified by name or null if not found
2132     */
2133    private synchronized ResourceBundle findResourceBundle(String name,
2134                                                           boolean useCallersModule) {
2135        // When this method is called from logrb, useCallersModule==false, and
2136        // the resource bundle 'name' is the argument provided to logrb.
2137        // It may, or may not be, equal to lb.resourceBundleName.
2138        // Otherwise, useCallersModule==true, and name is the resource bundle
2139        // name that is set (or will be set) in this logger.
2140        //
2141        // When useCallersModule is false, or when the caller's module is
2142        // null, or when the caller's module is an unnamed module, we look
2143        // first in the TCCL (or the System ClassLoader if the TCCL is null)
2144        // to locate the resource bundle.
2145        //
2146        // Otherwise, if useCallersModule is true, and the caller's module is not
2147        // null, and the caller's module is named, we look in the caller's module
2148        // to locate the resource bundle.
2149        //
2150        // Finally, if the caller's module is not null and is unnamed, and
2151        // useCallersModule is true, we look in the caller's module class loader
2152        // (unless we already looked there in step 1).
2153
2154        // Return a null bundle for a null name.
2155        if (name == null) {
2156            return null;
2157        }
2158
2159        Locale currentLocale = Locale.getDefault();
2160        final LoggerBundle lb = loggerBundle;
2161
2162        // Normally we should hit on our simple one entry cache.
2163        if (lb.userBundle != null &&
2164                name.equals(lb.resourceBundleName)) {
2165            return lb.userBundle;
2166        } else if (catalog != null && currentLocale.equals(catalogLocale)
2167                && name.equals(catalogName)) {
2168            return catalog;
2169        }
2170
2171        // Use the thread's context ClassLoader.  If there isn't one, use the
2172        // {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader}.
2173        ClassLoader cl = Thread.currentThread().getContextClassLoader();
2174        if (cl == null) {
2175            cl = ClassLoader.getSystemClassLoader();
2176        }
2177
2178        final Module callerModule = getCallerModule();
2179
2180        // If useCallersModule is false, we are called by logrb, with a name
2181        // that is provided by the user. In that case we will look in the TCCL.
2182        // We also look in the TCCL if callerModule is null or unnamed.
2183        if (!useCallersModule || callerModule == null || !callerModule.isNamed()) {
2184            try {
2185                Module mod = cl.getUnnamedModule();
2186                catalog = RB_ACCESS.getBundle(name, currentLocale, mod);
2187                catalogName = name;
2188                catalogLocale = currentLocale;
2189                return catalog;
2190            } catch (MissingResourceException ex) {
2191                // We can't find the ResourceBundle in the default
2192                // ClassLoader.  Drop through.
2193                if (useCallersModule && callerModule != null) {
2194                    try {
2195                        // We are called by an unnamed module: try with the
2196                        // unnamed module class loader:
2197                        PrivilegedAction<ClassLoader> getModuleClassLoader =
2198                                () -> callerModule.getClassLoader();
2199                        ClassLoader moduleCL =
2200                                AccessController.doPrivileged(getModuleClassLoader);
2201                        // moduleCL can be null if the logger is created by a class
2202                        // appended to the bootclasspath.
2203                        // If moduleCL is null we would use cl, but we already tried
2204                        // that above (we first looked in the TCCL for unnamed
2205                        // caller modules) - so there no point in trying again: we
2206                        // won't find anything more this second time.
2207                        // In this case just return null.
2208                        if (moduleCL == cl || moduleCL == null) return null;
2209
2210                        // we already tried the TCCL and found nothing - so try
2211                        // with the module's loader this time.
2212                        catalog = ResourceBundle.getBundle(name, currentLocale,
2213                                                           moduleCL);
2214                        catalogName = name;
2215                        catalogLocale = currentLocale;
2216                        return catalog;
2217                    } catch (MissingResourceException x) {
2218                        return null; // no luck
2219                    }
2220                } else {
2221                    return null;
2222                }
2223            }
2224        } else {
2225            // we should have:
2226            //  useCallersModule && callerModule != null && callerModule.isNamed();
2227            // Try with the caller's module
2228            try {
2229                // Use the caller's module
2230                catalog = RB_ACCESS.getBundle(name, currentLocale, callerModule);
2231                catalogName = name;
2232                catalogLocale = currentLocale;
2233                return catalog;
2234            } catch (MissingResourceException ex) {
2235                return null; // no luck
2236            }
2237        }
2238    }
2239
2240    private void setupResourceInfo(String name, Class<?> caller) {
2241        final Module module = caller == null ? null : caller.getModule();
2242        setupResourceInfo(name, module);
2243    }
2244
2245    // Private utility method to initialize our one entry
2246    // resource bundle name cache and the callers Module
2247    // Note: for consistency reasons, we are careful to check
2248    // that a suitable ResourceBundle exists before setting the
2249    // resourceBundleName field.
2250    // Synchronized to prevent races in setting the fields.
2251    private synchronized void setupResourceInfo(String name,
2252                                                Module callerModule) {
2253        final LoggerBundle lb = loggerBundle;
2254        if (lb.resourceBundleName != null) {
2255            // this Logger already has a ResourceBundle
2256
2257            if (lb.resourceBundleName.equals(name)) {
2258                // the names match so there is nothing more to do
2259                return;
2260            }
2261
2262            // cannot change ResourceBundles once they are set
2263            throw new IllegalArgumentException(
2264                lb.resourceBundleName + " != " + name);
2265        }
2266
2267        if (name == null) {
2268            return;
2269        }
2270
2271        setCallerModuleRef(callerModule);
2272
2273        if (isSystemLogger && (callerModule != null && !isSystem(callerModule))) {
2274            checkPermission();
2275        }
2276
2277        if (name.equals(SYSTEM_LOGGER_RB_NAME)) {
2278            loggerBundle = SYSTEM_BUNDLE;
2279        } else {
2280            ResourceBundle bundle = findResourceBundle(name, true);
2281            if (bundle == null) {
2282                // We've failed to find an expected ResourceBundle.
2283                // unset the caller's module since we were unable to find the
2284                // the bundle using it
2285                this.callerModuleRef = null;
2286                throw new MissingResourceException("Can't find " + name + " bundle from ",
2287                        name, "");
2288            }
2289
2290            loggerBundle = LoggerBundle.get(name, null);
2291        }
2292    }
2293
2294    /**
2295     * Sets a resource bundle on this logger.
2296     * All messages will be logged using the given resource bundle for its
2297     * specific {@linkplain ResourceBundle#getLocale locale}.
2298     * @param bundle The resource bundle that this logger shall use.
2299     * @throws NullPointerException if the given bundle is {@code null}.
2300     * @throws IllegalArgumentException if the given bundle doesn't have a
2301     *         {@linkplain ResourceBundle#getBaseBundleName base name},
2302     *         or if this logger already has a resource bundle set but
2303     *         the given bundle has a different base name.
2304     * @throws SecurityException if a security manager exists,
2305     *         this logger is not anonymous, and the caller
2306     *         does not have LoggingPermission("control").
2307     * @since 1.8
2308     */
2309    public void setResourceBundle(ResourceBundle bundle) {
2310        checkPermission();
2311
2312        // Will throw NPE if bundle is null.
2313        final String baseName = bundle.getBaseBundleName();
2314
2315        // bundle must have a name
2316        if (baseName == null || baseName.isEmpty()) {
2317            throw new IllegalArgumentException("resource bundle must have a name");
2318        }
2319
2320        synchronized (this) {
2321            LoggerBundle lb = loggerBundle;
2322            final boolean canReplaceResourceBundle = lb.resourceBundleName == null
2323                    || lb.resourceBundleName.equals(baseName);
2324
2325            if (!canReplaceResourceBundle) {
2326                throw new IllegalArgumentException("can't replace resource bundle");
2327            }
2328
2329
2330            loggerBundle = LoggerBundle.get(baseName, bundle);
2331        }
2332    }
2333
2334    /**
2335     * Return the parent for this Logger.
2336     * <p>
2337     * This method returns the nearest extant parent in the namespace.
2338     * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b"
2339     * has been created but no logger "a.b.c" exists, then a call of
2340     * getParent on the Logger "a.b.c.d" will return the Logger "a.b".
2341     * <p>
2342     * The result will be null if it is called on the root Logger
2343     * in the namespace.
2344     *
2345     * @return nearest existing parent Logger
2346     */
2347    public Logger getParent() {
2348        // Note: this used to be synchronized on treeLock.  However, this only
2349        // provided memory semantics, as there was no guarantee that the caller
2350        // would synchronize on treeLock (in fact, there is no way for external
2351        // callers to so synchronize).  Therefore, we have made parent volatile
2352        // instead.
2353        return parent;
2354    }
2355
2356    /**
2357     * Set the parent for this Logger.  This method is used by
2358     * the LogManager to update a Logger when the namespace changes.
2359     * <p>
2360     * It should not be called from application code.
2361     *
2362     * @param  parent   the new parent logger
2363     * @throws  SecurityException  if a security manager exists and if
2364     *          the caller does not have LoggingPermission("control").
2365     */
2366    public void setParent(Logger parent) {
2367        if (parent == null) {
2368            throw new NullPointerException();
2369        }
2370
2371        // check permission for all loggers, including anonymous loggers
2372        if (manager == null) {
2373            manager = LogManager.getLogManager();
2374        }
2375        manager.checkPermission();
2376
2377        doSetParent(parent);
2378    }
2379
2380    // Private method to do the work for parenting a child
2381    // Logger onto a parent logger.
2382    private void doSetParent(Logger newParent) {
2383
2384        // System.err.println("doSetParent \"" + getName() + "\" \""
2385        //                              + newParent.getName() + "\"");
2386
2387        synchronized (treeLock) {
2388
2389            // Remove ourself from any previous parent.
2390            LogManager.LoggerWeakRef ref = null;
2391            if (parent != null) {
2392                // assert parent.kids != null;
2393                for (Iterator<LogManager.LoggerWeakRef> iter = parent.kids.iterator(); iter.hasNext(); ) {
2394                    ref = iter.next();
2395                    Logger kid =  ref.get();
2396                    if (kid == this) {
2397                        // ref is used down below to complete the reparenting
2398                        iter.remove();
2399                        break;
2400                    } else {
2401                        ref = null;
2402                    }
2403                }
2404                // We have now removed ourself from our parents' kids.
2405            }
2406
2407            // Set our new parent.
2408            parent = newParent;
2409            if (parent.kids == null) {
2410                parent.kids = new ArrayList<>(2);
2411            }
2412            if (ref == null) {
2413                // we didn't have a previous parent
2414                ref = manager.new LoggerWeakRef(this);
2415            }
2416            ref.setParentRef(new WeakReference<>(parent));
2417            parent.kids.add(ref);
2418
2419            // As a result of the reparenting, the effective level
2420            // may have changed for us and our children.
2421            updateEffectiveLevel();
2422
2423        }
2424    }
2425
2426    // Package-level method.
2427    // Remove the weak reference for the specified child Logger from the
2428    // kid list. We should only be called from LoggerWeakRef.dispose().
2429    final void removeChildLogger(LogManager.LoggerWeakRef child) {
2430        synchronized (treeLock) {
2431            for (Iterator<LogManager.LoggerWeakRef> iter = kids.iterator(); iter.hasNext(); ) {
2432                LogManager.LoggerWeakRef ref = iter.next();
2433                if (ref == child) {
2434                    iter.remove();
2435                    return;
2436                }
2437            }
2438        }
2439    }
2440
2441    // Recalculate the effective level for this node and
2442    // recursively for our children.
2443
2444    private void updateEffectiveLevel() {
2445        // assert Thread.holdsLock(treeLock);
2446
2447        // Figure out our current effective level.
2448        int newLevelValue;
2449        final ConfigurationData cfg = config;
2450        final Level levelObject = cfg.levelObject;
2451        if (levelObject != null) {
2452            newLevelValue = levelObject.intValue();
2453        } else {
2454            if (parent != null) {
2455                newLevelValue = parent.config.levelValue;
2456            } else {
2457                // This may happen during initialization.
2458                newLevelValue = Level.INFO.intValue();
2459            }
2460        }
2461
2462        // If our effective value hasn't changed, we're done.
2463        if (cfg.levelValue == newLevelValue) {
2464            return;
2465        }
2466
2467        cfg.setLevelValue(newLevelValue);
2468
2469        // System.err.println("effective level: \"" + getName() + "\" := " + level);
2470
2471        // Recursively update the level on each of our kids.
2472        if (kids != null) {
2473            for (LogManager.LoggerWeakRef ref : kids) {
2474                Logger kid = ref.get();
2475                if (kid != null) {
2476                    kid.updateEffectiveLevel();
2477                }
2478            }
2479        }
2480    }
2481
2482
2483    // Private method to get the potentially inherited
2484    // resource bundle and resource bundle name for this Logger.
2485    // This method never returns null.
2486    private LoggerBundle getEffectiveLoggerBundle() {
2487        final LoggerBundle lb = loggerBundle;
2488        if (lb.isSystemBundle()) {
2489            return SYSTEM_BUNDLE;
2490        }
2491
2492        // first take care of this logger
2493        final ResourceBundle b = getResourceBundle();
2494        if (b != null && b == lb.userBundle) {
2495            return lb;
2496        } else if (b != null) {
2497            // either lb.userBundle is null or getResourceBundle() is
2498            // overriden
2499            final String rbName = getResourceBundleName();
2500            return LoggerBundle.get(rbName, b);
2501        }
2502
2503        // no resource bundle was specified on this logger, look up the
2504        // parent stack.
2505        Logger target = this.parent;
2506        while (target != null) {
2507            final LoggerBundle trb = target.loggerBundle;
2508            if (trb.isSystemBundle()) {
2509                return SYSTEM_BUNDLE;
2510            }
2511            if (trb.userBundle != null) {
2512                return trb;
2513            }
2514            final String rbName = isSystemLogger
2515                // ancestor of a system logger is expected to be a system logger.
2516                // ignore resource bundle name if it's not.
2517                ? (target.isSystemLogger ? trb.resourceBundleName : null)
2518                : target.getResourceBundleName();
2519            if (rbName != null) {
2520                return LoggerBundle.get(rbName,
2521                        findResourceBundle(rbName, true));
2522            }
2523            target = isSystemLogger ? target.parent : target.getParent();
2524        }
2525        return NO_RESOURCE_BUNDLE;
2526    }
2527
2528}
2529