1 /*
2  * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */

25
26 package java.util.logging;
27
28 import java.lang.ref.WeakReference;
29 import java.security.AccessController;
30 import java.security.PrivilegedAction;
31 import java.util.ArrayList;
32 import java.util.Iterator;
33 import java.util.Locale;
34 import java.util.MissingResourceException;
35 import java.util.Objects;
36 import java.util.ResourceBundle;
37 import java.util.concurrent.CopyOnWriteArrayList;
38 import java.util.function.Supplier;
39
40 import jdk.internal.misc.JavaUtilResourceBundleAccess;
41 import jdk.internal.misc.SharedSecrets;
42 import jdk.internal.reflect.CallerSensitive;
43 import jdk.internal.reflect.Reflection;
44 import static jdk.internal.logger.DefaultLoggerFinder.isSystem;
45
46 /**
47  * A Logger object is used to log messages for a specific
48  * system or application component.  Loggers are normally named,
49  * using a hierarchical dot-separated namespace.  Logger names
50  * can be arbitrary strings, but they should normally be based on
51  * the package name or class name of the logged component, such
52  * as java.net or javax.swing.  In addition it is possible to create
53  * "anonymous" Loggers that are not stored in the Logger namespace.
54  * <p>
55  * Logger objects may be obtained by calls on one of the getLogger
56  * factory methods.  These will either create a new Logger or
57  * return a suitable existing Logger. It is important to note that
58  * the Logger returned by one of the {@code getLogger} factory methods
59  * may be garbage collected at any time if a strong reference to the
60  * Logger is not kept.
61  * <p>
62  * Logging messages will be forwarded to registered Handler
63  * objects, which can forward the messages to a variety of
64  * destinations, including consoles, files, OS logs, etc.
65  * <p>
66  * Each Logger keeps track of a "parent" Logger, which is its
67  * nearest existing ancestor in the Logger namespace.
68  * <p>
69  * Each Logger has a "Level" associated with it.  This reflects
70  * a minimum Level that this logger cares about.  If a Logger's
71  * level is set to {@code null}, then its effective level is inherited
72  * from its parent, which may in turn obtain it recursively from its
73  * parent, and so on up the tree.
74  * <p>
75  * The log level can be configured based on the properties from the
76  * logging configuration file, as described in the description
77  * of the LogManager class.  However it may also be dynamically changed
78  * by calls on the Logger.setLevel method.  If a logger's level is
79  * changed the change may also affect child loggers, since any child
80  * logger that has {@code null} as its level will inherit its
81  * effective level from its parent.
82  * <p>
83  * On each logging call the Logger initially performs a cheap
84  * check of the request level (e.g., SEVERE or FINE) against the
85  * effective log level of the logger.  If the request level is
86  * lower than the log level, the logging call returns immediately.
87  * <p>
88  * After passing this initial (cheap) test, the Logger will allocate
89  * a LogRecord to describe the logging message.  It will then call a
90  * Filter (if present) to do a more detailed check on whether the
91  * record should be published.  If that passes it will then publish
92  * the LogRecord to its output Handlers.  By default, loggers also
93  * publish to their parent's Handlers, recursively up the tree.
94  * <p>
95  * Each Logger may have a {@code ResourceBundle} associated with it.
96  * The {@code ResourceBundle} may be specified by name, using the
97  * {@link #getLogger(java.lang.String, java.lang.String)} factory
98  * method, or by value - using the {@link
99  * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method.
100  * This bundle will be used for localizing logging messages.
101  * If a Logger does not have its own {@code ResourceBundle} or resource bundle
102  * name, then it will inherit the {@code ResourceBundle} or resource bundle name
103  * from its parent, recursively up the tree.
104  * <p>
105  * Most of the logger output methods take a "msg" argument.  This
106  * msg argument may be either a raw value or a localization key.
107  * During formatting, if the logger has (or inherits) a localization
108  * {@code ResourceBundle} and if the {@code ResourceBundle} has a mapping for
109  * the msg string, then the msg string is replaced by the localized value.
110  * Otherwise the original msg string is used.  Typically, formatters use
111  * java.text.MessageFormat style formatting to format parameters, so
112  * for example a format string "{0} {1}" would format two parameters
113  * as strings.
114  * <p>
115  * A set of methods alternatively take a "msgSupplier" instead of a "msg"
116  * argument.  These methods take a {@link Supplier}{@code <String>} function
117  * which is invoked to construct the desired log message only when the message
118  * actually is to be logged based on the effective log level thus eliminating
119  * unnecessary message construction. For example, if the developer wants to
120  * log system health status for diagnosis, with the String-accepting version,
121  * the code would look like:
122  * <pre>{@code
123  *
124  *  class DiagnosisMessages {
125  *    static String systemHealthStatus() {
126  *      // collect system health information
127  *      ...
128  *    }
129  *  }
130  *  ...
131  *  logger.log(Level.FINER, DiagnosisMessages.systemHealthStatus());
132  * }</pre>
133  * With the above code, the health status is collected unnecessarily even when
134  * the log level FINER is disabled. With the Supplier-accepting version as
135  * below, the status will only be collected when the log level FINER is
136  * enabled.
137  * <pre>{@code
138  *
139  *  logger.log(Level.FINER, DiagnosisMessages::systemHealthStatus);
140  * }</pre>
141  * <p>
142  * When looking for a {@code ResourceBundle}, the logger will first look at
143  * whether a bundle was specified using {@link
144  * #setResourceBundle(java.util.ResourceBundle) setResourceBundle}, and then
145  * only whether a resource bundle name was specified through the {@link
146  * #getLogger(java.lang.String, java.lang.String) getLogger} factory method.
147  * If no {@code ResourceBundle} or no resource bundle name is found,
148  * then it will use the nearest {@code ResourceBundle} or resource bundle
149  * name inherited from its parent tree.<br>
150  * When a {@code ResourceBundle} was inherited or specified through the
151  * {@link
152  * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method, then
153  * that {@code ResourceBundle} will be used. Otherwise if the logger only
154  * has or inherited a resource bundle name, then that resource bundle name
155  * will be mapped to a {@code ResourceBundle} object, using the default Locale
156  * at the time of logging.
157  * <br id="ResourceBundleMapping">When mapping resource bundle names to
158  * {@code ResourceBundle} objects, the logger will first try to use the
159  * Thread's {@linkplain java.lang.Thread#getContextClassLoader() context class
160  * loader} to map the given resource bundle name to a {@code ResourceBundle}.
161  * If the thread context class loader is {@code null}, it will try the
162  * {@linkplain java.lang.ClassLoader#getSystemClassLoader() system class loader}
163  * instead.  If the {@code ResourceBundle} is still not found, it will use the
164  * class loader of the first caller of the {@link
165  * #getLogger(java.lang.String, java.lang.String) getLogger} factory method.
166  * <p>
167  * Formatting (including localization) is the responsibility of
168  * the output Handler, which will typically call a Formatter.
169  * <p>
170  * Note that formatting need not occur synchronously.  It may be delayed
171  * until a LogRecord is actually written to an external sink.
172  * <p>
173  * The logging methods are grouped in five main categories:
174  * <ul>
175  * <li><p>
176  *     There are a set of "log" methods that take a log level, a message
177  *     string, and optionally some parameters to the message string.
178  * <li><p>
179  *     There are a set of "logp" methods (for "log precise") that are
180  *     like the "log" methods, but also take an explicit source class name
181  *     and method name.
182  * <li><p>
183  *     There are a set of "logrb" method (for "log with resource bundle")
184  *     that are like the "logp" method, but also take an explicit resource
185  *     bundle object for use in localizing the log message.
186  * <li><p>
187  *     There are convenience methods for tracing method entries (the
188  *     "entering" methods), method returns (the "exiting" methods) and
189  *     throwing exceptions (the "throwing" methods).
190  * <li><p>
191  *     Finally, there are a set of convenience methods for use in the
192  *     very simplest cases, when a developer simply wants to log a
193  *     simple string at a given log level.  These methods are named
194  *     after the standard Level names ("severe""warning""info", etc.)
195  *     and take a single argument, a message string.
196  * </ul>
197  * <p>
198  * For the methods that do not take an explicit source name and
199  * method name, the Logging framework will make a "best effort"
200  * to determine which class and method called into the logging method.
201  * However, it is important to realize that this automatically inferred
202  * information may only be approximate (or may even be quite wrong!).
203  * Virtual machines are allowed to do extensive optimizations when
204  * JITing and may entirely remove stack frames, making it impossible
205  * to reliably locate the calling class and method.
206  * <P>
207  * All methods on Logger are multi-thread safe.
208  * <p>
209  * <b>Subclassing Information:</b> Note that a LogManager class may
210  * provide its own implementation of named Loggers for any point in
211  * the namespace.  Therefore, any subclasses of Logger (unless they
212  * are implemented in conjunction with a new LogManager class) should
213  * take care to obtain a Logger instance from the LogManager class and
214  * should delegate operations such as "isLoggable" and "log(LogRecord)"
215  * to that instance.  Note that in order to intercept all logging
216  * output, subclasses need only override the log(LogRecord) method.
217  * All the other logging methods are implemented as calls on this
218  * log(LogRecord) method.
219  *
220  * @since 1.4
221  */

222 public class Logger {
223     private static final Handler emptyHandlers[] = new Handler[0];
224     private static final int offValue = Level.OFF.intValue();
225
226     static final String SYSTEM_LOGGER_RB_NAME = "sun.util.logging.resources.logging";
227
228     // This class is immutable and it is important that it remains so.
229     private static final class LoggerBundle {
230         final String resourceBundleName; // Base name of the bundle.
231         final ResourceBundle userBundle; // Bundle set through setResourceBundle.
232         private LoggerBundle(String resourceBundleName, ResourceBundle bundle) {
233             this.resourceBundleName = resourceBundleName;
234             this.userBundle = bundle;
235         }
236         boolean isSystemBundle() {
237             return SYSTEM_LOGGER_RB_NAME.equals(resourceBundleName);
238         }
239         static LoggerBundle get(String name, ResourceBundle bundle) {
240             if (name == null && bundle == null) {
241                 return NO_RESOURCE_BUNDLE;
242             } else if (SYSTEM_LOGGER_RB_NAME.equals(name) && bundle == null) {
243                 return SYSTEM_BUNDLE;
244             } else {
245                 return new LoggerBundle(name, bundle);
246             }
247         }
248     }
249
250     // This instance will be shared by all loggers created by the system
251     // code
252     private static final LoggerBundle SYSTEM_BUNDLE =
253             new LoggerBundle(SYSTEM_LOGGER_RB_NAME, null);
254
255     // This instance indicates that no resource bundle has been specified yet,
256     // and it will be shared by all loggers which have no resource bundle.
257     private static final LoggerBundle NO_RESOURCE_BUNDLE =
258             new LoggerBundle(nullnull);
259
260     // Calling SharedSecrets.getJavaUtilResourceBundleAccess()
261     // forces the initialization of ResourceBundle.class, which
262     // can be too early if the VM has not finished booting yet.
263     private static final class RbAccess {
264         static final JavaUtilResourceBundleAccess RB_ACCESS =
265             SharedSecrets.getJavaUtilResourceBundleAccess();
266     }
267
268     // A value class that holds the logger configuration data.
269     // This configuration can be shared between an application logger
270     // and a system logger of the same name.
271     private static final class ConfigurationData {
272
273         // The delegate field is used to avoid races while
274         // merging configuration. This will ensure that any pending
275         // configuration action on an application logger will either
276         // be finished before the merge happens, or will be forwarded
277         // to the system logger configuration after the merge is completed.
278         // By default delegate=this.
279         private volatile ConfigurationData delegate;
280
281         volatile boolean useParentHandlers;
282         volatile Filter filter;
283         volatile Level levelObject;
284         volatile int levelValue;  // current effective level value
285         final CopyOnWriteArrayList<Handler> handlers =
286             new CopyOnWriteArrayList<>();
287
288         ConfigurationData() {
289             delegate = this;
290             useParentHandlers = true;
291             levelValue = Level.INFO.intValue();
292         }
293
294         void setUseParentHandlers(boolean flag) {
295             useParentHandlers = flag;
296             if (delegate != this) {
297                 // merge in progress - propagate value to system peer.
298                 final ConfigurationData system = delegate;
299                 synchronized (system) {
300                     system.useParentHandlers = useParentHandlers;
301                 }
302             }
303         }
304
305         void setFilter(Filter f) {
306             filter = f;
307             if (delegate != this) {
308                 // merge in progress - propagate value to system peer.
309                 final ConfigurationData system = delegate;
310                 synchronized (system) {
311                     system.filter = filter;
312                 }
313             }
314         }
315
316         void setLevelObject(Level l) {
317             levelObject = l;
318             if (delegate != this) {
319                 // merge in progress - propagate value to system peer.
320                 final ConfigurationData system = delegate;
321                 synchronized (system) {
322                     system.levelObject = levelObject;
323                 }
324             }
325         }
326
327         void setLevelValue(int v) {
328             levelValue = v;
329             if (delegate != this) {
330                 // merge in progress - propagate value to system peer.
331                 final ConfigurationData system = delegate;
332                 synchronized (system) {
333                     system.levelValue = levelValue;
334                 }
335             }
336         }
337
338         void addHandler(Handler h) {
339             if (handlers.add(h)) {
340                 if (delegate != this) {
341                     // merge in progress - propagate value to system peer.
342                     final ConfigurationData system = delegate;
343                     synchronized (system) {
344                         system.handlers.addIfAbsent(h);
345                     }
346                 }
347             }
348         }
349
350         void removeHandler(Handler h) {
351             if (handlers.remove(h)) {
352                 if (delegate != this) {
353                     // merge in progress - propagate value to system peer.
354                     final ConfigurationData system = delegate;
355                     synchronized (system) {
356                         system.handlers.remove(h);
357                     }
358                 }
359             }
360         }
361
362         ConfigurationData merge(Logger systemPeer) {
363             if (!systemPeer.isSystemLogger) {
364                 // should never come here
365                 throw new InternalError("not a system logger");
366             }
367
368             ConfigurationData system = systemPeer.config;
369
370             if (system == this) {
371                 // nothing to do
372                 return system;
373             }
374
375             synchronized (system) {
376                 // synchronize before checking on delegate to counter
377                 // race conditions where two threads might attempt to
378                 // merge concurrently
379                 if (delegate == system) {
380                     // merge already performed;
381                     return system;
382                 }
383
384                 // publish system as the temporary delegate configuration.
385                 // This should take care of potential race conditions where
386                 // an other thread might attempt to call e.g. setlevel on
387                 // the application logger while merge is in progress.
388                 // (see implementation of ConfigurationData::setLevel)
389                 delegate = system;
390
391                 // merge this config object data into the system config
392                 system.useParentHandlers = useParentHandlers;
393                 system.filter = filter;
394                 system.levelObject = levelObject;
395                 system.levelValue = levelValue;
396
397                 // Prevent race condition in case two threads attempt to merge
398                 // configuration and add handlers at the same time. We don't want
399                 // to add the same handlers twice.
400                 //
401                 // Handlers are created and loaded by LogManager.addLogger. If we
402                 // reach here, then it means that the application logger has
403                 // been created first and added with LogManager.addLogger, and the
404                 // system logger was created after - and no handler has been added
405                 // to it by LogManager.addLogger. Therefore, system.handlers
406                 // should be empty.
407                 //
408                 // A non empty cfg.handlers list indicates a race condition
409                 // where two threads might attempt to merge the configuration
410                 // or add handlers concurrently. Though of no consequence for
411                 // the other data (level etc...) this would be an issue if we
412                 // added the same handlers twice.
413                 //
414                 for (Handler h : handlers) {
415                     if (!system.handlers.contains(h)) {
416                         systemPeer.addHandler(h);
417                     }
418                 }
419                 system.handlers.retainAll(handlers);
420                 system.handlers.addAllAbsent(handlers);
421             }
422
423             // sanity: update effective level after merging
424             synchronized(treeLock) {
425                 systemPeer.updateEffectiveLevel();
426             }
427
428             return system;
429         }
430
431     }
432
433     // The logger configuration data. Ideally, this should be final
434     // for system loggers, and replace-once for application loggers.
435     // When an application requests a logger by name, we do not know a-priori
436     // whether that corresponds to a system logger name or not.
437     // So if no system logger by that name already exists, we simply return an
438     // application logger.
439     // If a system class later requests a system logger of the same name, then
440     // the application logger and system logger configurations will be merged
441     // in a single instance of ConfigurationData that both loggers will share.
442     private volatile ConfigurationData config;
443
444     private volatile LogManager manager;
445     private String name;
446     private volatile LoggerBundle loggerBundle = NO_RESOURCE_BUNDLE;
447     private boolean anonymous;
448
449     // Cache to speed up behavior of findResourceBundle:
450     private ResourceBundle catalog;     // Cached resource bundle
451     private String catalogName;         // name associated with catalog
452     private Locale catalogLocale;       // locale associated with catalog
453
454     // The fields relating to parent-child relationships and levels
455     // are managed under a separate lock, the treeLock.
456     private static final Object treeLock = new Object();
457     // We keep weak references from parents to children, but strong
458     // references from children to parents.
459     private volatile Logger parent;    // our nearest parent.
460     private ArrayList<LogManager.LoggerWeakRef> kids;   // WeakReferences to loggers that have us as parent
461     private WeakReference<Module> callerModuleRef;
462     private final boolean isSystemLogger;
463
464     /**
465      * GLOBAL_LOGGER_NAME is a name for the global logger.
466      *
467      * @since 1.6
468      */

469     public static final String GLOBAL_LOGGER_NAME = "global";
470
471     /**
472      * Return global logger object with the name Logger.GLOBAL_LOGGER_NAME.
473      *
474      * @return global logger object
475      * @since 1.7
476      */

477     public static final Logger getGlobal() {
478         // In order to break a cyclic dependence between the LogManager
479         // and Logger static initializers causing deadlocks, the global
480         // logger is created with a special constructor that does not
481         // initialize its log manager.
482         //
483         // If an application calls Logger.getGlobal() before any logger
484         // has been initialized, it is therefore possible that the
485         // LogManager class has not been initialized yet, and therefore
486         // Logger.global.manager will be null.
487         //
488         // In order to finish the initialization of the global logger, we
489         // will therefore call LogManager.getLogManager() here.
490         //
491         // To prevent race conditions we also need to call
492         // LogManager.getLogManager() unconditionally here.
493         // Indeed we cannot rely on the observed value of global.manager,
494         // because global.manager will become not null somewhere during
495         // the initialization of LogManager.
496         // If two threads are calling getGlobal() concurrently, one thread
497         // will see global.manager null and call LogManager.getLogManager(),
498         // but the other thread could come in at a time when global.manager
499         // is already set although ensureLogManagerInitialized is not finished
500         // yet...
501         // Calling LogManager.getLogManager() unconditionally will fix that.
502
503         LogManager.getLogManager();
504
505         // Now the global LogManager should be initialized,
506         // and the global logger should have been added to
507         // it, unless we were called within the constructor of a LogManager
508         // subclass installed as LogManager, in which case global.manager
509         // would still be null, and global will be lazily initialized later on.
510
511         return global;
512     }
513
514     /**
515      * The "global" Logger object is provided as a convenience to developers
516      * who are making casual use of the Logging package.  Developers
517      * who are making serious use of the logging package (for example
518      * in products) should create and use their own Logger objects,
519      * with appropriate names, so that logging can be controlled on a
520      * suitable per-Logger granularity. Developers also need to keep a
521      * strong reference to their Logger objects to prevent them from
522      * being garbage collected.
523      *
524      * @deprecated Initialization of this field is prone to deadlocks.
525      * The field must be initialized by the Logger class initialization
526      * which may cause deadlocks with the LogManager class initialization.
527      * In such cases two class initialization wait for each other to complete.
528      * The preferred way to get the global logger object is via the call
529      * {@code Logger.getGlobal()}.
530      * For compatibility with old JDK versions where the
531      * {@code Logger.getGlobal()} is not available use the call
532      * {@code Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)}
533      * or {@code Logger.getLogger("global")}.
534      */

535     @Deprecated
536     public static final Logger global = new Logger(GLOBAL_LOGGER_NAME);
537
538     /**
539      * Protected method to construct a logger for a named subsystem.
540      * <p>
541      * The logger will be initially configured with a null Level
542      * and with useParentHandlers set to true.
543      *
544      * @param   name    A name for the logger.  This should
545      *                          be a dot-separated name and should normally
546      *                          be based on the package name or class name
547      *                          of the subsystem, such as java.net
548      *                          or javax.swing.  It may be null for anonymous Loggers.
549      * @param   resourceBundleName  name of ResourceBundle to be used for localizing
550      *                          messages for this logger.  May be null if none
551      *                          of the messages require localization.
552      * @throws MissingResourceException if the resourceBundleName is non-null and
553      *             no corresponding resource can be found.
554      */

555     protected Logger(String name, String resourceBundleName) {
556         this(name, resourceBundleName, null, LogManager.getLogManager(), false);
557     }
558
559     Logger(String name, String resourceBundleName, Module caller,
560            LogManager manager, boolean isSystemLogger) {
561         this.manager = manager;
562         this.isSystemLogger = isSystemLogger;
563         this.config = new ConfigurationData();
564         this.name = name;
565         setupResourceInfo(resourceBundleName, caller);
566     }
567
568     // Called by LogManager when a system logger is created
569     // after a user logger of the same name.
570     // Ensure that both loggers will share the same
571     // configuration.
572     final void mergeWithSystemLogger(Logger system) {
573         // sanity checks
574         if (!system.isSystemLogger
575                 || anonymous
576                 || name == null
577                 || !name.equals(system.name)) {
578             // should never come here
579             throw new InternalError("invalid logger merge");
580         }
581         checkPermission();
582         final ConfigurationData cfg = config;
583         if (cfg != system.config) {
584             config = cfg.merge(system);
585         }
586     }
587
588     private void setCallerModuleRef(Module callerModule) {
589         if (callerModule != null) {
590             this.callerModuleRef = new WeakReference<>(callerModule);
591         }
592     }
593
594     private Module getCallerModule() {
595         return (callerModuleRef != null)
596                 ? callerModuleRef.get()
597                 : null;
598     }
599
600     // This constructor is used only to create the global Logger.
601     // It is needed to break a cyclic dependence between the LogManager
602     // and Logger static initializers causing deadlocks.
603     private Logger(String name) {
604         // The manager field is not initialized here.
605         this.name = name;
606         this.isSystemLogger = true;
607         config = new ConfigurationData();
608     }
609
610     // It is called from LoggerContext.addLocalLogger() when the logger
611     // is actually added to a LogManager.
612     void setLogManager(LogManager manager) {
613         this.manager = manager;
614     }
615
616     private void checkPermission() throws SecurityException {
617         if (!anonymous) {
618             if (manager == null) {
619                 // Complete initialization of the global Logger.
620                 manager = LogManager.getLogManager();
621             }
622             manager.checkPermission();
623         }
624     }
625
626     // Until all JDK code converted to call sun.util.logging.PlatformLogger
627     // (see 7054233), we need to determine if Logger.getLogger is to add
628     // a system logger or user logger.
629     //
630     // As an interim solution, if the immediate caller whose caller loader is
631     // null, we assume it's a system logger and add it to the system context.
632     // These system loggers only set the resource bundle to the given
633     // resource bundle name (rather than the default system resource bundle).
634     private static class SystemLoggerHelper {
635         static boolean disableCallerCheck = getBooleanProperty("sun.util.logging.disableCallerCheck");
636         private static boolean getBooleanProperty(final String key) {
637             String s = AccessController.doPrivileged(new PrivilegedAction<String>() {
638                 @Override
639                 public String run() {
640                     return System.getProperty(key);
641                 }
642             });
643             return Boolean.parseBoolean(s);
644         }
645     }
646
647     private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
648         LogManager manager = LogManager.getLogManager();
649         if (!SystemLoggerHelper.disableCallerCheck) {
650             if (isSystem(caller.getModule())) {
651                 return manager.demandSystemLogger(name, resourceBundleName, caller);
652             }
653         }
654         return manager.demandLogger(name, resourceBundleName, caller);
655         // ends up calling new Logger(name, resourceBundleName, caller)
656         // iff the logger doesn't exist already
657     }
658
659     /**
660      * Find or create a logger for a named subsystem.  If a logger has
661      * already been created with the given name it is returned.  Otherwise
662      * a new logger is created.
663      * <p>
664      * If a new logger is created its log level will be configured
665      * based on the LogManager configuration and it will be configured
666      * to also send logging output to its parent's Handlers.  It will
667      * be registered in the LogManager global namespace.
668      * <p>
669      * Note: The LogManager may only retain a weak reference to the newly
670      * created Logger. It is important to understand that a previously
671      * created Logger with the given name may be garbage collected at any
672      * time if there is no strong reference to the Logger. In particular,
673      * this means that two back-to-back calls like
674      * {@code getLogger("MyLogger").log(...)} may use different Logger
675      * objects named "MyLogger" if there is no strong reference to the
676      * Logger named "MyLogger" elsewhere in the program.
677      *
678      * @param   name            A name for the logger.  This should
679      *                          be a dot-separated name and should normally
680      *                          be based on the package name or class name
681      *                          of the subsystem, such as java.net
682      *                          or javax.swing
683      * @return a suitable Logger
684      * @throws NullPointerException if the name is null.
685      */

686
687     // Synchronization is not required here. All synchronization for
688     // adding a new Logger object is handled by LogManager.addLogger().
689     @CallerSensitive
690     public static Logger getLogger(String name) {
691         // This method is intentionally not a wrapper around a call
692         // to getLogger(name, resourceBundleName). If it were then
693         // this sequence:
694         //
695         //     getLogger("Foo""resourceBundleForFoo");
696         //     getLogger("Foo");
697         //
698         // would throw an IllegalArgumentException in the second call
699         // because the wrapper would result in an attempt to replace
700         // the existing "resourceBundleForFoo" with null.
701         return Logger.getLogger(name, Reflection.getCallerClass());
702     }
703
704     /**
705      * Find or create a logger for a named subsystem on behalf
706      * of the given caller.
707      *
708      * This method is called by {@link #getLogger(java.lang.String)} after
709      * it has obtained a reference to its caller's class.
710      *
711      * @param   name            A name for the logger.
712      * @param   callerClass     The class that called {@link
713      *                          #getLogger(java.lang.String)}.
714      * @return a suitable Logger for {@code callerClass}.
715      */

716     private static Logger getLogger(String name, Class<?> callerClass) {
717         return demandLogger(name, null, callerClass);
718     }
719
720     /**
721      * Find or create a logger for a named subsystem.  If a logger has
722      * already been created with the given name it is returned.  Otherwise
723      * a new logger is created.
724      *
725      * <p>
726      * If a new logger is created its log level will be configured
727      * based on the LogManager and it will be configured to also send logging
728      * output to its parent's Handlers.  It will be registered in
729      * the LogManager global namespace.
730      * <p>
731      * Note: The LogManager may only retain a weak reference to the newly
732      * created Logger. It is important to understand that a previously
733      * created Logger with the given name may be garbage collected at any
734      * time if there is no strong reference to the Logger. In particular,
735      * this means that two back-to-back calls like
736      * {@code getLogger("MyLogger", ...).log(...)} may use different Logger
737      * objects named "MyLogger" if there is no strong reference to the
738      * Logger named "MyLogger" elsewhere in the program.
739      * <p>
740      * If the named Logger already exists and does not yet have a
741      * localization resource bundle then the given resource bundle
742      * name is used. If the named Logger already exists and has
743      * a different resource bundle name then an IllegalArgumentException
744      * is thrown.
745      *
746      * @param   name    A name for the logger.  This should
747      *                          be a dot-separated name and should normally
748      *                          be based on the package name or class name
749      *                          of the subsystem, such as java.net
750      *                          or javax.swing
751      * @param   resourceBundleName  name of ResourceBundle to be used for localizing
752      *                          messages for this logger. May be {@code null}
753      *                          if none of the messages require localization.
754      * @return a suitable Logger
755      * @throws MissingResourceException if the resourceBundleName is non-null and
756      *             no corresponding resource can be found.
757      * @throws IllegalArgumentException if the Logger already exists and uses
758      *             a different resource bundle name; or if
759      *             {@code resourceBundleName} is {@code null} but the named
760      *             logger has a resource bundle set.
761      * @throws NullPointerException if the name is null.
762      */

763
764     // Synchronization is not required here. All synchronization for
765     // adding a new Logger object is handled by LogManager.addLogger().
766     @CallerSensitive
767     public static Logger getLogger(String name, String resourceBundleName) {
768         return Logger.getLogger(name, resourceBundleName, Reflection.getCallerClass());
769     }
770
771     /**
772      * Find or create a logger for a named subsystem on behalf
773      * of the given caller.
774      *
775      * This method is called by {@link
776      * #getLogger(java.lang.String, java.lang.String)} after
777      * it has obtained a reference to its caller's class.
778      *
779      * @param   name            A name for the logger.
780      * @param   resourceBundleName  name of ResourceBundle to be used for localizing
781      *                          messages for this logger. May be {@code null}
782      *                          if none of the messages require localization.
783      * @param   callerClass     The class that called {@link
784      *                          #getLogger(java.lang.String, java.lang.String)}.
785      *                          This class will also be used for locating the
786      *                          resource bundle if {@code resourceBundleName} is
787      *                          not {@code null}.
788      * @return a suitable Logger for {@code callerClass}.
789      */

790     private static Logger getLogger(String name, String resourceBundleName,
791                                     Class<?> callerClass) {
792         Logger result = demandLogger(name, resourceBundleName, callerClass);
793
794         // MissingResourceException or IllegalArgumentException can be
795         // thrown by setupResourceInfo().
796         // We have to set the callers ClassLoader here in case demandLogger
797         // above found a previously created Logger.  This can happen, for
798         // example, if Logger.getLogger(name) is called and subsequently
799         // Logger.getLogger(name, resourceBundleName) is called.  In this case
800         // we won't necessarily have the correct classloader saved away, so
801         // we need to set it here, too.
802
803         result.setupResourceInfo(resourceBundleName, callerClass);
804         return result;
805     }
806
807     // package-private
808     // Add a platform logger to the system context.
809     // i.e. caller of sun.util.logging.PlatformLogger.getLogger
810     static Logger getPlatformLogger(String name) {
811         LogManager manager = LogManager.getLogManager();
812
813         // all loggers in the system context will default to
814         // the system logger's resource bundle - therefore the caller won't
815         // be needed and can be null.
816         Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME, (Module)null);
817         return result;
818     }
819
820     /**
821      * Create an anonymous Logger.  The newly created Logger is not
822      * registered in the LogManager namespace.  There will be no
823      * access checks on updates to the logger.
824      * <p>
825      * This factory method is primarily intended for use from applets.
826      * Because the resulting Logger is anonymous it can be kept private
827      * by the creating class.  This removes the need for normal security
828      * checks, which in turn allows untrusted applet code to update
829      * the control state of the Logger.  For example an applet can do
830      * a setLevel or an addHandler on an anonymous Logger.
831      * <p>
832      * Even although the new logger is anonymous, it is configured
833      * to have the root logger ("") as its parent.  This means that
834      * by default it inherits its effective level and handlers
835      * from the root logger. Changing its parent via the
836      * {@link #setParent(java.util.logging.Logger) setParent} method
837      * will still require the security permission specified by that method.
838      *
839      * @return a newly created private Logger
840      */

841     public static Logger getAnonymousLogger() {
842         return getAnonymousLogger(null);
843     }
844
845     /**
846      * Create an anonymous Logger.  The newly created Logger is not
847      * registered in the LogManager namespace.  There will be no
848      * access checks on updates to the logger.
849      * <p>
850      * This factory method is primarily intended for use from applets.
851      * Because the resulting Logger is anonymous it can be kept private
852      * by the creating class.  This removes the need for normal security
853      * checks, which in turn allows untrusted applet code to update
854      * the control state of the Logger.  For example an applet can do
855      * a setLevel or an addHandler on an anonymous Logger.
856      * <p>
857      * Even although the new logger is anonymous, it is configured
858      * to have the root logger ("") as its parent.  This means that
859      * by default it inherits its effective level and handlers
860      * from the root logger.  Changing its parent via the
861      * {@link #setParent(java.util.logging.Logger) setParent} method
862      * will still require the security permission specified by that method.
863      *
864      * @param   resourceBundleName  name of ResourceBundle to be used for localizing
865      *                          messages for this logger.
866      *          May be null if none of the messages require localization.
867      * @return a newly created private Logger
868      * @throws MissingResourceException if the resourceBundleName is non-null and
869      *             no corresponding resource can be found.
870      */

871
872     // Synchronization is not required here. All synchronization for
873     // adding a new anonymous Logger object is handled by doSetParent().
874     @CallerSensitive
875     public static Logger getAnonymousLogger(String resourceBundleName) {
876         LogManager manager = LogManager.getLogManager();
877         // cleanup some Loggers that have been GC'ed
878         manager.drainLoggerRefQueueBounded();
879         final Class<?> callerClass = Reflection.getCallerClass();
880         final Module module = callerClass.getModule();
881         Logger result = new Logger(null, resourceBundleName,
882                                    module, manager, false);
883         result.anonymous = true;
884         Logger root = manager.getLogger("");
885         result.doSetParent(root);
886         return result;
887     }
888
889     /**
890      * Retrieve the localization resource bundle for this
891      * logger.
892      * This method will return a {@code ResourceBundle} that was either
893      * set by the {@link
894      * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method or
895      * <a href="#ResourceBundleMapping">mapped from the
896      * the resource bundle name</a> set via the {@link
897      * Logger#getLogger(java.lang.String, java.lang.String) getLogger} factory
898      * method for the current default locale.
899      * <br>Note that if the result is {@code null}, then the Logger will use a resource
900      * bundle or resource bundle name inherited from its parent.
901      *
902      * @return localization bundle (may be {@code null})
903      */

904     public ResourceBundle getResourceBundle() {
905         return findResourceBundle(getResourceBundleName(), true);
906     }
907
908     /**
909      * Retrieve the localization resource bundle name for this
910      * logger.
911      * This is either the name specified through the {@link
912      * #getLogger(java.lang.String, java.lang.String) getLogger} factory method,
913      * or the {@linkplain ResourceBundle#getBaseBundleName() base name} of the
914      * ResourceBundle set through {@link
915      * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method.
916      * <br>Note that if the result is {@code null}, then the Logger will use a resource
917      * bundle or resource bundle name inherited from its parent.
918      *
919      * @return localization bundle name (may be {@code null})
920      */

921     public String getResourceBundleName() {
922         return loggerBundle.resourceBundleName;
923     }
924
925     /**
926      * Set a filter to control output on this Logger.
927      * <P>
928      * After passing the initial "level" check, the Logger will
929      * call this Filter to check if a log record should really
930      * be published.
931      *
932      * @param   newFilter  a filter object (may be null)
933      * @throws  SecurityException if a security manager exists,
934      *          this logger is not anonymous, and the caller
935      *          does not have LoggingPermission("control").
936      */

937     public void setFilter(Filter newFilter) throws SecurityException {
938         checkPermission();
939         config.setFilter(newFilter);
940     }
941
942     /**
943      * Get the current filter for this Logger.
944      *
945      * @return  a filter object (may be null)
946      */

947     public Filter getFilter() {
948         return config.filter;
949     }
950
951     /**
952      * Log a LogRecord.
953      * <p>
954      * All the other logging methods in this class call through
955      * this method to actually perform any logging.  Subclasses can
956      * override this single method to capture all log activity.
957      *
958      * @param record the LogRecord to be published
959      */

960     public void log(LogRecord record) {
961         if (!isLoggable(record.getLevel())) {
962             return;
963         }
964         Filter theFilter = config.filter;
965         if (theFilter != null && !theFilter.isLoggable(record)) {
966             return;
967         }
968
969         // Post the LogRecord to all our Handlers, and then to
970         // our parents' handlers, all the way up the tree.
971
972         Logger logger = this;
973         while (logger != null) {
974             final Handler[] loggerHandlers = isSystemLogger
975                 ? logger.accessCheckedHandlers()
976                 : logger.getHandlers();
977
978             for (Handler handler : loggerHandlers) {
979                 handler.publish(record);
980             }
981
982             final boolean useParentHdls = isSystemLogger
983                 ? logger.config.useParentHandlers
984                 : logger.getUseParentHandlers();
985
986             if (!useParentHdls) {
987                 break;
988             }
989
990             logger = isSystemLogger ? logger.parent : logger.getParent();
991         }
992     }
993
994     // private support method for logging.
995     // We fill in the logger name, resource bundle name, and
996     // resource bundle and then call "void log(LogRecord)".
997     private void doLog(LogRecord lr) {
998         lr.setLoggerName(name);
999         final LoggerBundle lb = getEffectiveLoggerBundle();
1000         final ResourceBundle  bundle = lb.userBundle;
1001         final String ebname = lb.resourceBundleName;
1002         if (ebname != null && bundle != null) {
1003             lr.setResourceBundleName(ebname);
1004             lr.setResourceBundle(bundle);
1005         }
1006         log(lr);
1007     }
1008
1009
1010     //================================================================
1011     // Start of convenience methods WITHOUT className and methodName
1012     //================================================================
1013
1014     /**
1015      * Log a message, with no arguments.
1016      * <p>
1017      * If the logger is currently enabled for the given message
1018      * level then the given message is forwarded to all the
1019      * registered output Handler objects.
1020      *
1021      * @param   level   One of the message level identifiers, e.g., SEVERE
1022      * @param   msg     The string message (or a key in the message catalog)
1023      */

1024     public void log(Level level, String msg) {
1025         if (!isLoggable(level)) {
1026             return;
1027         }
1028         LogRecord lr = new LogRecord(level, msg);
1029         doLog(lr);
1030     }
1031
1032     /**
1033      * Log a message, which is only to be constructed if the logging level
1034      * is such that the message will actually be logged.
1035      * <p>
1036      * If the logger is currently enabled for the given message
1037      * level then the message is constructed by invoking the provided
1038      * supplier function and forwarded to all the registered output
1039      * Handler objects.
1040      *
1041      * @param   level   One of the message level identifiers, e.g., SEVERE
1042      * @param   msgSupplier   A function, which when called, produces the
1043      *                        desired log message
1044      * @since 1.8
1045      */

1046     public void log(Level level, Supplier<String> msgSupplier) {
1047         if (!isLoggable(level)) {
1048             return;
1049         }
1050         LogRecord lr = new LogRecord(level, msgSupplier.get());
1051         doLog(lr);
1052     }
1053
1054     /**
1055      * Log a message, with one object parameter.
1056      * <p>
1057      * If the logger is currently enabled for the given message
1058      * level then a corresponding LogRecord is created and forwarded
1059      * to all the registered output Handler objects.
1060      *
1061      * @param   level   One of the message level identifiers, e.g., SEVERE
1062      * @param   msg     The string message (or a key in the message catalog)
1063      * @param   param1  parameter to the message
1064      */

1065     public void log(Level level, String msg, Object param1) {
1066         if (!isLoggable(level)) {
1067             return;
1068         }
1069         LogRecord lr = new LogRecord(level, msg);
1070         Object params[] = { param1 };
1071         lr.setParameters(params);
1072         doLog(lr);
1073     }
1074
1075     /**
1076      * Log a message, with an array of object arguments.
1077      * <p>
1078      * If the logger is currently enabled for the given message
1079      * level then a corresponding LogRecord is created and forwarded
1080      * to all the registered output Handler objects.
1081      *
1082      * @param   level   One of the message level identifiers, e.g., SEVERE
1083      * @param   msg     The string message (or a key in the message catalog)
1084      * @param   params  array of parameters to the message
1085      */

1086     public void log(Level level, String msg, Object params[]) {
1087         if (!isLoggable(level)) {
1088             return;
1089         }
1090         LogRecord lr = new LogRecord(level, msg);
1091         lr.setParameters(params);
1092         doLog(lr);
1093     }
1094
1095     /**
1096      * Log a message, with associated Throwable information.
1097      * <p>
1098      * If the logger is currently enabled for the given message
1099      * level then the given arguments are stored in a LogRecord
1100      * which is forwarded to all registered output handlers.
1101      * <p>
1102      * Note that the thrown argument is stored in the LogRecord thrown
1103      * property, rather than the LogRecord parameters property.  Thus it is
1104      * processed specially by output Formatters and is not treated
1105      * as a formatting parameter to the LogRecord message property.
1106      *
1107      * @param   level   One of the message level identifiers, e.g., SEVERE
1108      * @param   msg     The string message (or a key in the message catalog)
1109      * @param   thrown  Throwable associated with log message.
1110      */

1111     public void log(Level level, String msg, Throwable thrown) {
1112         if (!isLoggable(level)) {
1113             return;
1114         }
1115         LogRecord lr = new LogRecord(level, msg);
1116         lr.setThrown(thrown);
1117         doLog(lr);
1118     }
1119
1120     /**
1121      * Log a lazily constructed message, with associated Throwable information.
1122      * <p>
1123      * If the logger is currently enabled for the given message level then the
1124      * message is constructed by invoking the provided supplier function. The
1125      * message and the given {@link Throwable} are then stored in a {@link
1126      * LogRecord} which is forwarded to all registered output handlers.
1127      * <p>
1128      * Note that the thrown argument is stored in the LogRecord thrown
1129      * property, rather than the LogRecord parameters property.  Thus it is
1130      * processed specially by output Formatters and is not treated
1131      * as a formatting parameter to the LogRecord message property.
1132      *
1133      * @param   level   One of the message level identifiers, e.g., SEVERE
1134      * @param   thrown  Throwable associated with log message.
1135      * @param   msgSupplier   A function, which when called, produces the
1136      *                        desired log message
1137      * @since   1.8
1138      */

1139     public void log(Level level, Throwable thrown, Supplier<String> msgSupplier) {
1140         if (!isLoggable(level)) {
1141             return;
1142         }
1143         LogRecord lr = new LogRecord(level, msgSupplier.get());
1144         lr.setThrown(thrown);
1145         doLog(lr);
1146     }
1147
1148     //================================================================
1149     // Start of convenience methods WITH className and methodName
1150     //================================================================
1151
1152     /**
1153      * Log a message, specifying source class and method,
1154      * with no arguments.
1155      * <p>
1156      * If the logger is currently enabled for the given message
1157      * level then the given message is forwarded to all the
1158      * registered output Handler objects.
1159      *
1160      * @param   level   One of the message level identifiers, e.g., SEVERE
1161      * @param   sourceClass    name of class that issued the logging request
1162      * @param   sourceMethod   name of method that issued the logging request
1163      * @param   msg     The string message (or a key in the message catalog)
1164      */

1165     public void logp(Level level, String sourceClass, String sourceMethod, String msg) {
1166         if (!isLoggable(level)) {
1167             return;
1168         }
1169         LogRecord lr = new LogRecord(level, msg);
1170         lr.setSourceClassName(sourceClass);
1171         lr.setSourceMethodName(sourceMethod);
1172         doLog(lr);
1173     }
1174
1175     /**
1176      * Log a lazily constructed message, specifying source class and method,
1177      * with no arguments.
1178      * <p>
1179      * If the logger is currently enabled for the given message
1180      * level then the message is constructed by invoking the provided
1181      * supplier function and forwarded to all the registered output
1182      * Handler objects.
1183      *
1184      * @param   level   One of the message level identifiers, e.g., SEVERE
1185      * @param   sourceClass    name of class that issued the logging request
1186      * @param   sourceMethod   name of method that issued the logging request
1187      * @param   msgSupplier   A function, which when called, produces the
1188      *                        desired log message
1189      * @since   1.8
1190      */

1191     public void logp(Level level, String sourceClass, String sourceMethod,
1192                      Supplier<String> msgSupplier) {
1193         if (!isLoggable(level)) {
1194             return;
1195         }
1196         LogRecord lr = new LogRecord(level, msgSupplier.get());
1197         lr.setSourceClassName(sourceClass);
1198         lr.setSourceMethodName(sourceMethod);
1199         doLog(lr);
1200     }
1201
1202     /**
1203      * Log a message, specifying source class and method,
1204      * with a single object parameter to the log message.
1205      * <p>
1206      * If the logger is currently enabled for the given message
1207      * level then a corresponding LogRecord is created and forwarded
1208      * to all the registered output Handler objects.
1209      *
1210      * @param   level   One of the message level identifiers, e.g., SEVERE
1211      * @param   sourceClass    name of class that issued the logging request
1212      * @param   sourceMethod   name of method that issued the logging request
1213      * @param   msg      The string message (or a key in the message catalog)
1214      * @param   param1    Parameter to the log message.
1215      */

1216     public void logp(Level level, String sourceClass, String sourceMethod,
1217                                                 String msg, Object param1) {
1218         if (!isLoggable(level)) {
1219             return;
1220         }
1221         LogRecord lr = new LogRecord(level, msg);
1222         lr.setSourceClassName(sourceClass);
1223         lr.setSourceMethodName(sourceMethod);
1224         Object params[] = { param1 };
1225         lr.setParameters(params);
1226         doLog(lr);
1227     }
1228
1229     /**
1230      * Log a message, specifying source class and method,
1231      * with an array of object arguments.
1232      * <p>
1233      * If the logger is currently enabled for the given message
1234      * level then a corresponding LogRecord is created and forwarded
1235      * to all the registered output Handler objects.
1236      *
1237      * @param   level   One of the message level identifiers, e.g., SEVERE
1238      * @param   sourceClass    name of class that issued the logging request
1239      * @param   sourceMethod   name of method that issued the logging request
1240      * @param   msg     The string message (or a key in the message catalog)
1241      * @param   params  Array of parameters to the message
1242      */

1243     public void logp(Level level, String sourceClass, String sourceMethod,
1244                                                 String msg, Object params[]) {
1245         if (!isLoggable(level)) {
1246             return;
1247         }
1248         LogRecord lr = new LogRecord(level, msg);
1249         lr.setSourceClassName(sourceClass);
1250         lr.setSourceMethodName(sourceMethod);
1251         lr.setParameters(params);
1252         doLog(lr);
1253     }
1254
1255     /**
1256      * Log a message, specifying source class and method,
1257      * with associated Throwable information.
1258      * <p>
1259      * If the logger is currently enabled for the given message
1260      * level then the given arguments are stored in a LogRecord
1261      * which is forwarded to all registered output handlers.
1262      * <p>
1263      * Note that the thrown argument is stored in the LogRecord thrown
1264      * property, rather than the LogRecord parameters property.  Thus it is
1265      * processed specially by output Formatters and is not treated
1266      * as a formatting parameter to the LogRecord message property.
1267      *
1268      * @param   level   One of the message level identifiers, e.g., SEVERE
1269      * @param   sourceClass    name of class that issued the logging request
1270      * @param   sourceMethod   name of method that issued the logging request
1271      * @param   msg     The string message (or a key in the message catalog)
1272      * @param   thrown  Throwable associated with log message.
1273      */

1274     public void logp(Level level, String sourceClass, String sourceMethod,
1275                      String msg, Throwable thrown) {
1276         if (!isLoggable(level)) {
1277             return;
1278         }
1279         LogRecord lr = new LogRecord(level, msg);
1280         lr.setSourceClassName(sourceClass);
1281         lr.setSourceMethodName(sourceMethod);
1282         lr.setThrown(thrown);
1283         doLog(lr);
1284     }
1285
1286     /**
1287      * Log a lazily constructed message, specifying source class and method,
1288      * with associated Throwable information.
1289      * <p>
1290      * If the logger is currently enabled for the given message level then the
1291      * message is constructed by invoking the provided supplier function. The
1292      * message and the given {@link Throwable} are then stored in a {@link
1293      * LogRecord} which is forwarded to all registered output handlers.
1294      * <p>
1295      * Note that the thrown argument is stored in the LogRecord thrown
1296      * property, rather than the LogRecord parameters property.  Thus it is
1297      * processed specially by output Formatters and is not treated
1298      * as a formatting parameter to the LogRecord message property.
1299      *
1300      * @param   level   One of the message level identifiers, e.g., SEVERE
1301      * @param   sourceClass    name of class that issued the logging request
1302      * @param   sourceMethod   name of method that issued the logging request
1303      * @param   thrown  Throwable associated with log message.
1304      * @param   msgSupplier   A function, which when called, produces the
1305      *                        desired log message
1306      * @since   1.8
1307      */

1308     public void logp(Level level, String sourceClass, String sourceMethod,
1309                      Throwable thrown, Supplier<String> msgSupplier) {
1310         if (!isLoggable(level)) {
1311             return;
1312         }
1313         LogRecord lr = new LogRecord(level, msgSupplier.get());
1314         lr.setSourceClassName(sourceClass);
1315         lr.setSourceMethodName(sourceMethod);
1316         lr.setThrown(thrown);
1317         doLog(lr);
1318     }
1319
1320
1321     //=========================================================================
1322     // Start of convenience methods WITH className, methodName and bundle name.
1323     //=========================================================================
1324
1325     // Private support method for logging for "logrb" methods.
1326     // We fill in the logger name, resource bundle name, and
1327     // resource bundle and then call "void log(LogRecord)".
1328     private void doLog(LogRecord lr, String rbname) {
1329         lr.setLoggerName(name);
1330         if (rbname != null) {
1331             lr.setResourceBundleName(rbname);
1332             lr.setResourceBundle(findResourceBundle(rbname, false));
1333         }
1334         log(lr);
1335     }
1336
1337     // Private support method for logging for "logrb" methods.
1338     private void doLog(LogRecord lr, ResourceBundle rb) {
1339         lr.setLoggerName(name);
1340         if (rb != null) {
1341             lr.setResourceBundleName(rb.getBaseBundleName());
1342             lr.setResourceBundle(rb);
1343         }
1344         log(lr);
1345     }
1346
1347     /**
1348      * Log a message, specifying source class, method, and resource bundle name
1349      * with no arguments.
1350      * <p>
1351      * If the logger is currently enabled for the given message
1352      * level then the given message is forwarded to all the
1353      * registered output Handler objects.
1354      * <p>
1355      * The msg string is localized using the named resource bundle.  If the
1356      * resource bundle name is null, or an empty String or invalid
1357      * then the msg string is not localized.
1358      *
1359      * @param   level   One of the message level identifiers, e.g., SEVERE
1360      * @param   sourceClass    name of class that issued the logging request
1361      * @param   sourceMethod   name of method that issued the logging request
1362      * @param   bundleName     name of resource bundle to localize msg,
1363      *                         can be null
1364      * @param   msg     The string message (or a key in the message catalog)
1365      * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
1366      * java.lang.String, java.util.ResourceBundle, java.lang.String,
1367      * java.lang.Object...)} instead.
1368      */

1369     @Deprecated
1370     public void logrb(Level level, String sourceClass, String sourceMethod,
1371                                 String bundleName, String msg) {
1372         if (!isLoggable(level)) {
1373             return;
1374         }
1375         LogRecord lr = new LogRecord(level, msg);
1376         lr.setSourceClassName(sourceClass);
1377         lr.setSourceMethodName(sourceMethod);
1378         doLog(lr, bundleName);
1379     }
1380
1381     /**
1382      * Log a message, specifying source class, method, and resource bundle name,
1383      * with a single object parameter to the log message.
1384      * <p>
1385      * If the logger is currently enabled for the given message
1386      * level then a corresponding LogRecord is created and forwarded
1387      * to all the registered output Handler objects.
1388      * <p>
1389      * The msg string is localized using the named resource bundle.  If the
1390      * resource bundle name is null, or an empty String or invalid
1391      * then the msg string is not localized.
1392      *
1393      * @param   level   One of the message level identifiers, e.g., SEVERE
1394      * @param   sourceClass    name of class that issued the logging request
1395      * @param   sourceMethod   name of method that issued the logging request
1396      * @param   bundleName     name of resource bundle to localize msg,
1397      *                         can be null
1398      * @param   msg      The string message (or a key in the message catalog)
1399      * @param   param1    Parameter to the log message.
1400      * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
1401      *   java.lang.String, java.util.ResourceBundle, java.lang.String,
1402      *   java.lang.Object...)} instead
1403      */

1404     @Deprecated
1405     public void logrb(Level level, String sourceClass, String sourceMethod,
1406                                 String bundleName, String msg, Object param1) {
1407         if (!isLoggable(level)) {
1408             return;
1409         }
1410         LogRecord lr = new LogRecord(level, msg);
1411         lr.setSourceClassName(sourceClass);
1412         lr.setSourceMethodName(sourceMethod);
1413         Object params[] = { param1 };
1414         lr.setParameters(params);
1415         doLog(lr, bundleName);
1416     }
1417
1418     /**
1419      * Log a message, specifying source class, method, and resource bundle name,
1420      * with an array of object arguments.
1421      * <p>
1422      * If the logger is currently enabled for the given message
1423      * level then a corresponding LogRecord is created and forwarded
1424      * to all the registered output Handler objects.
1425      * <p>
1426      * The msg string is localized using the named resource bundle.  If the
1427      * resource bundle name is null, or an empty String or invalid
1428      * then the msg string is not localized.
1429      *
1430      * @param   level   One of the message level identifiers, e.g., SEVERE
1431      * @param   sourceClass    name of class that issued the logging request
1432      * @param   sourceMethod   name of method that issued the logging request
1433      * @param   bundleName     name of resource bundle to localize msg,
1434      *                         can be null.
1435      * @param   msg     The string message (or a key in the message catalog)
1436      * @param   params  Array of parameters to the message
1437      * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
1438      *      java.lang.String, java.util.ResourceBundle, java.lang.String,
1439      *      java.lang.Object...)} instead.
1440      */

1441     @Deprecated
1442     public void logrb(Level level, String sourceClass, String sourceMethod,
1443                                 String bundleName, String msg, Object params[]) {
1444         if (!isLoggable(level)) {
1445             return;
1446         }
1447         LogRecord lr = new LogRecord(level, msg);
1448         lr.setSourceClassName(sourceClass);
1449         lr.setSourceMethodName(sourceMethod);
1450         lr.setParameters(params);
1451         doLog(lr, bundleName);
1452     }
1453
1454     /**
1455      * Log a message, specifying source class, method, and resource bundle,
1456      * with an optional list of message parameters.
1457      * <p>
1458      * If the logger is currently enabled for the given message
1459      * {@code level} then a corresponding {@code LogRecord} is created and
1460      * forwarded to all the registered output {@code Handler} objects.
1461      * <p>
1462      * The {@code msg} string is localized using the given resource bundle.
1463      * If the resource bundle is {@code null}, then the {@code msg} string is not
1464      * localized.
1465      *
1466      * @param   level   One of the message level identifiers, e.g., {@code SEVERE}
1467      * @param   sourceClass    Name of the class that issued the logging request
1468      * @param   sourceMethod   Name of the method that issued the logging request
1469      * @param   bundle         Resource bundle to localize {@code msg},
1470      *                         can be {@code null}.
1471      * @param   msg     The string message (or a key in the message catalog)
1472      * @param   params  Parameters to the message (optional, may be none).
1473      * @since 1.8
1474      */

1475     public void logrb(Level level, String sourceClass, String sourceMethod,
1476                       ResourceBundle bundle, String msg, Object... params) {
1477         if (!isLoggable(level)) {
1478             return;
1479         }
1480         LogRecord lr = new LogRecord(level, msg);
1481         lr.setSourceClassName(sourceClass);
1482         lr.setSourceMethodName(sourceMethod);
1483         if (params != null && params.length != 0) {
1484             lr.setParameters(params);
1485         }
1486         doLog(lr, bundle);
1487     }
1488
1489     /**
1490      * Log a message, specifying source class, method, and resource bundle,
1491      * with an optional list of message parameters.
1492      * <p>
1493      * If the logger is currently enabled for the given message
1494      * {@code level} then a corresponding {@code LogRecord} is created
1495      * and forwarded to all the registered output {@code Handler} objects.
1496      * <p>
1497      * The {@code msg} string is localized using the given resource bundle.
1498      * If the resource bundle is {@code null}, then the {@code msg} string is not
1499      * localized.
1500      *
1501      * @param   level   One of the message level identifiers, e.g., {@code SEVERE}
1502      * @param   bundle  Resource bundle to localize {@code msg};
1503      *                  can be {@code null}.
1504      * @param   msg     The string message (or a key in the message catalog)
1505      * @param   params  Parameters to the message (optional, may be none).
1506      * @since 9
1507      */

1508     public void logrb(Level level, ResourceBundle bundle, String msg, Object... params) {
1509         if (!isLoggable(level)) {
1510             return;
1511         }
1512         LogRecord lr = new LogRecord(level, msg);
1513         if (params != null && params.length != 0) {
1514             lr.setParameters(params);
1515         }
1516         doLog(lr, bundle);
1517     }
1518
1519     /**
1520      * Log a message, specifying source class, method, and resource bundle name,
1521      * with associated Throwable information.
1522      * <p>
1523      * If the logger is currently enabled for the given message
1524      * level then the given arguments are stored in a LogRecord
1525      * which is forwarded to all registered output handlers.
1526      * <p>
1527      * The msg string is localized using the named resource bundle.  If the
1528      * resource bundle name is null, or an empty String or invalid
1529      * then the msg string is not localized.
1530      * <p>
1531      * Note that the thrown argument is stored in the LogRecord thrown
1532      * property, rather than the LogRecord parameters property.  Thus it is
1533      * processed specially by output Formatters and is not treated
1534      * as a formatting parameter to the LogRecord message property.
1535      *
1536      * @param   level   One of the message level identifiers, e.g., SEVERE
1537      * @param   sourceClass    name of class that issued the logging request
1538      * @param   sourceMethod   name of method that issued the logging request
1539      * @param   bundleName     name of resource bundle to localize msg,
1540      *                         can be null
1541      * @param   msg     The string message (or a key in the message catalog)
1542      * @param   thrown  Throwable associated with log message.
1543      * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
1544      *     java.lang.String, java.util.ResourceBundle, java.lang.String,
1545      *     java.lang.Throwable)} instead.
1546      */

1547     @Deprecated
1548     public void logrb(Level level, String sourceClass, String sourceMethod,
1549                                         String bundleName, String msg, Throwable thrown) {
1550         if (!isLoggable(level)) {
1551             return;
1552         }
1553         LogRecord lr = new LogRecord(level, msg);
1554         lr.setSourceClassName(sourceClass);
1555         lr.setSourceMethodName(sourceMethod);
1556         lr.setThrown(thrown);
1557         doLog(lr, bundleName);
1558     }
1559
1560     /**
1561      * Log a message, specifying source class, method, and resource bundle,
1562      * with associated Throwable information.
1563      * <p>
1564      * If the logger is currently enabled for the given message
1565      * {@code level} then the given arguments are stored in a {@code LogRecord}
1566      * which is forwarded to all registered output handlers.
1567      * <p>
1568      * The {@code msg} string is localized using the given resource bundle.
1569      * If the resource bundle is {@code null}, then the {@code msg} string is not
1570      * localized.
1571      * <p>
1572      * Note that the {@code thrown} argument is stored in the {@code LogRecord}
1573      * {@code thrown} property, rather than the {@code LogRecord}
1574      * {@code parameters} property.  Thus it is
1575      * processed specially by output {@code Formatter} objects and is not treated
1576      * as a formatting parameter to the {@code LogRecord} {@code message} property.
1577      *
1578      * @param   level   One of the message level identifiers, e.g., {@code SEVERE}
1579      * @param   sourceClass    Name of the class that issued the logging request
1580      * @param   sourceMethod   Name of the method that issued the logging request
1581      * @param   bundle         Resource bundle to localize {@code msg},
1582      *                         can be {@code null}
1583      * @param   msg     The string message (or a key in the message catalog)
1584      * @param   thrown  Throwable associated with the log message.
1585      * @since 1.8
1586      */

1587     public void logrb(Level level, String sourceClass, String sourceMethod,
1588                       ResourceBundle bundle, String msg, Throwable thrown) {
1589         if (!isLoggable(level)) {
1590             return;
1591         }
1592         LogRecord lr = new LogRecord(level, msg);
1593         lr.setSourceClassName(sourceClass);
1594         lr.setSourceMethodName(sourceMethod);
1595         lr.setThrown(thrown);
1596         doLog(lr, bundle);
1597     }
1598
1599     /**
1600      * Log a message, specifying source class, method, and resource bundle,
1601      * with associated Throwable information.
1602      * <p>
1603      * If the logger is currently enabled for the given message
1604      * {@code level} then the given arguments are stored in a {@code LogRecord}
1605      * which is forwarded to all registered output handlers.
1606      * <p>
1607      * The {@code msg} string is localized using the given resource bundle.
1608      * If the resource bundle is {@code null}, then the {@code msg} string is not
1609      * localized.
1610      * <p>
1611      * Note that the {@code thrown} argument is stored in the {@code LogRecord}
1612      * {@code thrown} property, rather than the {@code LogRecord}
1613      * {@code parameters} property.  Thus it is
1614      * processed specially by output {@code Formatter} objects and is not treated
1615      * as a formatting parameter to the {@code LogRecord} {@code message}
1616      * property.
1617      *
1618      * @param   level   One of the message level identifiers, e.g., {@code SEVERE}
1619      * @param   bundle  Resource bundle to localize {@code msg};
1620      *                  can be {@code null}.
1621      * @param   msg     The string message (or a key in the message catalog)
1622      * @param   thrown  Throwable associated with the log message.
1623      * @since 9
1624      */

1625     public void logrb(Level level, ResourceBundle bundle, String msg,
1626             Throwable thrown) {
1627         if (!isLoggable(level)) {
1628             return;
1629         }
1630         LogRecord lr = new LogRecord(level, msg);
1631         lr.setThrown(thrown);
1632         doLog(lr, bundle);
1633     }
1634
1635     //======================================================================
1636     // Start of convenience methods for logging method entries and returns.
1637     //======================================================================
1638
1639     /**
1640      * Log a method entry.
1641      * <p>
1642      * This is a convenience method that can be used to log entry
1643      * to a method.  A LogRecord with message "ENTRY", log level
1644      * FINER, and the given sourceMethod and sourceClass is logged.
1645      *
1646      * @param   sourceClass    name of class that issued the logging request
1647      * @param   sourceMethod   name of method that is being entered
1648      */

1649     public void entering(String sourceClass, String sourceMethod) {
1650         logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
1651     }
1652
1653     /**
1654      * Log a method entry, with one parameter.
1655      * <p>
1656      * This is a convenience method that can be used to log entry
1657      * to a method.  A LogRecord with message "ENTRY {0}", log level
1658      * FINER, and the given sourceMethod, sourceClass, and parameter
1659      * is logged.
1660      *
1661      * @param   sourceClass    name of class that issued the logging request
1662      * @param   sourceMethod   name of method that is being entered
1663      * @param   param1         parameter to the method being entered
1664      */

1665     public void entering(String sourceClass, String sourceMethod, Object param1) {
1666         logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param1);
1667     }
1668
1669     /**
1670      * Log a method entry, with an array of parameters.
1671      * <p>
1672      * This is a convenience method that can be used to log entry
1673      * to a method.  A LogRecord with message "ENTRY" (followed by a
1674      * format {N} indicator for each entry in the parameter array),
1675      * log level FINER, and the given sourceMethod, sourceClass, and
1676      * parameters is logged.
1677      *
1678      * @param   sourceClass    name of class that issued the logging request
1679      * @param   sourceMethod   name of method that is being entered
1680      * @param   params         array of parameters to the method being entered
1681      */

1682     public void entering(String sourceClass, String sourceMethod, Object params[]) {
1683         String msg = "ENTRY";
1684         if (params == null ) {
1685            logp(Level.FINER, sourceClass, sourceMethod, msg);
1686            return;
1687         }
1688         if (!isLoggable(Level.FINER)) return;
1689         if (params.length > 0) {
1690             final StringBuilder b = new StringBuilder(msg);
1691             for (int i = 0; i < params.length; i++) {
1692                 b.append(' ').append('{').append(i).append('}');
1693             }
1694             msg = b.toString();
1695         }
1696         logp(Level.FINER, sourceClass, sourceMethod, msg, params);
1697     }
1698
1699     /**
1700      * Log a method return.
1701      * <p>
1702      * This is a convenience method that can be used to log returning
1703      * from a method.  A LogRecord with message "RETURN", log level
1704      * FINER, and the given sourceMethod and sourceClass is logged.
1705      *
1706      * @param   sourceClass    name of class that issued the logging request
1707      * @param   sourceMethod   name of the method
1708      */

1709     public void exiting(String sourceClass, String sourceMethod) {
1710         logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
1711     }
1712
1713
1714     /**
1715      * Log a method return, with result object.
1716      * <p>
1717      * This is a convenience method that can be used to log returning
1718      * from a method.  A LogRecord with message "RETURN {0}", log level
1719      * FINER, and the gives sourceMethod, sourceClass, and result
1720      * object is logged.
1721      *
1722      * @param   sourceClass    name of class that issued the logging request
1723      * @param   sourceMethod   name of the method
1724      * @param   result  Object that is being returned
1725      */

1726     public void exiting(String sourceClass, String sourceMethod, Object result) {
1727         logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
1728     }
1729
1730     /**
1731      * Log throwing an exception.
1732      * <p>
1733      * This is a convenience method to log that a method is
1734      * terminating by throwing an exception.  The logging is done
1735      * using the FINER level.
1736      * <p>
1737      * If the logger is currently enabled for the given message
1738      * level then the given arguments are stored in a LogRecord
1739      * which is forwarded to all registered output handlers.  The
1740      * LogRecord's message is set to "THROW".
1741      * <p>
1742      * Note that the thrown argument is stored in the LogRecord thrown
1743      * property, rather than the LogRecord parameters property.  Thus it is
1744      * processed specially by output Formatters and is not treated
1745      * as a formatting parameter to the LogRecord message property.
1746      *
1747      * @param   sourceClass    name of class that issued the logging request
1748      * @param   sourceMethod  name of the method.
1749      * @param   thrown  The Throwable that is being thrown.
1750      */

1751     public void throwing(String sourceClass, String sourceMethod, Throwable thrown) {
1752         if (!isLoggable(Level.FINER)) {
1753             return;
1754         }
1755         LogRecord lr = new LogRecord(Level.FINER, "THROW");
1756         lr.setSourceClassName(sourceClass);
1757         lr.setSourceMethodName(sourceMethod);
1758         lr.setThrown(thrown);
1759         doLog(lr);
1760     }
1761
1762     //=======================================================================
1763     // Start of simple convenience methods using level names as method names
1764     //=======================================================================
1765
1766     /**
1767      * Log a SEVERE message.
1768      * <p>
1769      * If the logger is currently enabled for the SEVERE message
1770      * level then the given message is forwarded to all the
1771      * registered output Handler objects.
1772      *
1773      * @param   msg     The string message (or a key in the message catalog)
1774      */

1775     public void severe(String msg) {
1776         log(Level.SEVERE, msg);
1777     }
1778
1779     /**
1780      * Log a WARNING message.
1781      * <p>
1782      * If the logger is currently enabled for the WARNING message
1783      * level then the given message is forwarded to all the
1784      * registered output Handler objects.
1785      *
1786      * @param   msg     The string message (or a key in the message catalog)
1787      */

1788     public void warning(String msg) {
1789         log(Level.WARNING, msg);
1790     }
1791
1792     /**
1793      * Log an INFO message.
1794      * <p>
1795      * If the logger is currently enabled for the INFO message
1796      * level then the given message is forwarded to all the
1797      * registered output Handler objects.
1798      *
1799      * @param   msg     The string message (or a key in the message catalog)
1800      */

1801     public void info(String msg) {
1802         log(Level.INFO, msg);
1803     }
1804
1805     /**
1806      * Log a CONFIG message.
1807      * <p>
1808      * If the logger is currently enabled for the CONFIG message
1809      * level then the given message is forwarded to all the
1810      * registered output Handler objects.
1811      *
1812      * @param   msg     The string message (or a key in the message catalog)
1813      */

1814     public void config(String msg) {
1815         log(Level.CONFIG, msg);
1816     }
1817
1818     /**
1819      * Log a FINE message.
1820      * <p>
1821      * If the logger is currently enabled for the FINE message
1822      * level then the given message is forwarded to all the
1823      * registered output Handler objects.
1824      *
1825      * @param   msg     The string message (or a key in the message catalog)
1826      */

1827     public void fine(String msg) {
1828         log(Level.FINE, msg);
1829     }
1830
1831     /**
1832      * Log a FINER message.
1833      * <p>
1834      * If the logger is currently enabled for the FINER message
1835      * level then the given message is forwarded to all the
1836      * registered output Handler objects.
1837      *
1838      * @param   msg     The string message (or a key in the message catalog)
1839      */

1840     public void finer(String msg) {
1841         log(Level.FINER, msg);
1842     }
1843
1844     /**
1845      * Log a FINEST message.
1846      * <p>
1847      * If the logger is currently enabled for the FINEST message
1848      * level then the given message is forwarded to all the
1849      * registered output Handler objects.
1850      *
1851      * @param   msg     The string message (or a key in the message catalog)
1852      */

1853     public void finest(String msg) {
1854         log(Level.FINEST, msg);
1855     }
1856
1857     //=======================================================================
1858     // Start of simple convenience methods using level names as method names
1859     // and use Supplier<String>
1860     //=======================================================================
1861
1862     /**
1863      * Log a SEVERE message, which is only to be constructed if the logging
1864      * level is such that the message will actually be logged.
1865      * <p>
1866      * If the logger is currently enabled for the SEVERE message
1867      * level then the message is constructed by invoking the provided
1868      * supplier function and forwarded to all the registered output
1869      * Handler objects.
1870      *
1871      * @param   msgSupplier   A function, which when called, produces the
1872      *                        desired log message
1873      * @since   1.8
1874      */

1875     public void severe(Supplier<String> msgSupplier) {
1876         log(Level.SEVERE, msgSupplier);
1877     }
1878
1879     /**
1880      * Log a WARNING message, which is only to be constructed if the logging
1881      * level is such that the message will actually be logged.
1882      * <p>
1883      * If the logger is currently enabled for the WARNING message
1884      * level then the message is constructed by invoking the provided
1885      * supplier function and forwarded to all the registered output
1886      * Handler objects.
1887      *
1888      * @param   msgSupplier   A function, which when called, produces the
1889      *                        desired log message
1890      * @since   1.8
1891      */

1892     public void warning(Supplier<String> msgSupplier) {
1893         log(Level.WARNING, msgSupplier);
1894     }
1895
1896     /**
1897      * Log a INFO message, which is only to be constructed if the logging
1898      * level is such that the message will actually be logged.
1899      * <p>
1900      * If the logger is currently enabled for the INFO message
1901      * level then the message is constructed by invoking the provided
1902      * supplier function and forwarded to all the registered output
1903      * Handler objects.
1904      *
1905      * @param   msgSupplier   A function, which when called, produces the
1906      *                        desired log message
1907      * @since   1.8
1908      */

1909     public void info(Supplier<String> msgSupplier) {
1910         log(Level.INFO, msgSupplier);
1911     }
1912
1913     /**
1914      * Log a CONFIG message, which is only to be constructed if the logging
1915      * level is such that the message will actually be logged.
1916      * <p>
1917      * If the logger is currently enabled for the CONFIG message
1918      * level then the message is constructed by invoking the provided
1919      * supplier function and forwarded to all the registered output
1920      * Handler objects.
1921      *
1922      * @param   msgSupplier   A function, which when called, produces the
1923      *                        desired log message
1924      * @since   1.8
1925      */

1926     public void config(Supplier<String> msgSupplier) {
1927         log(Level.CONFIG, msgSupplier);
1928     }
1929
1930     /**
1931      * Log a FINE message, which is only to be constructed if the logging
1932      * level is such that the message will actually be logged.
1933      * <p>
1934      * If the logger is currently enabled for the FINE message
1935      * level then the message is constructed by invoking the provided
1936      * supplier function and forwarded to all the registered output
1937      * Handler objects.
1938      *
1939      * @param   msgSupplier   A function, which when called, produces the
1940      *                        desired log message
1941      * @since   1.8
1942      */

1943     public void fine(Supplier<String> msgSupplier) {
1944         log(Level.FINE, msgSupplier);
1945     }
1946
1947     /**
1948      * Log a FINER message, which is only to be constructed if the logging
1949      * level is such that the message will actually be logged.
1950      * <p>
1951      * If the logger is currently enabled for the FINER message
1952      * level then the message is constructed by invoking the provided
1953      * supplier function and forwarded to all the registered output
1954      * Handler objects.
1955      *
1956      * @param   msgSupplier   A function, which when called, produces the
1957      *                        desired log message
1958      * @since   1.8
1959      */

1960     public void finer(Supplier<String> msgSupplier) {
1961         log(Level.FINER, msgSupplier);
1962     }
1963
1964     /**
1965      * Log a FINEST message, which is only to be constructed if the logging
1966      * level is such that the message will actually be logged.
1967      * <p>
1968      * If the logger is currently enabled for the FINEST message
1969      * level then the message is constructed by invoking the provided
1970      * supplier function and forwarded to all the registered output
1971      * Handler objects.
1972      *
1973      * @param   msgSupplier   A function, which when called, produces the
1974      *                        desired log message
1975      * @since   1.8
1976      */

1977     public void finest(Supplier<String> msgSupplier) {
1978         log(Level.FINEST, msgSupplier);
1979     }
1980
1981     //================================================================
1982     // End of convenience methods
1983     //================================================================
1984
1985     /**
1986      * Set the log level specifying which message levels will be
1987      * logged by this logger.  Message levels lower than this
1988      * value will be discarded.  The level value Level.OFF
1989      * can be used to turn off logging.
1990      * <p>
1991      * If the new level is null, it means that this node should
1992      * inherit its level from its nearest ancestor with a specific
1993      * (non-null) level value.
1994      *
1995      * @param newLevel   the new value for the log level (may be null)
1996      * @throws  SecurityException if a security manager exists,
1997      *          this logger is not anonymous, and the caller
1998      *          does not have LoggingPermission("control").
1999      */

2000     public void setLevel(Level newLevel) throws SecurityException {
2001         checkPermission();
2002         synchronized (treeLock) {
2003             config.setLevelObject(newLevel);
2004             updateEffectiveLevel();
2005         }
2006     }
2007
2008     final boolean isLevelInitialized() {
2009         return config.levelObject != null;
2010     }
2011
2012     /**
2013      * Get the log Level that has been specified for this Logger.
2014      * The result may be null, which means that this logger's
2015      * effective level will be inherited from its parent.
2016      *
2017      * @return  this Logger's level
2018      */

2019     public Level getLevel() {
2020         return config.levelObject;
2021     }
2022
2023     /**
2024      * Check if a message of the given level would actually be logged
2025      * by this logger.  This check is based on the Loggers effective level,
2026      * which may be inherited from its parent.
2027      *
2028      * @param   level   a message logging level
2029      * @return  true if the given message level is currently being logged.
2030      */

2031     public boolean isLoggable(Level level) {
2032         int levelValue = config.levelValue;
2033         if (level.intValue() < levelValue || levelValue == offValue) {
2034             return false;
2035         }
2036         return true;
2037     }
2038
2039     /**
2040      * Get the name for this logger.
2041      * @return logger name.  Will be null for anonymous Loggers.
2042      */

2043     public String getName() {
2044         return name;
2045     }
2046
2047     /**
2048      * Add a log Handler to receive logging messages.
2049      * <p>
2050      * By default, Loggers also send their output to their parent logger.
2051      * Typically the root Logger is configured with a set of Handlers
2052      * that essentially act as default handlers for all loggers.
2053      *
2054      * @param   handler a logging Handler
2055      * @throws  SecurityException if a security manager exists,
2056      *          this logger is not anonymous, and the caller
2057      *          does not have LoggingPermission("control").
2058      */

2059     public void addHandler(Handler handler) throws SecurityException {
2060         Objects.requireNonNull(handler);
2061         checkPermission();
2062         config.addHandler(handler);
2063     }
2064
2065     /**
2066      * Remove a log Handler.
2067      * <P>
2068      * Returns silently if the given Handler is not found or is null
2069      *
2070      * @param   handler a logging Handler
2071      * @throws  SecurityException if a security manager exists,
2072      *          this logger is not anonymous, and the caller
2073      *          does not have LoggingPermission("control").
2074      */

2075     public void removeHandler(Handler handler) throws SecurityException {
2076         checkPermission();
2077         if (handler == null) {
2078             return;
2079         }
2080         config.removeHandler(handler);
2081     }
2082
2083     /**
2084      * Get the Handlers associated with this logger.
2085      *
2086      * @return  an array of all registered Handlers
2087      */

2088     public Handler[] getHandlers() {
2089         return accessCheckedHandlers();
2090     }
2091
2092     // This method should ideally be marked final - but unfortunately
2093     // it needs to be overridden by LogManager.RootLogger
2094     Handler[] accessCheckedHandlers() {
2095         return config.handlers.toArray(emptyHandlers);
2096     }
2097
2098     /**
2099      * Specify whether or not this logger should send its output
2100      * to its parent Logger.  This means that any LogRecords will
2101      * also be written to the parent's Handlers, and potentially
2102      * to its parent, recursively up the namespace.
2103      *
2104      * @param useParentHandlers   true if output is to be sent to the
2105      *          logger's parent.
2106      * @throws  SecurityException if a security manager exists,
2107      *          this logger is not anonymous, and the caller
2108      *          does not have LoggingPermission("control").
2109      */

2110     public void setUseParentHandlers(boolean useParentHandlers) {
2111         checkPermission();
2112         config.setUseParentHandlers(useParentHandlers);
2113     }
2114
2115     /**
2116      * Discover whether or not this logger is sending its output
2117      * to its parent logger.
2118      *
2119      * @return  true if output is to be sent to the logger's parent
2120      */

2121     public boolean getUseParentHandlers() {
2122         return config.useParentHandlers;
2123     }
2124
2125     /**
2126      * Private utility method to map a resource bundle name to an
2127      * actual resource bundle, using a simple one-entry cache.
2128      * Returns null for a null name.
2129      * May also return null if we can't find the resource bundle and
2130      * there is no suitable previous cached value.
2131      *
2132      * @param name the ResourceBundle to locate
2133      * @param useCallersModule if true search using the caller's module.
2134      * @return ResourceBundle specified by name or null if not found
2135      */

2136     private synchronized ResourceBundle findResourceBundle(String name,
2137                                                            boolean useCallersModule) {
2138         // When this method is called from logrb, useCallersModule==false, and
2139         // the resource bundle 'name' is the argument provided to logrb.
2140         // It may, or may not be, equal to lb.resourceBundleName.
2141         // Otherwise, useCallersModule==true, and name is the resource bundle
2142         // name that is set (or will be set) in this logger.
2143         //
2144         // When useCallersModule is false, or when the caller's module is
2145         // null, or when the caller's module is an unnamed module, we look
2146         // first in the TCCL (or the System ClassLoader if the TCCL is null)
2147         // to locate the resource bundle.
2148         //
2149         // Otherwise, if useCallersModule is true, and the caller's module is not
2150         // null, and the caller's module is named, we look in the caller's module
2151         // to locate the resource bundle.
2152         //
2153         // Finally, if the caller's module is not null and is unnamed, and
2154         // useCallersModule is true, we look in the caller's module class loader
2155         // (unless we already looked there in step 1).
2156
2157         // Return a null bundle for a null name.
2158         if (name == null) {
2159             return null;
2160         }
2161
2162         Locale currentLocale = Locale.getDefault();
2163         final LoggerBundle lb = loggerBundle;
2164
2165         // Normally we should hit on our simple one entry cache.
2166         if (lb.userBundle != null &&
2167                 name.equals(lb.resourceBundleName)) {
2168             return lb.userBundle;
2169         } else if (catalog != null && currentLocale.equals(catalogLocale)
2170                 && name.equals(catalogName)) {
2171             return catalog;
2172         }
2173
2174         // Use the thread's context ClassLoader.  If there isn't one, use the
2175         // {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader}.
2176         ClassLoader cl = Thread.currentThread().getContextClassLoader();
2177         if (cl == null) {
2178             cl = ClassLoader.getSystemClassLoader();
2179         }
2180
2181         final Module callerModule = getCallerModule();
2182
2183         // If useCallersModule is false, we are called by logrb, with a name
2184         // that is provided by the user. In that case we will look in the TCCL.
2185         // We also look in the TCCL if callerModule is null or unnamed.
2186         if (!useCallersModule || callerModule == null || !callerModule.isNamed()) {
2187             try {
2188                 Module mod = cl.getUnnamedModule();
2189                 catalog = RbAccess.RB_ACCESS.getBundle(name, currentLocale, mod);
2190                 catalogName = name;
2191                 catalogLocale = currentLocale;
2192                 return catalog;
2193             } catch (MissingResourceException ex) {
2194                 // We can't find the ResourceBundle in the default
2195                 // ClassLoader.  Drop through.
2196                 if (useCallersModule && callerModule != null) {
2197                     try {
2198                         // We are called by an unnamed module: try with the
2199                         // unnamed module class loader:
2200                         PrivilegedAction<ClassLoader> getModuleClassLoader =
2201                                 () -> callerModule.getClassLoader();
2202                         ClassLoader moduleCL =
2203                                 AccessController.doPrivileged(getModuleClassLoader);
2204                         // moduleCL can be null if the logger is created by a class
2205                         // appended to the bootclasspath.
2206                         // If moduleCL is null we would use cl, but we already tried
2207                         // that above (we first looked in the TCCL for unnamed
2208                         // caller modules) - so there no point in trying again: we
2209                         // won't find anything more this second time.
2210                         // In this case just return null.
2211                         if (moduleCL == cl || moduleCL == nullreturn null;
2212
2213                         // we already tried the TCCL and found nothing - so try
2214                         // with the module's loader this time.
2215                         catalog = ResourceBundle.getBundle(name, currentLocale,
2216                                                            moduleCL);
2217                         catalogName = name;
2218                         catalogLocale = currentLocale;
2219                         return catalog;
2220                     } catch (MissingResourceException x) {
2221                         return null// no luck
2222                     }
2223                 } else {
2224                     return null;
2225                 }
2226             }
2227         } else {
2228             // we should have:
2229             //  useCallersModule && callerModule != null && callerModule.isNamed();
2230             // Try with the caller's module
2231             try {
2232                 // Use the caller's module
2233                 catalog = RbAccess.RB_ACCESS.getBundle(name, currentLocale, callerModule);
2234                 catalogName = name;
2235                 catalogLocale = currentLocale;
2236                 return catalog;
2237             } catch (MissingResourceException ex) {
2238                 return null// no luck
2239             }
2240         }
2241     }
2242
2243     private void setupResourceInfo(String name, Class<?> caller) {
2244         final Module module = caller == null ? null : caller.getModule();
2245         setupResourceInfo(name, module);
2246     }
2247
2248     // Private utility method to initialize our one entry
2249     // resource bundle name cache and the callers Module
2250     // Note: for consistency reasons, we are careful to check
2251     // that a suitable ResourceBundle exists before setting the
2252     // resourceBundleName field.
2253     // Synchronized to prevent races in setting the fields.
2254     private synchronized void setupResourceInfo(String name,
2255                                                 Module callerModule) {
2256         final LoggerBundle lb = loggerBundle;
2257         if (lb.resourceBundleName != null) {
2258             // this Logger already has a ResourceBundle
2259
2260             if (lb.resourceBundleName.equals(name)) {
2261                 // the names match so there is nothing more to do
2262                 return;
2263             }
2264
2265             // cannot change ResourceBundles once they are set
2266             throw new IllegalArgumentException(
2267                 lb.resourceBundleName + " != " + name);
2268         }
2269
2270         if (name == null) {
2271             return;
2272         }
2273
2274         setCallerModuleRef(callerModule);
2275
2276         if (isSystemLogger && (callerModule != null && !isSystem(callerModule))) {
2277             checkPermission();
2278         }
2279
2280         if (name.equals(SYSTEM_LOGGER_RB_NAME)) {
2281             loggerBundle = SYSTEM_BUNDLE;
2282         } else {
2283             ResourceBundle bundle = findResourceBundle(name, true);
2284             if (bundle == null) {
2285                 // We've failed to find an expected ResourceBundle.
2286                 // unset the caller's module since we were unable to find the
2287                 // the bundle using it
2288                 this.callerModuleRef = null;
2289                 throw new MissingResourceException("Can't find " + name + " bundle from ",
2290                         name, "");
2291             }
2292
2293             loggerBundle = LoggerBundle.get(name, null);
2294         }
2295     }
2296
2297     /**
2298      * Sets a resource bundle on this logger.
2299      * All messages will be logged using the given resource bundle for its
2300      * specific {@linkplain ResourceBundle#getLocale locale}.
2301      * @param bundle The resource bundle that this logger shall use.
2302      * @throws NullPointerException if the given bundle is {@code null}.
2303      * @throws IllegalArgumentException if the given bundle doesn't have a
2304      *         {@linkplain ResourceBundle#getBaseBundleName base name},
2305      *         or if this logger already has a resource bundle set but
2306      *         the given bundle has a different base name.
2307      * @throws SecurityException if a security manager exists,
2308      *         this logger is not anonymous, and the caller
2309      *         does not have LoggingPermission("control").
2310      * @since 1.8
2311      */

2312     public void setResourceBundle(ResourceBundle bundle) {
2313         checkPermission();
2314
2315         // Will throw NPE if bundle is null.
2316         final String baseName = bundle.getBaseBundleName();
2317
2318         // bundle must have a name
2319         if (baseName == null || baseName.isEmpty()) {
2320             throw new IllegalArgumentException("resource bundle must have a name");
2321         }
2322
2323         synchronized (this) {
2324             LoggerBundle lb = loggerBundle;
2325             final boolean canReplaceResourceBundle = lb.resourceBundleName == null
2326                     || lb.resourceBundleName.equals(baseName);
2327
2328             if (!canReplaceResourceBundle) {
2329                 throw new IllegalArgumentException("can't replace resource bundle");
2330             }
2331
2332
2333             loggerBundle = LoggerBundle.get(baseName, bundle);
2334         }
2335     }
2336
2337     /**
2338      * Return the parent for this Logger.
2339      * <p>
2340      * This method returns the nearest extant parent in the namespace.
2341      * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b"
2342      * has been created but no logger "a.b.c" exists, then a call of
2343      * getParent on the Logger "a.b.c.d" will return the Logger "a.b".
2344      * <p>
2345      * The result will be null if it is called on the root Logger
2346      * in the namespace.
2347      *
2348      * @return nearest existing parent Logger
2349      */

2350     public Logger getParent() {
2351         // Note: this used to be synchronized on treeLock.  However, this only
2352         // provided memory semantics, as there was no guarantee that the caller
2353         // would synchronize on treeLock (in fact, there is no way for external
2354         // callers to so synchronize).  Therefore, we have made parent volatile
2355         // instead.
2356         return parent;
2357     }
2358
2359     /**
2360      * Set the parent for this Logger.  This method is used by
2361      * the LogManager to update a Logger when the namespace changes.
2362      * <p>
2363      * It should not be called from application code.
2364      *
2365      * @param  parent   the new parent logger
2366      * @throws  SecurityException  if a security manager exists and if
2367      *          the caller does not have LoggingPermission("control").
2368      */

2369     public void setParent(Logger parent) {
2370         if (parent == null) {
2371             throw new NullPointerException();
2372         }
2373
2374         // check permission for all loggers, including anonymous loggers
2375         if (manager == null) {
2376             manager = LogManager.getLogManager();
2377         }
2378         manager.checkPermission();
2379
2380         doSetParent(parent);
2381     }
2382
2383     // Private method to do the work for parenting a child
2384     // Logger onto a parent logger.
2385     private void doSetParent(Logger newParent) {
2386
2387         // System.err.println("doSetParent \"" + getName() + "\" \""
2388         //                              + newParent.getName() + "\"");
2389
2390         synchronized (treeLock) {
2391
2392             // Remove ourself from any previous parent.
2393             LogManager.LoggerWeakRef ref = null;
2394             if (parent != null) {
2395                 // assert parent.kids != null;
2396                 for (Iterator<LogManager.LoggerWeakRef> iter = parent.kids.iterator(); iter.hasNext(); ) {
2397                     ref = iter.next();
2398                     Logger kid =  ref.get();
2399                     if (kid == this) {
2400                         // ref is used down below to complete the reparenting
2401                         iter.remove();
2402                         break;
2403                     } else {
2404                         ref = null;
2405                     }
2406                 }
2407                 // We have now removed ourself from our parents' kids.
2408             }
2409
2410             // Set our new parent.
2411             parent = newParent;
2412             if (parent.kids == null) {
2413                 parent.kids = new ArrayList<>(2);
2414             }
2415             if (ref == null) {
2416                 // we didn't have a previous parent
2417                 ref = manager.new LoggerWeakRef(this);
2418             }
2419             ref.setParentRef(new WeakReference<>(parent));
2420             parent.kids.add(ref);
2421
2422             // As a result of the reparenting, the effective level
2423             // may have changed for us and our children.
2424             updateEffectiveLevel();
2425
2426         }
2427     }
2428
2429     // Package-level method.
2430     // Remove the weak reference for the specified child Logger from the
2431     // kid list. We should only be called from LoggerWeakRef.dispose().
2432     final void removeChildLogger(LogManager.LoggerWeakRef child) {
2433         synchronized (treeLock) {
2434             for (Iterator<LogManager.LoggerWeakRef> iter = kids.iterator(); iter.hasNext(); ) {
2435                 LogManager.LoggerWeakRef ref = iter.next();
2436                 if (ref == child) {
2437                     iter.remove();
2438                     return;
2439                 }
2440             }
2441         }
2442     }
2443
2444     // Recalculate the effective level for this node and
2445     // recursively for our children.
2446
2447     private void updateEffectiveLevel() {
2448         // assert Thread.holdsLock(treeLock);
2449
2450         // Figure out our current effective level.
2451         int newLevelValue;
2452         final ConfigurationData cfg = config;
2453         final Level levelObject = cfg.levelObject;
2454         if (levelObject != null) {
2455             newLevelValue = levelObject.intValue();
2456         } else {
2457             if (parent != null) {
2458                 newLevelValue = parent.config.levelValue;
2459             } else {
2460                 // This may happen during initialization.
2461                 newLevelValue = Level.INFO.intValue();
2462             }
2463         }
2464
2465         // If our effective value hasn't changed, we're done.
2466         if (cfg.levelValue == newLevelValue) {
2467             return;
2468         }
2469
2470         cfg.setLevelValue(newLevelValue);
2471
2472         // System.err.println("effective level: \"" + getName() + "\" := " + level);
2473
2474         // Recursively update the level on each of our kids.
2475         if (kids != null) {
2476             for (LogManager.LoggerWeakRef ref : kids) {
2477                 Logger kid = ref.get();
2478                 if (kid != null) {
2479                     kid.updateEffectiveLevel();
2480                 }
2481             }
2482         }
2483     }
2484
2485
2486     // Private method to get the potentially inherited
2487     // resource bundle and resource bundle name for this Logger.
2488     // This method never returns null.
2489     private LoggerBundle getEffectiveLoggerBundle() {
2490         final LoggerBundle lb = loggerBundle;
2491         if (lb.isSystemBundle()) {
2492             return SYSTEM_BUNDLE;
2493         }
2494
2495         // first take care of this logger
2496         final ResourceBundle b = getResourceBundle();
2497         if (b != null && b == lb.userBundle) {
2498             return lb;
2499         } else if (b != null) {
2500             // either lb.userBundle is null or getResourceBundle() is
2501             // overriden
2502             final String rbName = getResourceBundleName();
2503             return LoggerBundle.get(rbName, b);
2504         }
2505
2506         // no resource bundle was specified on this logger, look up the
2507         // parent stack.
2508         Logger target = this.parent;
2509         while (target != null) {
2510             final LoggerBundle trb = target.loggerBundle;
2511             if (trb.isSystemBundle()) {
2512                 return SYSTEM_BUNDLE;
2513             }
2514             if (trb.userBundle != null) {
2515                 return trb;
2516             }
2517             final String rbName = isSystemLogger
2518                 // ancestor of a system logger is expected to be a system logger.
2519                 // ignore resource bundle name if it's not.
2520                 ? (target.isSystemLogger ? trb.resourceBundleName : null)
2521                 : target.getResourceBundleName();
2522             if (rbName != null) {
2523                 return LoggerBundle.get(rbName,
2524                         findResourceBundle(rbName, true));
2525             }
2526             target = isSystemLogger ? target.parent : target.getParent();
2527         }
2528         return NO_RESOURCE_BUNDLE;
2529     }
2530
2531 }
2532