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