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


package java.util.logging;

import java.lang.ref.WeakReference;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Supplier;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;

/**
 
* A Logger object is used to log messages for a specific
 
* system or application component.
  
Loggers are normally named,
 
* using a hierarchical dot-separated namespace.
  
Logger names
 
* can be arbitrary strings, but they should normally be based on
 
* the package name or class name of the logged component, such
 
* as java.net or javax.swing.
  
In addition it is possible to create
 
* "anonymous" Loggers that are not stored in the Logger namespace.
 
* <p>
 
* Logger objects may be obtained by calls on one of the getLogger
 
* factory methods.
  
These will either create a new Logger or
 
* return a suitable existing Logger. It is important to note that
 
* the Logger returned by one of the {@code getLogger} factory methods
 
* may be garbage collected at any time if a strong reference to the
 
* Logger is not kept.
 
* <p>
 
* Logging messages will be forwarded to registered Handler
 
* objects, which can forward the messages to a variety of
 
* destinations, including consoles, files, OS logs, etc.
 
* <p>
 
* Each Logger keeps track of a "parent" Logger, which is its
 
* nearest existing ancestor in the Logger namespace.
 
* <p>
 
* Each Logger has a "Level" associated with it.
  
This reflects
 
* a minimum Level that this logger cares about.
  
If a Logger's
 
* level is set to <tt>null</tt>, then its effective level is inherited
 
* from its parent, which may in turn obtain it recursively from its
 
* parent, and so on up the tree.
 
* <p>
 
* The log level can be configured based on the properties from the
 
* logging configuration file, as described in the description
 
* of the LogManager class.
  
However it may also be dynamically changed
 
* by calls on the Logger.setLevel method.
  
If a logger's level is
 
* changed the change may also affect child loggers, since any child
 
* logger that has <tt>null</tt> as its level will inherit its
 
* effective level from its parent.
 
* <p>
 
* On each logging call the Logger initially performs a cheap
 
* check of the request level (e.g., SEVERE or FINE) against the
 
* effective log level of the logger.
  
If the request level is
 
* lower than the log level, the logging call returns immediately.
 
* <p>
 
* After passing this initial (cheap) test, the Logger will allocate
 
* a LogRecord to describe the logging message.
  
It will then call a
 
* Filter (if present) to do a more detailed check on whether the
 
* record should be published.
  
If that passes it will then publish
 
* the LogRecord to its output Handlers.
  
By default, loggers also
 
* publish to their parent's Handlers, recursively up the tree.
 
* <p>
 
* Each Logger may have a {@code ResourceBundle} associated with it.
 
* The {@code ResourceBundle} may be specified by name, using the
 
* {@link #getLogger(java.lang.String, java.lang.String)} factory
 
* method, or by value - using the {@link
 
* #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method.
 
* This bundle will be used for localizing logging messages.
 
* If a Logger does not have its own {@code ResourceBundle} or resource bundle
 
* name, then it will inherit the {@code ResourceBundle} or resource bundle name
 
* from its parent, recursively up the tree.
 
* <p>
 
* Most of the logger output methods take a "msg" argument.
  
This
 
* msg argument may be either a raw value or a localization key.
 
* During formatting, if the logger has (or inherits) a localization
 
* {@code ResourceBundle} and if the {@code ResourceBundle} has a mapping for
 
* the msg string, then the msg string is replaced by the localized value.
 
* Otherwise the original msg string is used.
  
Typically, formatters use
 
* java.text.MessageFormat style formatting to format parameters, so
 
* for example a format string "{0} {1}" would format two parameters
 
* as strings.
 
* <p>
 
* A set of methods alternatively take a "msgSupplier" instead of a "msg"
 
* argument.
  
These methods take a {@link Supplier}{@code <String>} function
 
* which is invoked to construct the desired log message only when the message
 
* actually is to be logged based on the effective log level thus eliminating
 
* unnecessary message construction. For example, if the developer wants to
 
* log system health status for diagnosis, with the String-accepting version,
 
* the code would look like:
 
<pre><code>

   
class DiagnosisMessages {
     
static String systemHealthStatus() {
       
// collect system health information
       
...
     
}
   
}
   
...
   
logger.log(Level.FINER, DiagnosisMessages.systemHealthStatus());
</code></pre>
 
* With the above code, the health status is collected unnecessarily even when
 
* the log level FINER is disabled. With the Supplier-accepting version as
 
* below, the status will only be collected when the log level FINER is
 
* enabled.
 
<pre><code>

   
logger.log(Level.FINER, DiagnosisMessages::systemHealthStatus);
</code></pre>
 
* <p>
 
* When looking for a {@code ResourceBundle}, the logger will first look at
 
* whether a bundle was specified using {@link
 
* #setResourceBundle(java.util.ResourceBundle) setResourceBundle}, and then
 
* only whether a resource bundle name was specified through the {@link
 
* #getLogger(java.lang.String, java.lang.String) getLogger} factory method.
 
* If no {@code ResourceBundle} or no resource bundle name is found,
 
* then it will use the nearest {@code ResourceBundle} or resource bundle
 
* name inherited from its parent tree.<br>
 
* When a {@code ResourceBundle} was inherited or specified through the
 
* {@link
 
* #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method, then
 
* that {@code ResourceBundle} will be used. Otherwise if the logger only
 
* has or inherited a resource bundle name, then that resource bundle name
 
* will be mapped to a {@code ResourceBundle} object, using the default Locale
 
* at the time of logging.
 
* <br id="ResourceBundleMapping">When mapping resource bundle names to
 
* {@code ResourceBundle} objects, the logger will first try to use the
 
* Thread's {@linkplain java.lang.Thread#getContextClassLoader() context class
 
* loader} to map the given resource bundle name to a {@code ResourceBundle}.
 
* If the thread context class loader is {@code null}, it will try the
 
* {@linkplain java.lang.ClassLoader#getSystemClassLoader() system class loader}
 
* instead.
  
If the {@code ResourceBundle} is still not found, it will use the
 
* class loader of the first caller of the {@link
 
* #getLogger(java.lang.String, java.lang.String) getLogger} factory method.
 
* <p>
 
* Formatting (including localization) is the responsibility of
 
* the output Handler, which will typically call a Formatter.
 
* <p>
 
* Note that formatting need not occur synchronously.
  
It may be delayed
 
* until a LogRecord is actually written to an external sink.
 
* <p>
 
* The logging methods are grouped in five main categories:
 
* <ul>
 
* <li><p>
 
*
     
There are a set of "log" methods that take a log level, a message
 
*
     
string, and optionally some parameters to the message string.
 
* <li><p>
 
*
     
There are a set of "logp" methods (for "log precise") that are
 
*
     
like the "log" methods, but also take an explicit source class name
 
*
     
and method name.
 
* <li><p>
 
*
     
There are a set of "logrb" method (for "log with resource bundle")
 
*
     
that are like the "logp" method, but also take an explicit resource
 
*
     
bundle object for use in localizing the log message.
 
* <li><p>
 
*
     
There are convenience methods for tracing method entries (the
 
*
     
"entering" methods), method returns (the "exiting" methods) and
 
*
     
throwing exceptions (the "throwing" methods).
 
* <li><p>
 
*
     
Finally, there are a set of convenience methods for use in the
 
*
     
very simplest cases, when a developer simply wants to log a
 
*
     
simple string at a given log level.
  
These methods are named
 
*
     
after the standard Level names ("severe", "warning", "info", etc.)
 
*
     
and take a single argument, a message string.
 
* </ul>
 
* <p>
 
* For the methods that do not take an explicit source name and
 
* method name, the Logging framework will make a "best effort"
 
* to determine which class and method called into the logging method.
 
* However, it is important to realize that this automatically inferred
 
* information may only be approximate (or may even be quite wrong!).
 
* Virtual machines are allowed to do extensive optimizations when
 
* JITing and may entirely remove stack frames, making it impossible
 
* to reliably locate the calling class and method.
 
* <P>
 
* All methods on Logger are multi-thread safe.
 
* <p>
 
* <b>Subclassing Information:</b> Note that a LogManager class may
 
* provide its own implementation of named Loggers for any point in
 
* the namespace.
  
Therefore, any subclasses of Logger (unless they
 
* are implemented in conjunction with a new LogManager class) should
 
* take care to obtain a Logger instance from the LogManager class and
 
* should delegate operations such as "isLoggable" and "log(LogRecord)"
 
* to that instance.
  
Note that in order to intercept all logging
 
* output, subclasses need only override the log(LogRecord) method.
 
* All the other logging methods are implemented as calls on this
 
* log(LogRecord) method.
 
*
 
* @since 1.4
 
*/

public class Logger {
    
private static final Handler emptyHandlers[] = new Handler[0];
    
private static final int offValue = Level.OFF.intValue();

    
static final String SYSTEM_LOGGER_RB_NAME = "sun.util.logging.resources.logging";

    
// This class is immutable and it is important that it remains so.
    
private static final class LoggerBundle {
        
final String resourceBundleName; // Base name of the bundle.
        
final ResourceBundle userBundle; // Bundle set through setResourceBundle.
        
private LoggerBundle(String resourceBundleName, ResourceBundle bundle) {
            
this.resourceBundleName = resourceBundleName;
            
this.userBundle = bundle;
        
}
        
boolean isSystemBundle() {
            
return SYSTEM_LOGGER_RB_NAME.equals(resourceBundleName);
        
}
        
static LoggerBundle get(String name, ResourceBundle bundle) {
            
if (name == null && bundle == null) {
                
return NO_RESOURCE_BUNDLE;
            
} else if (SYSTEM_LOGGER_RB_NAME.equals(name) && bundle == null) {
                
return SYSTEM_BUNDLE;
            
} else {
                
return new LoggerBundle(name, bundle);
            
}
        
}
    
}

    
// This instance will be shared by all loggers created by the system
    
// code
    
private static final LoggerBundle SYSTEM_BUNDLE =
            
new LoggerBundle(SYSTEM_LOGGER_RB_NAME, null);

    
// This instance indicates that no resource bundle has been specified yet,
    
// and it will be shared by all loggers which have no resource bundle.
    
private static final LoggerBundle NO_RESOURCE_BUNDLE =
            
new LoggerBundle(null, null);

    
private volatile LogManager manager;
    
private String name;
    
private final CopyOnWriteArrayList<Handler> handlers =
        
new CopyOnWriteArrayList<>();
    
private volatile LoggerBundle loggerBundle = NO_RESOURCE_BUNDLE;
    
private volatile boolean useParentHandlers = true;
    
private volatile Filter filter;
    
private boolean anonymous;

    
// Cache to speed up behavior of findResourceBundle:
    
private ResourceBundle catalog;
     
// Cached resource bundle
    
private String catalogName;
         
// name associated with catalog
    
private Locale catalogLocale;
       
// locale associated with catalog

    
// The fields relating to parent-child relationships and levels
    
// are managed under a separate lock, the treeLock.
    
private static final Object treeLock = new Object();
    
// We keep weak references from parents to children, but strong
    
// references from children to parents.
    
private volatile Logger parent;
    
// our nearest parent.
    
private ArrayList<LogManager.LoggerWeakRef> kids;
   
// WeakReferences to loggers that have us as parent
    
private volatile Level levelObject;
    
private volatile int levelValue;
  
// current effective level value
    
private WeakReference<ClassLoader> callersClassLoaderRef;
    
private final boolean isSystemLogger;

    
/**
     
* GLOBAL_LOGGER_NAME is a name for the global logger.
     
*
     
* @since 1.6
     
*/
    
public static final String GLOBAL_LOGGER_NAME = "global";

    
/**
     
* Return global logger object with the name Logger.GLOBAL_LOGGER_NAME.
     
*
     
* @return global logger object
     
* @since 1.7
     
*/

    
public static final Logger getGlobal() {
        
// In order to break a cyclic dependence between the LogManager
        
// and Logger static initializers causing deadlocks, the global
        
// logger is created with a special constructor that does not
        
// initialize its log manager.
        
//
        
// If an application calls Logger.getGlobal() before any logger
        
// has been initialized, it is therefore possible that the
        
// LogManager class has not been initialized yet, and therefore
        
// Logger.global.manager will be null.
        
//
        
// In order to finish the initialization of the global logger, we
        
// will therefore call LogManager.getLogManager() here.
        
//
        
// To prevent race conditions we also need to call
        
// LogManager.getLogManager() unconditionally here.
        
// Indeed we cannot rely on the observed value of global.manager,
        
// because global.manager will become not null somewhere during
        
// the initialization of LogManager.
        
// If two threads are calling getGlobal() concurrently, one thread
        
// will see global.manager null and call LogManager.getLogManager(),
        
// but the other thread could come in at a time when global.manager
        
// is already set although ensureLogManagerInitialized is not finished
        
// yet...
        
// Calling LogManager.getLogManager() unconditionally will fix that.

        
LogManager.getLogManager();

        
// Now the global LogManager should be initialized,
        
// and the global logger should have been added to
        
// it, unless we were called within the constructor of a LogManager
        
// subclass installed as LogManager, in which case global.manager
        
// would still be null, and global will be lazily initialized later on.

        
return global;
    
}

    
/**
     
* The "global" Logger object is provided as a convenience to developers
     
* who are making casual use of the Logging package.
  
Developers
     
* who are making serious use of the logging package (for example
     
* in products) should create and use their own Logger objects,
     
* with appropriate names, so that logging can be controlled on a
     
* suitable per-Logger granularity. Developers also need to keep a
     
* strong reference to their Logger objects to prevent them from
     
* being garbage collected.
     
* <p>
     
* @deprecated Initialization of this field is prone to deadlocks.
     
* The field must be initialized by the Logger class initialization
     
* which may cause deadlocks with the LogManager class initialization.
     
* In such cases two class initialization wait for each other to complete.
     
* The preferred way to get the global logger object is via the call
     
* <code>Logger.getGlobal()</code>.
     
* For compatibility with old JDK versions where the
     
* <code>Logger.getGlobal()</code> is not available use the call
     
* <code>Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)</code>
     
* or <code>Logger.getLogger("global")</code>.
     
*/

    
@Deprecated
    
public static final Logger global = new Logger(GLOBAL_LOGGER_NAME);

    
/**
     
* Protected method to construct a logger for a named subsystem.
     
* <p>
     
* The logger will be initially configured with a null Level
     
* and with useParentHandlers set to true.
     
*
     
* @param
   
name
    
A name for the logger.
  
This should
     
*
                          
be a dot-separated name and should normally
     
*
                          
be based on the package name or class name
     
*
                          
of the subsystem, such as java.net
     
*
                          
or javax.swing.
  
It may be null for anonymous Loggers.
     
* @param
   
resourceBundleName
  
name of ResourceBundle to be used for localizing
     
*
                          
messages for this logger.
  
May be null if none
     
*
                          
of the messages require localization.
     
* @throws MissingResourceException if the resourceBundleName is non-null and
     
*
             
no corresponding resource can be found.
     
*/

    
protected Logger(String name, String resourceBundleName) {
        
this(name, resourceBundleName, null, LogManager.getLogManager(), false);
    
}

    
Logger(String name, String resourceBundleName, Class<?> caller, LogManager manager, boolean isSystemLogger) {
        
this.manager = manager;
        
this.isSystemLogger = isSystemLogger;
        
setupResourceInfo(resourceBundleName, caller);
        
this.name = name;
        
levelValue = Level.INFO.intValue();
    
}

    
private void setCallersClassLoaderRef(Class<?> caller) {
        
ClassLoader callersClassLoader = ((caller != null)
                                         
? caller.getClassLoader()
                                         
: null);
        
if (callersClassLoader != null) {
            
this.callersClassLoaderRef = new WeakReference<>(callersClassLoader);
        
}
    
}

    
private ClassLoader getCallersClassLoader() {
        
return (callersClassLoaderRef != null)
                
? callersClassLoaderRef.get()
                
: null;
    
}

    
// This constructor is used only to create the global Logger.
    
// It is needed to break a cyclic dependence between the LogManager
    
// and Logger static initializers causing deadlocks.
    
private Logger(String name) {
        
// The manager field is not initialized here.
        
this.name = name;
        
this.isSystemLogger = true;
        
levelValue = Level.INFO.intValue();
    
}

    
// It is called from LoggerContext.addLocalLogger() when the logger
    
// is actually added to a LogManager.
    
void setLogManager(LogManager manager) {
        
this.manager = manager;
    
}

    
private void checkPermission() throws SecurityException {
        
if (!anonymous) {
            
if (manager == null) {
                
// Complete initialization of the global Logger.
                
manager = LogManager.getLogManager();
            
}
            
manager.checkPermission();
        
}
    
}

    
// Until all JDK code converted to call sun.util.logging.PlatformLogger
    
// (see 7054233), we need to determine if Logger.getLogger is to add
    
// a system logger or user logger.
    
//
    
// As an interim solution, if the immediate caller whose caller loader is
    
// null, we assume it's a system logger and add it to the system context.
    
// These system loggers only set the resource bundle to the given
    
// resource bundle name (rather than the default system resource bundle).
    
private static class SystemLoggerHelper {
        
static boolean disableCallerCheck = getBooleanProperty("sun.util.logging.disableCallerCheck");
        
private static boolean getBooleanProperty(final String key) {
            
String s = AccessController.doPrivileged(new PrivilegedAction<String>() {
                
@Override
                
public String run() {
                    
return System.getProperty(key);
                
}
            
});
            
return Boolean.valueOf(s);
        
}
    
}

    
private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
        
LogManager manager = LogManager.getLogManager();
        
SecurityManager sm = System.getSecurityManager();
        
if (sm != null && !SystemLoggerHelper.disableCallerCheck) {
            
if (caller.getClassLoader() == null) {
                
return manager.demandSystemLogger(name, resourceBundleName);
            
}
        
}
        
return manager.demandLogger(name, resourceBundleName, caller);
        
// ends up calling new Logger(name, resourceBundleName, caller)
        
// iff the logger doesn't exist already
    
}

    
/**
     
* Find or create a logger for a named subsystem.
  
If a logger has
     
* already been created with the given name it is returned.
  
Otherwise
     
* a new logger is created.
     
* <p>
     
* If a new logger is created its log level will be configured
     
* based on the LogManager configuration and it will configured
     
* to also send logging output to its parent's Handlers.
  
It will
     
* be registered in the LogManager global namespace.
     
* <p>
     
* Note: The LogManager may only retain a weak reference to the newly
     
* created Logger. It is important to understand that a previously
     
* created Logger with the given name may be garbage collected at any
     
* time if there is no strong reference to the Logger. In particular,
     
* this means that two back-to-back calls like
     
* {@code getLogger("MyLogger").log(...)} may use different Logger
     
* objects named "MyLogger" if there is no strong reference to the
     
* Logger named "MyLogger" elsewhere in the program.
     
*
     
* @param
   
name
            
A name for the logger.
  
This should
     
*
                          
be a dot-separated name and should normally
     
*
                          
be based on the package name or class name
     
*
                          
of the subsystem, such as java.net
     
*
                          
or javax.swing
     
* @return a suitable Logger
     
* @throws NullPointerException if the name is null.
     
*/


    
// Synchronization is not required here. All synchronization for
    
// adding a new Logger object is handled by LogManager.addLogger().
    
@CallerSensitive
    
public static Logger getLogger(String name) {
        
// This method is intentionally not a wrapper around a call
        
// to getLogger(name, resourceBundleName). If it were then
        
// this sequence:
        
//
        
//
     
getLogger("Foo", "resourceBundleForFoo");
        
//
     
getLogger("Foo");
        
//
        
// would throw an IllegalArgumentException in the second call
        
// because the wrapper would result in an attempt to replace
        
// the existing "resourceBundleForFoo" with null.
        
return demandLogger(name, null, Reflection.getCallerClass());
    
}

    
/**
     
* Find or create a logger for a named subsystem.
  
If a logger has
     
* already been created with the given name it is returned.
  
Otherwise
     
* a new logger is created.
     
* <p>
     
* If a new logger is created its log level will be configured
     
* based on the LogManager and it will configured to also send logging
     
* output to its parent's Handlers.
  
It will be registered in
     
* the LogManager global namespace.
     
* <p>
     
* Note: The LogManager may only retain a weak reference to the newly
     
* created Logger. It is important to understand that a previously
     
* created Logger with the given name may be garbage collected at any
     
* time if there is no strong reference to the Logger. In particular,
     
* this means that two back-to-back calls like
     
* {@code getLogger("MyLogger", ...).log(...)} may use different Logger
     
* objects named "MyLogger" if there is no strong reference to the
     
* Logger named "MyLogger" elsewhere in the program.
     
* <p>
     
* If the named Logger already exists and does not yet have a
     
* localization resource bundle then the given resource bundle
     
* name is used.
  
If the named Logger already exists and has
     
* a different resource bundle name then an IllegalArgumentException
     
* is thrown.
     
* <p>
     
* @param
   
name
    
A name for the logger.
  
This should
     
*
                          
be a dot-separated name and should normally
     
*
                          
be based on the package name or class name
     
*
                          
of the subsystem, such as java.net
     
*
                          
or javax.swing
     
* @param
   
resourceBundleName
  
name of ResourceBundle to be used for localizing
     
*
                          
messages for this logger. May be {@code null}
     
*
                          
if none of the messages require localization.
     
* @return a suitable Logger
     
* @throws MissingResourceException if the resourceBundleName is non-null and
     
*
             
no corresponding resource can be found.
     
* @throws IllegalArgumentException if the Logger already exists and uses
     
*
             
a different resource bundle name; or if
     
*
             
{@code resourceBundleName} is {@code null} but the named
     
*
             
logger has a resource bundle set.
     
* @throws NullPointerException if the name is null.
     
*/


    
// Synchronization is not required here. All synchronization for
    
// adding a new Logger object is handled by LogManager.addLogger().
    
@CallerSensitive
    
public static Logger getLogger(String name, String resourceBundleName) {
        
Class<?> callerClass = Reflection.getCallerClass();
        
Logger result = demandLogger(name, resourceBundleName, callerClass);

        
// MissingResourceException or IllegalArgumentException can be
        
// thrown by setupResourceInfo().
        
// We have to set the callers ClassLoader here in case demandLogger
        
// above found a previously created Logger.
  
This can happen, for

        
// example, if Logger.getLogger(name) is called and subsequently
        
// Logger.getLogger(name, resourceBundleName) is called.
  
In this case
        
// we won't necessarily have the correct classloader saved away, so
        
// we need to set it here, too.

        
result.setupResourceInfo(resourceBundleName, callerClass);
        
return result;
    
}

    
// package-private
    
// Add a platform logger to the system context.
    
// i.e. caller of sun.util.logging.PlatformLogger.getLogger
    
static Logger getPlatformLogger(String name) {
        
LogManager manager = LogManager.getLogManager();

        
// all loggers in the system context will default to
        
// the system logger's resource bundle
        
Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME);
        
return result;
    
}

    
/**
     
* Create an anonymous Logger.
  
The newly created Logger is not
     
* registered in the LogManager namespace.
  
There will be no
     
* access checks on updates to the logger.
     
* <p>
     
* This factory method is primarily intended for use from applets.
     
* Because the resulting Logger is anonymous it can be kept private
     
* by the creating class.
  
This removes the need for normal security
     
* checks, which in turn allows untrusted applet code to update
     
* the control state of the Logger.
  
For example an applet can do
     
* a setLevel or an addHandler on an anonymous Logger.
     
* <p>
     
* Even although the new logger is anonymous, it is configured
     
* to have the root logger ("") as its parent.
  
This means that
     
* by default it inherits its effective level and handlers
     
* from the root logger. Changing its parent via the
     
* {@link #setParent(java.util.logging.Logger) setParent} method
     
* will still require the security permission specified by that method.
     
* <p>
     
*
     
* @return a newly created private Logger
     
*/

    
public static Logger getAnonymousLogger() {
        
return getAnonymousLogger(null);
    
}

    
/**
     
* Create an anonymous Logger.
  
The newly created Logger is not
     
* registered in the LogManager namespace.
  
There will be no
     
* access checks on updates to the logger.
     
* <p>
     
* This factory method is primarily intended for use from applets.
     
* Because the resulting Logger is anonymous it can be kept private
     
* by the creating class.
  
This removes the need for normal security
     
* checks, which in turn allows untrusted applet code to update
     
* the control state of the Logger.
  
For example an applet can do
     
* a setLevel or an addHandler on an anonymous Logger.
     
* <p>
     
* Even although the new logger is anonymous, it is configured
     
* to have the root logger ("") as its parent.
  
This means that
     
* by default it inherits its effective level and handlers
     
* from the root logger.
  
Changing its parent via the
     
* {@link #setParent(java.util.logging.Logger) setParent} method
     
* will still require the security permission specified by that method.
     
* <p>
     
* @param
   
resourceBundleName
  
name of ResourceBundle to be used for localizing
     
*
                          
messages for this logger.
     
*
          
May be null if none of the messages require localization.
     
* @return a newly created private Logger
     
* @throws MissingResourceException if the resourceBundleName is non-null and
     
*
             
no corresponding resource can be found.
     
*/


    
// Synchronization is not required here. All synchronization for
    
// adding a new anonymous Logger object is handled by doSetParent().
    
@CallerSensitive
    
public static Logger getAnonymousLogger(String resourceBundleName) {
        
LogManager manager = LogManager.getLogManager();
        
// cleanup some Loggers that have been GC'ed
        
manager.drainLoggerRefQueueBounded();
        
Logger result = new Logger(null, resourceBundleName,
                                   
Reflection.getCallerClass(), manager, false);
        
result.anonymous = true;
        
Logger root = manager.getLogger("");
        
result.doSetParent(root);
        
return result;
    
}

    
/**
     
* Retrieve the localization resource bundle for this
     
* logger.
     
* This method will return a {@code ResourceBundle} that was either
     
* set by the {@link
     
* #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method or
     
* <a href="#ResourceBundleMapping">mapped from the
     
* the resource bundle name</a> set via the {@link
     
* Logger#getLogger(java.lang.String, java.lang.String) getLogger} factory
     
* method for the current default locale.
     
* <br>Note that if the result is {@code null}, then the Logger will use a resource
     
* bundle or resource bundle name inherited from its parent.
     
*
     
* @return localization bundle (may be {@code null})
     
*/

    
public ResourceBundle getResourceBundle() {
        
return findResourceBundle(getResourceBundleName(), true);
    
}

    
/**
     
* Retrieve the localization resource bundle name for this
     
* logger.
     
* This is either the name specified through the {@link
     
* #getLogger(java.lang.String, java.lang.String) getLogger} factory method,
     
* or the {@linkplain ResourceBundle#getBaseBundleName() base name} of the
     
* ResourceBundle set through {@link
     
* #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method.
     
* <br>Note that if the result is {@code null}, then the Logger will use a resource
     
* bundle or resource bundle name inherited from its parent.
     
*
     
* @return localization bundle name (may be {@code null})
     
*/

    
public String getResourceBundleName() {
        
return loggerBundle.resourceBundleName;
    
}

    
/**
     
* Set a filter to control output on this Logger.
     
* <P>
     
* After passing the initial "level" check, the Logger will
     
* call this Filter to check if a log record should really
     
* be published.
     
*
     
* @param
   
newFilter
  
a filter object (may be null)
     
* @throws
  
SecurityException if a security manager exists,
     
*
          
this logger is not anonymous, and the caller
     
*
          
does not have LoggingPermission("control").
     
*/

    
public void setFilter(Filter newFilter) throws SecurityException {
        
checkPermission();
        
filter = newFilter;
    
}

    
/**
     
* Get the current filter for this Logger.
     
*
     
* @return
  
a filter object (may be null)
     
*/

    
public Filter getFilter() {
        
return filter;
    
}

    
/**
     
* Log a LogRecord.
     
* <p>
     
* All the other logging methods in this class call through
     
* this method to actually perform any logging.
  
Subclasses can
     
* override this single method to capture all log activity.
     
*
     
* @param record the LogRecord to be published
     
*/

    
public void log(LogRecord record) {
        
if (!isLoggable(record.getLevel())) {
            
return;
        
}
        
Filter theFilter = filter;
        
if (theFilter != null && !theFilter.isLoggable(record)) {
            
return;
        
}

        
// Post the LogRecord to all our Handlers, and then to
        
// our parents' handlers, all the way up the tree.

        
Logger logger = this;
        
while (logger != null) {
            
final Handler[] loggerHandlers = isSystemLogger
                
? logger.accessCheckedHandlers()
                
: logger.getHandlers();

            
for (Handler handler : loggerHandlers) {
                
handler.publish(record);
            
}

            
final boolean useParentHdls = isSystemLogger
                
? logger.useParentHandlers
                
: logger.getUseParentHandlers();

            
if (!useParentHdls) {
                
break;
            
}

            
logger = isSystemLogger ? logger.parent : logger.getParent();
        
}
    
}

    
// private support method for logging.
    
// We fill in the logger name, resource bundle name, and
    
// resource bundle and then call "void log(LogRecord)".
    
private void doLog(LogRecord lr) {
        
lr.setLoggerName(name);
        
final LoggerBundle lb = getEffectiveLoggerBundle();
        
final ResourceBundle
  
bundle
= lb.userBundle;
        
final String ebname = lb.resourceBundleName;
        
if (ebname != null && bundle != null) {
            
lr.setResourceBundleName(ebname);
            
lr.setResourceBundle(bundle);
        
}
        
log(lr);
    
}


    
//================================================================
    
// Start of convenience methods WITHOUT className and methodName
    
//================================================================

    
/**
     
* Log a message, with no arguments.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then the given message is forwarded to all the
     
* registered output Handler objects.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
msgThe string message (or a key in the message catalog)
     
*/

    
public void log(Level level, String msg) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msg);
        
doLog(lr);
    
}

    
/**
     
* Log a message, which is only to be constructed if the logging level
     
* is such that the message will actually be logged.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then the message is constructed by invoking the provided
     
* supplier function and forwarded to all the registered output
     
* Handler objects.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
msgSupplierA function, which when called, produces the
     
*
                        
desired log message
     
* @since 1.8
     
*/

    
public void log(Level level, Supplier<String> msgSupplier) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msgSupplier.get());
        
doLog(lr);
    
}

    
/**
     
* Log a message, with one object parameter.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then a corresponding LogRecord is created and forwarded
     
* to all the registered output Handler objects.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
msgThe string message (or a key in the message catalog)
     
* @param
   
param1
  
parameter to the message
     
*/

    
public void log(Level level, String msg, Object param1) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msg);
        
Object params[] = { param1 };
        
lr.setParameters(params);
        
doLog(lr);
    
}

    
/**
     
* Log a message, with an array of object arguments.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then a corresponding LogRecord is created and forwarded
     
* to all the registered output Handler objects.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
msgThe string message (or a key in the message catalog)
     
* @param
   
params
  
array of parameters to the message
     
*/

    
public void log(Level level, String msg, Object params[]) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msg);
        
lr.setParameters(params);
        
doLog(lr);
    
}

    
/**
     
* Log a message, with associated Throwable information.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then the given arguments are stored in a LogRecord
     
* which is forwarded to all registered output handlers.
     
* <p>
     
* Note that the thrown argument is stored in the LogRecord thrown
     
* property, rather than the LogRecord parameters property.
  
Thus it is
     
* processed specially by output Formatters and is not treated
     
* as a formatting parameter to the LogRecord message property.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
msgThe string message (or a key in the message catalog)
     
* @param
   
thrown
  
Throwable associated with log message.
     
*/

    
public void log(Level level, String msg, Throwable thrown) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msg);
        
lr.setThrown(thrown);
        
doLog(lr);
    
}

    
/**
     
* Log a lazily constructed message, with associated Throwable information.
     
* <p>
     
* If the logger is currently enabled for the given message level then the
     
* message is constructed by invoking the provided supplier function. The
     
* message and the given {@link Throwable} are then stored in a {@link
     
* LogRecord} which is forwarded to all registered output handlers.
     
* <p>
     
* Note that the thrown argument is stored in the LogRecord thrown
     
* property, rather than the LogRecord parameters property.
  
Thus it is
     
* processed specially by output Formatters and is not treated
     
* as a formatting parameter to the LogRecord message property.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
thrown
  
Throwable associated with log message.
     
* @param
   
msgSupplierA function, which when called, produces the
     
*
                        
desired log message
     
* @since
   
1.8
     
*/

    
public void log(Level level, Throwable thrown, Supplier<String> msgSupplier) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msgSupplier.get());
        
lr.setThrown(thrown);
        
doLog(lr);
    
}

    
//================================================================
    
// Start of convenience methods WITH className and methodName
    
//================================================================

    
/**
     
* Log a message, specifying source class and method,
     
* with no arguments.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then the given message is forwarded to all the
     
* registered output Handler objects.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
sourceClass
    
name of class that issued the logging request
     
* @param
   
sourceMethodname of method that issued the logging request
     
* @param
   
msgThe string message (or a key in the message catalog)
     
*/

    
public void logp(Level level, String sourceClass, String sourceMethod, String msg) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msg);
        
lr.setSourceClassName(sourceClass);
        
lr.setSourceMethodName(sourceMethod);
        
doLog(lr);
    
}

    
/**
     
* Log a lazily constructed message, specifying source class and method,
     
* with no arguments.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then the message is constructed by invoking the provided
     
* supplier function and forwarded to all the registered output
     
* Handler objects.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
sourceClass
    
name of class that issued the logging request
     
* @param
   
sourceMethodname of method that issued the logging request
     
* @param
   
msgSupplierA function, which when called, produces the
     
*
                        
desired log message
     
* @since
   
1.8
     
*/

    
public void logp(Level level, String sourceClass, String sourceMethod,
                     
Supplier<String> msgSupplier) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msgSupplier.get());
        
lr.setSourceClassName(sourceClass);
        
lr.setSourceMethodName(sourceMethod);
        
doLog(lr);
    
}

    
/**
     
* Log a message, specifying source class and method,
     
* with a single object parameter to the log message.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then a corresponding LogRecord is created and forwarded
     
* to all the registered output Handler objects.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
sourceClass
    
name of class that issued the logging request
     
* @param
   
sourceMethodname of method that issued the logging request
     
* @param
   
msg
      
The string message (or a key in the message catalog)
     
* @param
   
param1
    
Parameter to the log message.
     
*/

    
public void logp(Level level, String sourceClass, String sourceMethod,
                                                
String msg, Object param1) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msg);
        
lr.setSourceClassName(sourceClass);
        
lr.setSourceMethodName(sourceMethod);
        
Object params[] = { param1 };
        
lr.setParameters(params);
        
doLog(lr);
    
}

    
/**
     
* Log a message, specifying source class and method,
     
* with an array of object arguments.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then a corresponding LogRecord is created and forwarded
     
* to all the registered output Handler objects.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
sourceClass
    
name of class that issued the logging request
     
* @param
   
sourceMethodname of method that issued the logging request
     
* @param
   
msgThe string message (or a key in the message catalog)
     
* @param
   
params
  
Array of parameters to the message
     
*/

    
public void logp(Level level, String sourceClass, String sourceMethod,
                                                
String msg, Object params[]) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msg);
        
lr.setSourceClassName(sourceClass);
        
lr.setSourceMethodName(sourceMethod);
        
lr.setParameters(params);
        
doLog(lr);
    
}

    
/**
     
* Log a message, specifying source class and method,
     
* with associated Throwable information.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then the given arguments are stored in a LogRecord
     
* which is forwarded to all registered output handlers.
     
* <p>
     
* Note that the thrown argument is stored in the LogRecord thrown
     
* property, rather than the LogRecord parameters property.
  
Thus it is
     
* processed specially by output Formatters and is not treated
     
* as a formatting parameter to the LogRecord message property.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
sourceClass
    
name of class that issued the logging request
     
* @param
   
sourceMethodname of method that issued the logging request
     
* @param
   
msgThe string message (or a key in the message catalog)
     
* @param
   
thrown
  
Throwable associated with log message.
     
*/

    
public void logp(Level level, String sourceClass, String sourceMethod,
                     
String msg, Throwable thrown) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msg);
        
lr.setSourceClassName(sourceClass);
        
lr.setSourceMethodName(sourceMethod);
        
lr.setThrown(thrown);
        
doLog(lr);
    
}

    
/**
     
* Log a lazily constructed message, specifying source class and method,
     
* with associated Throwable information.
     
* <p>
     
* If the logger is currently enabled for the given message level then the
     
* message is constructed by invoking the provided supplier function. The
     
* message and the given {@link Throwable} are then stored in a {@link
     
* LogRecord} which is forwarded to all registered output handlers.
     
* <p>
     
* Note that the thrown argument is stored in the LogRecord thrown
     
* property, rather than the LogRecord parameters property.
  
Thus it is
     
* processed specially by output Formatters and is not treated
     
* as a formatting parameter to the LogRecord message property.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
sourceClass
    
name of class that issued the logging request
     
* @param
   
sourceMethodname of method that issued the logging request
     
* @param
   
thrown
  
Throwable associated with log message.
     
* @param
   
msgSupplierA function, which when called, produces the
     
*
                        
desired log message
     
* @since
   
1.8
     
*/

    
public void logp(Level level, String sourceClass, String sourceMethod,
                     
Throwable thrown, Supplier<String> msgSupplier) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msgSupplier.get());
        
lr.setSourceClassName(sourceClass);
        
lr.setSourceMethodName(sourceMethod);
        
lr.setThrown(thrown);
        
doLog(lr);
    
}


    
//=========================================================================
    
// Start of convenience methods WITH className, methodName and bundle name.
    
//=========================================================================

    
// Private support method for logging for "logrb" methods.
    
// We fill in the logger name, resource bundle name, and
    
// resource bundle and then call "void log(LogRecord)".
    
private void doLog(LogRecord lr, String rbname) {
        
lr.setLoggerName(name);
        
if (rbname != null) {
            
lr.setResourceBundleName(rbname);
            
lr.setResourceBundle(findResourceBundle(rbname, false));
        
}
        
log(lr);
    
}

    
// Private support method for logging for "logrb" methods.
    
private void doLog(LogRecord lr, ResourceBundle rb) {
        
lr.setLoggerName(name);
        
if (rb != null) {
            
lr.setResourceBundleName(rb.getBaseBundleName());
            
lr.setResourceBundle(rb);
        
}
        
log(lr);
    
}

    
/**
     
* Log a message, specifying source class, method, and resource bundle name
     
* with no arguments.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then the given message is forwarded to all the
     
* registered output Handler objects.
     
* <p>
     
* The msg string is localized using the named resource bundle.
  
If the
     
* resource bundle name is null, or an empty String or invalid
     
* then the msg string is not localized.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
sourceClass
    
name of class that issued the logging request
     
* @param
   
sourceMethodname of method that issued the logging request
     
* @param
   
bundleNamename of resource bundle to localize msg,
     
*
                         
can be null
     
* @param
   
msgThe string message (or a key in the message catalog)
     
* @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
     
* java.lang.String, java.util.ResourceBundle, java.lang.String,
     
* java.lang.Object...)} instead.
     
*/

    
@Deprecated
    
public void logrb(Level level, String sourceClass, String sourceMethod,
                                
String bundleName, String msg) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msg);
        
lr.setSourceClassName(sourceClass);
        
lr.setSourceMethodName(sourceMethod);
        
doLog(lr, bundleName);
    
}

    
/**
     
* Log a message, specifying source class, method, and resource bundle name,
     
* with a single object parameter to the log message.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then a corresponding LogRecord is created and forwarded
     
* to all the registered output Handler objects.
     
* <p>
     
* The msg string is localized using the named resource bundle.
  
If the
     
* resource bundle name is null, or an empty String or invalid
     
* then the msg string is not localized.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
sourceClass
    
name of class that issued the logging request
     
* @param
   
sourceMethodname of method that issued the logging request
     
* @param
   
bundleNamename of resource bundle to localize msg,
     
*
                         
can be null
     
* @param
   
msg
      
The string message (or a key in the message catalog)
     
* @param
   
param1
    
Parameter to the log message.
     
* @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
     
*
   
java.lang.String, java.util.ResourceBundle, java.lang.String,
     
*
   
java.lang.Object...)} instead
     
*/

    
@Deprecated
    
public void logrb(Level level, String sourceClass, String sourceMethod,
                                
String bundleName, String msg, Object param1) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msg);
        
lr.setSourceClassName(sourceClass);
        
lr.setSourceMethodName(sourceMethod);
        
Object params[] = { param1 };
        
lr.setParameters(params);
        
doLog(lr, bundleName);
    
}

    
/**
     
* Log a message, specifying source class, method, and resource bundle name,
     
* with an array of object arguments.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then a corresponding LogRecord is created and forwarded
     
* to all the registered output Handler objects.
     
* <p>
     
* The msg string is localized using the named resource bundle.
  
If the
     
* resource bundle name is null, or an empty String or invalid
     
* then the msg string is not localized.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
sourceClass
    
name of class that issued the logging request
     
* @param
   
sourceMethodname of method that issued the logging request
     
* @param
   
bundleNamename of resource bundle to localize msg,
     
*
                         
can be null.
     
* @param
   
msgThe string message (or a key in the message catalog)
     
* @param
   
params
  
Array of parameters to the message
     
* @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
     
*
      
java.lang.String, java.util.ResourceBundle, java.lang.String,
     
*
      
java.lang.Object...)} instead.
     
*/

    
@Deprecated
    
public void logrb(Level level, String sourceClass, String sourceMethod,
                                
String bundleName, String msg, Object params[]) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msg);
        
lr.setSourceClassName(sourceClass);
        
lr.setSourceMethodName(sourceMethod);
        
lr.setParameters(params);
        
doLog(lr, bundleName);
    
}

    
/**
     
* Log a message, specifying source class, method, and resource bundle,
     
* with an optional list of message parameters.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then a corresponding LogRecord is created and forwarded
     
* to all the registered output Handler objects.
     
* <p>
     
* The {@code msg} string is localized using the given resource bundle.
     
* If the resource bundle is {@code null}, then the {@code msg} string is not
     
* localized.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
sourceClass
    
Name of the class that issued the logging request
     
* @param
   
sourceMethodName of the method that issued the logging request
     
* @param
   
bundle
         
Resource bundle to localize {@code msg},
     
*
                         
can be {@code null}.
     
* @param
   
msgThe string message (or a key in the message catalog)
     
* @param
   
params
  
Parameters to the message (optional, may be none).
     
* @since 1.8
     
*/

    
public void logrb(Level level, String sourceClass, String sourceMethod,
                      
ResourceBundle bundle, String msg, Object... params) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msg);
        
lr.setSourceClassName(sourceClass);
        
lr.setSourceMethodName(sourceMethod);
        
if (params != null && params.length != 0) {
            
lr.setParameters(params);
        
}
        
doLog(lr, bundle);
    
}

    
/**
     
* Log a message, specifying source class, method, and resource bundle name,
     
* with associated Throwable information.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then the given arguments are stored in a LogRecord
     
* which is forwarded to all registered output handlers.
     
* <p>
     
* The msg string is localized using the named resource bundle.
  
If the
     
* resource bundle name is null, or an empty String or invalid
     
* then the msg string is not localized.
     
* <p>
     
* Note that the thrown argument is stored in the LogRecord thrown
     
* property, rather than the LogRecord parameters property.
  
Thus it is
     
* processed specially by output Formatters and is not treated
     
* as a formatting parameter to the LogRecord message property.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
sourceClass
    
name of class that issued the logging request
     
* @param
   
sourceMethodname of method that issued the logging request
     
* @param
   
bundleNamename of resource bundle to localize msg,
     
*
                         
can be null
     
* @param
   
msgThe string message (or a key in the message catalog)
     
* @param
   
thrown
  
Throwable associated with log message.
     
* @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
     
*java.lang.String, java.util.ResourceBundle, java.lang.String,
     
*java.lang.Throwable)} instead.
     
*/

    
@Deprecated
    
public void logrb(Level level, String sourceClass, String sourceMethod,
                                        
String bundleName, String msg, Throwable thrown) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msg);
        
lr.setSourceClassName(sourceClass);
        
lr.setSourceMethodName(sourceMethod);
        
lr.setThrown(thrown);
        
doLog(lr, bundleName);
    
}

    
/**
     
* Log a message, specifying source class, method, and resource bundle,
     
* with associated Throwable information.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then the given arguments are stored in a LogRecord
     
* which is forwarded to all registered output handlers.
     
* <p>
     
* The {@code msg} string is localized using the given resource bundle.
     
* If the resource bundle is {@code null}, then the {@code msg} string is not
     
* localized.
     
* <p>
     
* Note that the thrown argument is stored in the LogRecord thrown
     
* property, rather than the LogRecord parameters property.
  
Thus it is
     
* processed specially by output Formatters and is not treated
     
* as a formatting parameter to the LogRecord message property.
     
* <p>
     
* @param
   
levelOne of the message level identifiers, e.g., SEVERE
     
* @param
   
sourceClass
    
Name of the class that issued the logging request
     
* @param
   
sourceMethodName of the method that issued the logging request
     
* @param
   
bundle
         
Resource bundle to localize {@code msg},
     
*
                         
can be {@code null}
     
* @param
   
msgThe string message (or a key in the message catalog)
     
* @param
   
thrown
  
Throwable associated with the log message.
     
* @since 1.8
     
*/

    
public void logrb(Level level, String sourceClass, String sourceMethod,
                      
ResourceBundle bundle, String msg, Throwable thrown) {
        
if (!isLoggable(level)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(level, msg);
        
lr.setSourceClassName(sourceClass);
        
lr.setSourceMethodName(sourceMethod);
        
lr.setThrown(thrown);
        
doLog(lr, bundle);
    
}

    
//======================================================================
    
// Start of convenience methods for logging method entries and returns.
    
//======================================================================

    
/**
     
* Log a method entry.
     
* <p>
     
* This is a convenience method that can be used to log entry
     
* to a method.
  
A LogRecord with message "ENTRY", log level
     
* FINER, and the given sourceMethod and sourceClass is logged.
     
* <p>
     
* @param
   
sourceClass
    
name of class that issued the logging request
     
* @param
   
sourceMethodname of method that is being entered
     
*/

    
public void entering(String sourceClass, String sourceMethod) {
        
logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
    
}

    
/**
     
* Log a method entry, with one parameter.
     
* <p>
     
* This is a convenience method that can be used to log entry
     
* to a method.
  
A LogRecord with message "ENTRY {0}", log level
     
* FINER, and the given sourceMethod, sourceClass, and parameter
     
* is logged.
     
* <p>
     
* @param
   
sourceClass
    
name of class that issued the logging request
     
* @param
   
sourceMethodname of method that is being entered
     
* @param
   
param1
         
parameter to the method being entered
     
*/

    
public void entering(String sourceClass, String sourceMethod, Object param1) {
        
logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param1);
    
}

    
/**
     
* Log a method entry, with an array of parameters.
     
* <p>
     
* This is a convenience method that can be used to log entry
     
* to a method.
  
A LogRecord with message "ENTRY" (followed by a
     
* format {N} indicator for each entry in the parameter array),
     
* log level FINER, and the given sourceMethod, sourceClass, and
     
* parameters is logged.
     
* <p>
     
* @param
   
sourceClass
    
name of class that issued the logging request
     
* @param
   
sourceMethodname of method that is being entered
     
* @param
   
params
         
array of parameters to the method being entered
     
*/

    
public void entering(String sourceClass, String sourceMethod, Object params[]) {
        
String msg = "ENTRY";
        
if (params == null ) {
           
logp(Level.FINER, sourceClass, sourceMethod, msg);
           
return;
        
}
        
if (!isLoggable(Level.FINER)) return;
        
for (int i = 0; i < params.length; i++) {
            
msg = msg + " {" + i + "}";
        
}
        
logp(Level.FINER, sourceClass, sourceMethod, msg, params);
    
}

    
/**
     
* Log a method return.
     
* <p>
     
* This is a convenience method that can be used to log returning
     
* from a method.
  
A LogRecord with message "RETURN", log level
     
* FINER, and the given sourceMethod and sourceClass is logged.
     
* <p>
     
* @param
   
sourceClass
    
name of class that issued the logging request
     
* @param
   
sourceMethodname of the method
     
*/

    
public void exiting(String sourceClass, String sourceMethod) {
        
logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
    
}


    
/**
     
* Log a method return, with result object.
     
* <p>
     
* This is a convenience method that can be used to log returning
     
* from a method.
  
A LogRecord with message "RETURN {0}", log level
     
* FINER, and the gives sourceMethod, sourceClass, and result
     
* object is logged.
     
* <p>
     
* @param
   
sourceClass
    
name of class that issued the logging request
     
* @param
   
sourceMethodname of the method
     
* @param
   
result
  
Object that is being returned
     
*/

    
public void exiting(String sourceClass, String sourceMethod, Object result) {
        
logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
    
}

    
/**
     
* Log throwing an exception.
     
* <p>
     
* This is a convenience method to log that a method is
     
* terminating by throwing an exception.
  
The logging is done
     
* using the FINER level.
     
* <p>
     
* If the logger is currently enabled for the given message
     
* level then the given arguments are stored in a LogRecord
     
* which is forwarded to all registered output handlers.
  
The
     
* LogRecord's message is set to "THROW".
     
* <p>
     
* Note that the thrown argument is stored in the LogRecord thrown
     
* property, rather than the LogRecord parameters property.
  
Thus it is
     
* processed specially by output Formatters and is not treated
     
* as a formatting parameter to the LogRecord message property.
     
* <p>
     
* @param
   
sourceClass
    
name of class that issued the logging request
     
* @param
   
sourceMethod
  
name of the method.
     
* @param
   
thrown
  
The Throwable that is being thrown.
     
*/

    
public void throwing(String sourceClass, String sourceMethod, Throwable thrown) {
        
if (!isLoggable(Level.FINER)) {
            
return;
        
}
        
LogRecord lr = new LogRecord(Level.FINER, "THROW");
        
lr.setSourceClassName(sourceClass);
        
lr.setSourceMethodName(sourceMethod);
        
lr.setThrown(thrown);
        
doLog(lr);
    
}

    
//=======================================================================
    
// Start of simple convenience methods using level names as method names
    
//=======================================================================

    
/**
     
* Log a SEVERE message.
     
* <p>
     
* If the logger is currently enabled for the SEVERE message
     
* level then the given message is forwarded to all the
     
* registered output Handler objects.
     
* <p>
     
* @param
   
msgThe string message (or a key in the message catalog)
     
*/

    
public void severe(String msg) {
        
log(Level.SEVERE, msg);
    
}

    
/**
     
* Log a WARNING message.
     
* <p>
     
* If the logger is currently enabled for the WARNING message
     
* level then the given message is forwarded to all the
     
* registered output Handler objects.
     
* <p>
     
* @param
   
msgThe string message (or a key in the message catalog)
     
*/

    
public void warning(String msg) {
        
log(Level.WARNING, msg);
    
}

    
/**
     
* Log an INFO message.
     
* <p>
     
* If the logger is currently enabled for the INFO message
     
* level then the given message is forwarded to all the
     
* registered output Handler objects.
     
* <p>
     
* @param
   
msgThe string message (or a key in the message catalog)
     
*/

    
public void info(String msg) {
        
log(Level.INFO, msg);
    
}

    
/**
     
* Log a CONFIG message.
     
* <p>
     
* If the logger is currently enabled for the CONFIG message
     
* level then the given message is forwarded to all the
     
* registered output Handler objects.
     
* <p>
     
* @param
   
msgThe string message (or a key in the message catalog)
     
*/

    
public void config(String msg) {
        
log(Level.CONFIG, msg);
    
}

    
/**
     
* Log a FINE message.
     
* <p>
     
* If the logger is currently enabled for the FINE message
     
* level then the given message is forwarded to all the
     
* registered output Handler objects.
     
* <p>
     
* @param
   
msgThe string message (or a key in the message catalog)
     
*/

    
public void fine(String msg) {
        
log(Level.FINE, msg);
    
}

    
/**
     
* Log a FINER message.
     
* <p>
     
* If the logger is currently enabled for the FINER message
     
* level then the given message is forwarded to all the
     
* registered output Handler objects.
     
* <p>
     
* @param
   
msgThe string message (or a key in the message catalog)
     
*/

    
public void finer(String msg) {
        
log(Level.FINER, msg);
    
}

    
/**
     
* Log a FINEST message.
     
* <p>
     
* If the logger is currently enabled for the FINEST message
     
* level then the given message is forwarded to all the
     
* registered output Handler objects.
     
* <p>
     
* @param
   
msgThe string message (or a key in the message catalog)
     
*/

    
public void finest(String msg) {
        
log(Level.FINEST, msg);
    
}

    
//=======================================================================
    
// Start of simple convenience methods using level names as method names
    
// and use Supplier<String>
    
//=======================================================================

    
/**
     
* Log a SEVERE message, which is only to be constructed if the logging
     
* level is such that the message will actually be logged.
     
* <p>
     
* If the logger is currently enabled for the SEVERE message
     
* level then the message is constructed by invoking the provided
     
* supplier function and forwarded to all the registered output
     
* Handler objects.
     
* <p>
     
* @param
   
msgSupplierA function, which when called, produces the
     
*
                        
desired log message
     
* @since
   
1.8
     
*/

    
public void severe(Supplier<String> msgSupplier) {
        
log(Level.SEVERE, msgSupplier);
    
}

    
/**
     
* Log a WARNING message, which is only to be constructed if the logging
     
* level is such that the message will actually be logged.
     
* <p>
     
* If the logger is currently enabled for the WARNING message
     
* level then the message is constructed by invoking the provided
     
* supplier function and forwarded to all the registered output
     
* Handler objects.
     
* <p>
     
* @param
   
msgSupplierA function, which when called, produces the
     
*
                        
desired log message
     
* @since
   
1.8
     
*/

    
public void warning(Supplier<String> msgSupplier) {
        
log(Level.WARNING, msgSupplier);
    
}

    
/**
     
* Log a INFO message, which is only to be constructed if the logging
     
* level is such that the message will actually be logged.
     
* <p>
     
* If the logger is currently enabled for the INFO message
     
* level then the message is constructed by invoking the provided
     
* supplier function and forwarded to all the registered output
     
* Handler objects.
     
* <p>
     
* @param
   
msgSupplierA function, which when called, produces the
     
*
                        
desired log message
     
* @since
   
1.8
     
*/

    
public void info(Supplier<String> msgSupplier) {
        
log(Level.INFO, msgSupplier);
    
}

    
/**
     
* Log a CONFIG message, which is only to be constructed if the logging
     
* level is such that the message will actually be logged.
     
* <p>
     
* If the logger is currently enabled for the CONFIG message
     
* level then the message is constructed by invoking the provided
     
* supplier function and forwarded to all the registered output
     
* Handler objects.
     
* <p>
     
* @param
   
msgSupplierA function, which when called, produces the
     
*
                        
desired log message
     
* @since
   
1.8
     
*/

    
public void config(Supplier<String> msgSupplier) {
        
log(Level.CONFIG, msgSupplier);
    
}

    
/**
     
* Log a FINE message, which is only to be constructed if the logging
     
* level is such that the message will actually be logged.
     
* <p>
     
* If the logger is currently enabled for the FINE message
     
* level then the message is constructed by invoking the provided
     
* supplier function and forwarded to all the registered output
     
* Handler objects.
     
* <p>
     
* @param
   
msgSupplierA function, which when called, produces the
     
*
                        
desired log message
     
* @since
   
1.8
     
*/

    
public void fine(Supplier<String> msgSupplier) {
        
log(Level.FINE, msgSupplier);
    
}

    
/**
     
* Log a FINER message, which is only to be constructed if the logging
     
* level is such that the message will actually be logged.
     
* <p>
     
* If the logger is currently enabled for the FINER message
     
* level then the message is constructed by invoking the provided
     
* supplier function and forwarded to all the registered output
     
* Handler objects.
     
* <p>
     
* @param
   
msgSupplierA function, which when called, produces the
     
*
                        
desired log message
     
* @since
   
1.8
     
*/

    
public void finer(Supplier<String> msgSupplier) {
        
log(Level.FINER, msgSupplier);
    
}

    
/**
     
* Log a FINEST message, which is only to be constructed if the logging
     
* level is such that the message will actually be logged.
     
* <p>
     
* If the logger is currently enabled for the FINEST message
     
* level then the message is constructed by invoking the provided
     
* supplier function and forwarded to all the registered output
     
* Handler objects.
     
* <p>
     
* @param
   
msgSupplierA function, which when called, produces the
     
*
                        
desired log message
     
* @since
   
1.8
     
*/

    
public void finest(Supplier<String> msgSupplier) {
        
log(Level.FINEST, msgSupplier);
    
}

    
//================================================================
    
// End of convenience methods
    
//================================================================

    
/**
     
* Set the log level specifying which message levels will be
     
* logged by this logger.
  
Message levels lower than this
     
* value will be discarded.
  
The level value Level.OFF
     
* can be used to turn off logging.
     
* <p>
     
* If the new level is null, it means that this node should
     
* inherit its level from its nearest ancestor with a specific
     
* (non-null) level value.
     
*
     
* @param newLevel
   
the new value for the log level (may be null)
     
* @throws
  
SecurityException if a security manager exists,
     
*
          
this logger is not anonymous, and the caller
     
*
          
does not have LoggingPermission("control").
     
*/

    
public void setLevel(Level newLevel) throws SecurityException {
        
checkPermission();
        
synchronized (treeLock) {
            
levelObject = newLevel;
            
updateEffectiveLevel();
        
}
    
}

    
final boolean isLevelInitialized() {
        
return levelObject != null;
    
}

    
/**
     
* Get the log Level that has been specified for this Logger.
     
* The result may be null, which means that this logger's
     
* effective level will be inherited from its parent.
     
*
     
* @return
  
this Logger's level
     
*/

    
public Level getLevel() {
        
return levelObject;
    
}

    
/**
     
* Check if a message of the given level would actually be logged
     
* by this logger.
  
This check is based on the Loggers effective level,
     
* which may be inherited from its parent.
     
*
     
* @param
   
levela message logging level
     
* @return
  
true if the given message level is currently being logged.
     
*/

    
public boolean isLoggable(Level level) {
        
if (level.intValue() < levelValue || levelValue == offValue) {
            
return false;
        
}
        
return true;
    
}

    
/**
     
* Get the name for this logger.
     
* @return logger name.
  
Will be null for anonymous Loggers.
     
*/

    
public String getName() {
        
return name;
    
}

    
/**
     
* Add a log Handler to receive logging messages.
     
* <p>
     
* By default, Loggers also send their output to their parent logger.
     
* Typically the root Logger is configured with a set of Handlers
     
* that essentially act as default handlers for all loggers.
     
*
     
* @param
   
handler a logging Handler
     
* @throws
  
SecurityException if a security manager exists,
     
*
          
this logger is not anonymous, and the caller
     
*
          
does not have LoggingPermission("control").
     
*/

    
public void addHandler(Handler handler) throws SecurityException {
        
// Check for null handler
        
handler.getClass();
        
checkPermission();
        
handlers.add(handler);
    
}

    
/**
     
* Remove a log Handler.
     
* <P>
     
* Returns silently if the given Handler is not found or is null
     
*
     
* @param
   
handler a logging Handler
     
* @throws
  
SecurityException if a security manager exists,
     
*
          
this logger is not anonymous, and the caller
     
*
          
does not have LoggingPermission("control").
     
*/

    
public void removeHandler(Handler handler) throws SecurityException {
        
checkPermission();
        
if (handler == null) {
            
return;
        
}
        
handlers.remove(handler);
    
}

    
/**
     
* Get the Handlers associated with this logger.
     
* <p>
     
* @return
  
an array of all registered Handlers
     
*/

    
public Handler[] getHandlers() {
        
return accessCheckedHandlers();
    
}

    
// This method should ideally be marked final - but unfortunately
    
// it needs to be overridden by LogManager.RootLogger
    
Handler[] accessCheckedHandlers() {
        
return handlers.toArray(emptyHandlers);
    
}

    
/**
     
* Specify whether or not this logger should send its output
     
* to its parent Logger.
  
This means that any LogRecords will
     
* also be written to the parent's Handlers, and potentially
     
* to its parent, recursively up the namespace.
     
*
     
* @param useParentHandlers
   
true if output is to be sent to the
     
*
          
logger's parent.
     
* @throws
  
SecurityException if a security manager exists,
     
*
          
this logger is not anonymous, and the caller
     
*
          
does not have LoggingPermission("control").
     
*/

    
public void setUseParentHandlers(boolean useParentHandlers) {
        
checkPermission();
        
this.useParentHandlers = useParentHandlers;
    
}

    
/**
     
* Discover whether or not this logger is sending its output
     
* to its parent logger.
     
*
     
* @return
  
true if output is to be sent to the logger's parent
     
*/

    
public boolean getUseParentHandlers() {
        
return useParentHandlers;
    
}

    
private static ResourceBundle findSystemResourceBundle(final Locale locale) {
        
// the resource bundle is in a restricted package
        
return AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() {
            
@Override
            
public ResourceBundle run() {
                
try {
                    
return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME,
                                                    
locale);
                
} catch (MissingResourceException e) {
                    
throw new InternalError(e.toString());
                
}
            
}
        
});
    
}

    
/**
     
* Private utility method to map a resource bundle name to an
     
* actual resource bundle, using a simple one-entry cache.
     
* Returns null for a null name.
     
* May also return null if we can't find the resource bundle and
     
* there is no suitable previous cached value.
     
*
     
* @param name the ResourceBundle to locate
     
* @param userCallersClassLoader if true search using the caller's ClassLoader
     
* @return ResourceBundle specified by name or null if not found
     
*/

    
private synchronized ResourceBundle findResourceBundle(String name,
                                                           
boolean useCallersClassLoader) {
        
// For all lookups, we first check the thread context class loader
        
// if it is set.
  
If not, we use the system classloader.If we
        
// still haven't found it we use the callersClassLoaderRef if it
        
// is set and useCallersClassLoader is true.
  
We set
        
// callersClassLoaderRef initially upon creating the logger with a
        
// non-null resource bundle name.

        
// Return a null bundle for a null name.
        
if (name == null) {
            
return null;
        
}

        
Locale currentLocale = Locale.getDefault();
        
final LoggerBundle lb = loggerBundle;

        
// Normally we should hit on our simple one entry cache.
        
if (lb.userBundle != null &&
                
name.equals(lb.resourceBundleName)) {
            
return lb.userBundle;
        
} else if (catalog != null && currentLocale.equals(catalogLocale)
                
&& name.equals(catalogName)) {
            
return catalog;
        
}

        
if (name.equals(SYSTEM_LOGGER_RB_NAME)) {
            
catalog = findSystemResourceBundle(currentLocale);
            
catalogName = name;
            
catalogLocale = currentLocale;
            
return catalog;
        
}

        
// Use the thread's context ClassLoader.
  
If there isn't one, use the

        
// {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader}.
        
ClassLoader cl = Thread.currentThread().getContextClassLoader();
        
if (cl == null) {
            
cl = ClassLoader.getSystemClassLoader();
        
}
        
try {
            
catalog = ResourceBundle.getBundle(name, currentLocale, cl);
            
catalogName = name;
            
catalogLocale = currentLocale;
            
return catalog;
        
} catch (MissingResourceException ex) {
            
// We can't find the ResourceBundle in the default
            
// ClassLoader.
  
Drop through.
        
}

        
if (useCallersClassLoader) {
            
// Try with the caller's ClassLoader
            
ClassLoader callersClassLoader = getCallersClassLoader();

            
if (callersClassLoader == null || callersClassLoader == cl) {
                
return null;
            
}

            
try {
                
catalog = ResourceBundle.getBundle(name, currentLocale,
                                                   
callersClassLoader);
                
catalogName = name;
                
catalogLocale = currentLocale;
                
return catalog;
            
} catch (MissingResourceException ex) {
                
return null; // no luck
            
}
        
} else {
            
return null;
        
}
    
}

    
// Private utility method to initialize our one entry
    
// resource bundle name cache and the callers ClassLoader
    
// Note: for consistency reasons, we are careful to check
    
// that a suitable ResourceBundle exists before setting the
    
// resourceBundleName field.
    
// Synchronized to prevent races in setting the fields.
    
private synchronized void setupResourceInfo(String name,
                                                
Class<?> callersClass) {
        
final LoggerBundle lb = loggerBundle;
        
if (lb.resourceBundleName != null) {
            
// this Logger already has a ResourceBundle

            
if (lb.resourceBundleName.equals(name)) {
                
// the names match so there is nothing more to do
                
return;
            
}

            
// cannot change ResourceBundles once they are set
            
throw new IllegalArgumentException(
                
lb.resourceBundleName + " != " + name);
        
}

        
if (name == null) {
            
return;
        
}

        
setCallersClassLoaderRef(callersClass);
        
if (isSystemLogger && getCallersClassLoader() != null) {
            
checkPermission();
        
}
        
if (findResourceBundle(name, true) == null) {
            
// We've failed to find an expected ResourceBundle.
            
// unset the caller's ClassLoader since we were unable to find the
            
// the bundle using it
            
this.callersClassLoaderRef = null;
            
throw new MissingResourceException("Can't find " + name + " bundle",
                                                
name, "");
        
}

        
// if lb.userBundle is not null we won't reach this line.
        
assert lb.userBundle == null;
        
loggerBundle = LoggerBundle.get(name, null);
    
}

    
/**
     
* Sets a resource bundle on this logger.
     
* All messages will be logged using the given resource bundle for its
     
* specific {@linkplain ResourceBundle#getLocale locale}.
     
* @param bundle The resource bundle that this logger shall use.
     
* @throws NullPointerException if the given bundle is {@code null}.
     
* @throws IllegalArgumentException if the given bundle doesn't have a
     
*
         
{@linkplain ResourceBundle#getBaseBundleName base name},
     
*
         
or if this logger already has a resource bundle set but
     
*
         
the given bundle has a different base name.
     
* @throws SecurityException if a security manager exists,
     
*
         
this logger is not anonymous, and the caller
     
*
         
does not have LoggingPermission("control").
     
* @since 1.8
     
*/

    
public void setResourceBundle(ResourceBundle bundle) {
        
checkPermission();

        
// Will throw NPE if bundle is null.
        
final String baseName = bundle.getBaseBundleName();

        
// bundle must have a name
        
if (baseName == null || baseName.isEmpty()) {
            
throw new IllegalArgumentException("resource bundle must have a name");
        
}

        
synchronized (this) {
            
LoggerBundle lb = loggerBundle;
            
final boolean canReplaceResourceBundle = lb.resourceBundleName == null
                    
|| lb.resourceBundleName.equals(baseName);

            
if (!canReplaceResourceBundle) {
                
throw new IllegalArgumentException("can't replace resource bundle");
            
}


            
loggerBundle = LoggerBundle.get(baseName, bundle);
        
}
    
}

    
/**
     
* Return the parent for this Logger.
     
* <p>
     
* This method returns the nearest extant parent in the namespace.
     
* Thus if a Logger is called "a.b.c.d", and a Logger called "a.b"
     
* has been created but no logger "a.b.c" exists, then a call of
     
* getParent on the Logger "a.b.c.d" will return the Logger "a.b".
     
* <p>
     
* The result will be null if it is called on the root Logger
     
* in the namespace.
     
*
     
* @return nearest existing parent Logger
     
*/

    
public Logger getParent() {
        
// Note: this used to be synchronized on treeLock.
  
However, this only
        
// provided memory semantics, as there was no guarantee that the caller
        
// would synchronize on treeLock (in fact, there is no way for external
        
// callers to so synchronize).
  
Therefore, we have made parent volatile

        
// instead.
        
return parent;
    
}

    
/**
     
* Set the parent for this Logger.
  
This method is used by
     
* the LogManager to update a Logger when the namespace changes.
     
* <p>
     
* It should not be called from application code.
     
* <p>
     
* @param
  
parent
   
the new parent logger
     
* @throws
  
SecurityExceptionif a security manager exists and if
     
*
          
the caller does not have LoggingPermission("control").
     
*/

    
public void setParent(Logger parent) {
        
if (parent == null) {
            
throw new NullPointerException();
        
}

        
// check permission for all loggers, including anonymous loggers
        
if (manager == null) {
            
manager = LogManager.getLogManager();
        
}
        
manager.checkPermission();

        
doSetParent(parent);
    
}

    
// Private method to do the work for parenting a child
    
// Logger onto a parent logger.
    
private void doSetParent(Logger newParent) {

        
// System.err.println("doSetParent \"" + getName() + "\" \""
        
//
                              
+ newParent.getName() + "\"");

        
synchronized (treeLock) {

            
// Remove ourself from any previous parent.
            
LogManager.LoggerWeakRef ref = null;
            
if (parent != null) {
                
// assert parent.kids != null;
                
for (Iterator<LogManager.LoggerWeakRef> iter = parent.kids.iterator(); iter.hasNext(); ) {
                    
ref = iter.next();
                    
Logger kid =
  
ref.get();
                    
if (kid == this) {
                        
// ref is used down below to complete the reparenting
                        
iter.remove();
                        
break;
                    
} else {
                        
ref = null;
                    
}
                
}
                
// We have now removed ourself from our parents' kids.
            
}

            
// Set our new parent.
            
parent = newParent;
            
if (parent.kids == null) {
                
parent.kids = new ArrayList<>(2);
            
}
            
if (ref == null) {
                
// we didn't have a previous parent
                
ref = manager.new LoggerWeakRef(this);
            
}
            
ref.setParentRef(new WeakReference<>(parent));
            
parent.kids.add(ref);

            
// As a result of the reparenting, the effective level
            
// may have changed for us and our children.
            
updateEffectiveLevel();

        
}
    
}

    
// Package-level method.
    
// Remove the weak reference for the specified child Logger from the
    
// kid list. We should only be called from LoggerWeakRef.dispose().
    
final void removeChildLogger(LogManager.LoggerWeakRef child) {
        
synchronized (treeLock) {
            
for (Iterator<LogManager.LoggerWeakRef> iter = kids.iterator(); iter.hasNext(); ) {
                
LogManager.LoggerWeakRef ref = iter.next();
                
if (ref == child) {
                    
iter.remove();
                    
return;
                
}
            
}
        
}
    
}

    
// Recalculate the effective level for this node and
    
// recursively for our children.

    
private void updateEffectiveLevel() {
        
// assert Thread.holdsLock(treeLock);

        
// Figure out our current effective level.
        
int newLevelValue;
        
if (levelObject != null) {
            
newLevelValue = levelObject.intValue();
        
} else {
            
if (parent != null) {
                
newLevelValue = parent.levelValue;
            
} else {
                
// This may happen during initialization.
                
newLevelValue = Level.INFO.intValue();
            
}
        
}

        
// If our effective value hasn't changed, we're done.
        
if (levelValue == newLevelValue) {
            
return;
        
}

        
levelValue = newLevelValue;

        
// System.err.println("effective level: \"" + getName() + "\" := " + level);

        
// Recursively update the level on each of our kids.
        
if (kids != null) {
            
for (int i = 0; i < kids.size(); i++) {
                
LogManager.LoggerWeakRef ref = kids.get(i);
                
Logger kid =
  
ref.get();
                
if (kid != null) {
                    
kid.updateEffectiveLevel();
                
}
            
}
        
}
    
}


    
// Private method to get the potentially inherited
    
// resource bundle and resource bundle name for this Logger.
    
// This method never returns null.
    
private LoggerBundle getEffectiveLoggerBundle() {
        
final LoggerBundle lb = loggerBundle;
        
if (lb.isSystemBundle()) {
            
return SYSTEM_BUNDLE;
        
}

        
// first take care of this logger
        
final ResourceBundle b = getResourceBundle();
        
if (b != null && b == lb.userBundle) {
            
return lb;
        
} else if (b != null) {
            
// either lb.userBundle is null or getResourceBundle() is
            
// overriden
            
final String rbName = getResourceBundleName();
            
return LoggerBundle.get(rbName, b);
        
}

        
// no resource bundle was specified on this logger, look up the
        
// parent stack.
        
Logger target = this.parent;
        
while (target != null) {
            
final LoggerBundle trb = target.loggerBundle;
            
if (trb.isSystemBundle()) {
                
return SYSTEM_BUNDLE;
            
}
            
if (trb.userBundle != null) {
                
return trb;
            
}
            
final String rbName = isSystemLogger
                
// ancestor of a system logger is expected to be a system logger.
                
// ignore resource bundle name if it's not.
                
? (target.isSystemLogger ? trb.resourceBundleName : null)
                
: target.getResourceBundleName();
            
if (rbName != null) {
                
return LoggerBundle.get(rbName,
                        
findResourceBundle(rbName, true));
            
}
            
target = isSystemLogger ? target.parent : target.getParent();
        
}
        
return NO_RESOURCE_BUNDLE;
    
}

}