Home | History | Annotate | Download | only in logging
      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 
     28 package java.util.logging;
     29 
     30 import dalvik.system.VMStack;
     31 import java.lang.ref.WeakReference;
     32 import java.security.AccessController;
     33 import java.security.PrivilegedAction;
     34 import java.util.ArrayList;
     35 import java.util.Iterator;
     36 import java.util.Locale;
     37 import java.util.MissingResourceException;
     38 import java.util.ResourceBundle;
     39 import java.util.concurrent.CopyOnWriteArrayList;
     40 import java.util.function.Supplier;
     41 import 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  */
    219 public 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