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