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