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