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