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