src/share/classes/java/util/logging/Logger.java

Print this page




 201  * to reliably locate the calling class and method.
 202  * <P>
 203  * All methods on Logger are multi-thread safe.
 204  * <p>
 205  * <b>Subclassing Information:</b> Note that a LogManager class may
 206  * provide its own implementation of named Loggers for any point in
 207  * the namespace.  Therefore, any subclasses of Logger (unless they
 208  * are implemented in conjunction with a new LogManager class) should
 209  * take care to obtain a Logger instance from the LogManager class and
 210  * should delegate operations such as "isLoggable" and "log(LogRecord)"
 211  * to that instance.  Note that in order to intercept all logging
 212  * output, subclasses need only override the log(LogRecord) method.
 213  * All the other logging methods are implemented as calls on this
 214  * log(LogRecord) method.
 215  *
 216  * @since 1.4
 217  */
 218 public class Logger {
 219     private static final Handler emptyHandlers[] = new Handler[0];
 220     private static final int offValue = Level.OFF.intValue();
 221     private LogManager manager;



































 222     private String name;
 223     private final CopyOnWriteArrayList<Handler> handlers =
 224         new CopyOnWriteArrayList<>();
 225     private String resourceBundleName;  // Base name of the bundle.
 226     private ResourceBundle userBundle;  // Bundle set through setResourceBundle.
 227     private volatile boolean useParentHandlers = true;
 228     private volatile Filter filter;
 229     private boolean anonymous;
 230 
 231     // Cache to speed up behavior of findResourceBundle:
 232     private ResourceBundle catalog;     // Cached resource bundle
 233     private String catalogName;         // name associated with catalog
 234     private Locale catalogLocale;       // locale associated with catalog
 235 
 236     // The fields relating to parent-child relationships and levels
 237     // are managed under a separate lock, the treeLock.
 238     private static final Object treeLock = new Object();
 239     // We keep weak references from parents to children, but strong
 240     // references from children to parents.
 241     private volatile Logger parent;    // our nearest parent.
 242     private ArrayList<LogManager.LoggerWeakRef> kids;   // WeakReferences to loggers that have us as parent
 243     private volatile Level levelObject;
 244     private volatile int levelValue;  // current effective level value
 245     private WeakReference<ClassLoader> callersClassLoaderRef;
 246 


 324      * The logger will be initially configured with a null Level
 325      * and with useParentHandlers set to true.
 326      *
 327      * @param   name    A name for the logger.  This should
 328      *                          be a dot-separated name and should normally
 329      *                          be based on the package name or class name
 330      *                          of the subsystem, such as java.net
 331      *                          or javax.swing.  It may be null for anonymous Loggers.
 332      * @param   resourceBundleName  name of ResourceBundle to be used for localizing
 333      *                          messages for this logger.  May be null if none
 334      *                          of the messages require localization.
 335      * @throws MissingResourceException if the resourceBundleName is non-null and
 336      *             no corresponding resource can be found.
 337      */
 338     protected Logger(String name, String resourceBundleName) {
 339         this(name, resourceBundleName, null, LogManager.getLogManager());
 340     }
 341 
 342     Logger(String name, String resourceBundleName, Class<?> caller, LogManager manager) {
 343         this.manager = manager;

 344         setupResourceInfo(resourceBundleName, caller);
 345         this.name = name;
 346         levelValue = Level.INFO.intValue();
 347     }
 348 
 349     private void setCallersClassLoaderRef(Class<?> caller) {
 350         ClassLoader callersClassLoader = ((caller != null)
 351                                          ? caller.getClassLoader()
 352                                          : null);
 353         if (callersClassLoader != null) {
 354             this.callersClassLoaderRef = new WeakReference<>(callersClassLoader);
 355         }
 356     }
 357 
 358     private ClassLoader getCallersClassLoader() {
 359         return (callersClassLoaderRef != null)
 360                 ? callersClassLoaderRef.get()
 361                 : null;
 362     }
 363 
 364     // This constructor is used only to create the global Logger.
 365     // It is needed to break a cyclic dependence between the LogManager
 366     // and Logger static initializers causing deadlocks.
 367     private Logger(String name) {
 368         // The manager field is not initialized here.

 369         this.name = name;
 370         levelValue = Level.INFO.intValue();
 371     }
 372 
 373     // It is called from LoggerContext.addLocalLogger() when the logger
 374     // is actually added to a LogManager.
 375     void setLogManager(LogManager manager) {
 376         this.manager = manager;
 377     }
 378 
 379     private void checkPermission() throws SecurityException {
 380         if (!anonymous) {
 381             if (manager == null) {
 382                 // Complete initialization of the global Logger.
 383                 manager = LogManager.getLogManager();
 384             }
 385             manager.checkPermission();
 386         }
 387     }
 388 


 624      * @return localization bundle (may be {@code null})
 625      */
 626     public ResourceBundle getResourceBundle() {
 627         return findResourceBundle(getResourceBundleName(), true);
 628     }
 629 
 630     /**
 631      * Retrieve the localization resource bundle name for this
 632      * logger.
 633      * This is either the name specified through the {@link
 634      * #getLogger(java.lang.String, java.lang.String) getLogger} factory method,
 635      * or the {@linkplain ResourceBundle#getBaseBundleName() base name} of the
 636      * ResourceBundle set through {@link
 637      * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method.
 638      * <br>Note that if the result is {@code null}, then the Logger will use a resource
 639      * bundle or resource bundle name inherited from its parent.
 640      *
 641      * @return localization bundle name (may be {@code null})
 642      */
 643     public String getResourceBundleName() {
 644         return resourceBundleName;
 645     }
 646 
 647     /**
 648      * Set a filter to control output on this Logger.
 649      * <P>
 650      * After passing the initial "level" check, the Logger will
 651      * call this Filter to check if a log record should really
 652      * be published.
 653      *
 654      * @param   newFilter  a filter object (may be null)
 655      * @throws  SecurityException if a security manager exists,
 656      *          this logger is not anonymous, and the caller
 657      *          does not have LoggingPermission("control").
 658      */
 659     public void setFilter(Filter newFilter) throws SecurityException {
 660         checkPermission();
 661         filter = newFilter;
 662     }
 663 
 664     /**


 693 
 694         Logger logger = this;
 695         while (logger != null) {
 696             for (Handler handler : logger.getHandlers()) {
 697                 handler.publish(record);
 698             }
 699 
 700             if (!logger.getUseParentHandlers()) {
 701                 break;
 702             }
 703 
 704             logger = logger.getParent();
 705         }
 706     }
 707 
 708     // private support method for logging.
 709     // We fill in the logger name, resource bundle name, and
 710     // resource bundle and then call "void log(LogRecord)".
 711     private void doLog(LogRecord lr) {
 712         lr.setLoggerName(name);
 713         final ResourceBundle bundle = getEffectiveResourceBundle();
 714         final String ebname = getEffectiveResourceBundleName();

 715         if (ebname != null && bundle != null) {
 716             lr.setResourceBundleName(ebname);
 717             lr.setResourceBundle(bundle);
 718         }
 719         log(lr);
 720     }
 721 
 722 
 723     //================================================================
 724     // Start of convenience methods WITHOUT className and methodName
 725     //================================================================
 726 
 727     /**
 728      * Log a message, with no arguments.
 729      * <p>
 730      * If the logger is currently enabled for the given message
 731      * level then the given message is forwarded to all the
 732      * registered output Handler objects.
 733      * <p>
 734      * @param   level   One of the message level identifiers, e.g., SEVERE


1740      *          logger's parent.
1741      * @throws  SecurityException if a security manager exists,
1742      *          this logger is not anonymous, and the caller
1743      *          does not have LoggingPermission("control").
1744      */
1745     public void setUseParentHandlers(boolean useParentHandlers) {
1746         checkPermission();
1747         this.useParentHandlers = useParentHandlers;
1748     }
1749 
1750     /**
1751      * Discover whether or not this logger is sending its output
1752      * to its parent logger.
1753      *
1754      * @return  true if output is to be sent to the logger's parent
1755      */
1756     public boolean getUseParentHandlers() {
1757         return useParentHandlers;
1758     }
1759 
1760     static final String SYSTEM_LOGGER_RB_NAME = "sun.util.logging.resources.logging";
1761 
1762     private static ResourceBundle findSystemResourceBundle(final Locale locale) {
1763         // the resource bundle is in a restricted package
1764         return AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() {
1765             @Override
1766             public ResourceBundle run() {
1767                 try {
1768                     return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME,
1769                                                     locale,
1770                                                     ClassLoader.getSystemClassLoader());
1771                 } catch (MissingResourceException e) {
1772                     throw new InternalError(e.toString());
1773                 }
1774             }
1775         });
1776     }
1777 
1778     /**
1779      * Private utility method to map a resource bundle name to an
1780      * actual resource bundle, using a simple one-entry cache.
1781      * Returns null for a null name.


1784      *
1785      * @param name the ResourceBundle to locate
1786      * @param userCallersClassLoader if true search using the caller's ClassLoader
1787      * @return ResourceBundle specified by name or null if not found
1788      */
1789     private synchronized ResourceBundle findResourceBundle(String name,
1790                                                            boolean useCallersClassLoader) {
1791         // For all lookups, we first check the thread context class loader
1792         // if it is set.  If not, we use the system classloader.  If we
1793         // still haven't found it we use the callersClassLoaderRef if it
1794         // is set and useCallersClassLoader is true.  We set
1795         // callersClassLoaderRef initially upon creating the logger with a
1796         // non-null resource bundle name.
1797 
1798         // Return a null bundle for a null name.
1799         if (name == null) {
1800             return null;
1801         }
1802 
1803         Locale currentLocale = Locale.getDefault();

1804 
1805         // Normally we should hit on our simple one entry cache.
1806         if (userBundle != null &&
1807                 name.equals(resourceBundleName)) {
1808             return userBundle;
1809         } else if (catalog != null && currentLocale.equals(catalogLocale)
1810                 && name.equals(catalogName)) {
1811             return catalog;
1812         }
1813 
1814         if (name.equals(SYSTEM_LOGGER_RB_NAME)) {
1815             catalog = findSystemResourceBundle(currentLocale);
1816             catalogName = name;
1817             catalogLocale = currentLocale;
1818             return catalog;
1819         }
1820 
1821         // Use the thread's context ClassLoader.  If there isn't one, use the
1822         // {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader}.
1823         ClassLoader cl = Thread.currentThread().getContextClassLoader();
1824         if (cl == null) {
1825             cl = ClassLoader.getSystemClassLoader();
1826         }
1827         try {
1828             catalog = ResourceBundle.getBundle(name, currentLocale, cl);


1847                                                    callersClassLoader);
1848                 catalogName = name;
1849                 catalogLocale = currentLocale;
1850                 return catalog;
1851             } catch (MissingResourceException ex) {
1852                 return null; // no luck
1853             }
1854         } else {
1855             return null;
1856         }
1857     }
1858 
1859     // Private utility method to initialize our one entry
1860     // resource bundle name cache and the callers ClassLoader
1861     // Note: for consistency reasons, we are careful to check
1862     // that a suitable ResourceBundle exists before setting the
1863     // resourceBundleName field.
1864     // Synchronized to prevent races in setting the fields.
1865     private synchronized void setupResourceInfo(String name,
1866                                                 Class<?> callersClass) {
1867         if (resourceBundleName != null) {

1868             // this Logger already has a ResourceBundle
1869 
1870             if (resourceBundleName.equals(name)) {
1871                 // the names match so there is nothing more to do
1872                 return;
1873             }
1874 
1875             // cannot change ResourceBundles once they are set
1876             throw new IllegalArgumentException(
1877                 resourceBundleName + " != " + name);
1878         }
1879 
1880         if (name == null) {
1881             return;
1882         }
1883 
1884         setCallersClassLoaderRef(callersClass);
1885         if (findResourceBundle(name, true) == null) {
1886             // We've failed to find an expected ResourceBundle.
1887             // unset the caller's ClassLoader since we were unable to find the
1888             // the bundle using it
1889             this.callersClassLoaderRef = null;
1890             throw new MissingResourceException("Can't find " + name + " bundle",
1891                                                 name, "");
1892         }
1893         resourceBundleName = name;
1894     }
1895 
1896     /**
1897      * Sets a resource bundle on this logger.
1898      * All messages will be logged using the given resource bundle for its
1899      * specific {@linkplain ResourceBundle#getLocale locale}.
1900      * @param bundle The resource bundle that this logger shall use.
1901      * @throws NullPointerException if the given bundle is {@code null}.
1902      * @throws IllegalArgumentException if the given bundle doesn't have a
1903      *         {@linkplain ResourceBundle#getBaseBundleName base name},
1904      *         or if this logger already has a resource bundle set but
1905      *         the given bundle has a different base name.
1906      * @throws SecurityException if a security manager exists,
1907      *         this logger is not anonymous, and the caller
1908      *         does not have LoggingPermission("control").
1909      * @since 1.8
1910      */
1911     public void setResourceBundle(ResourceBundle bundle) {
1912         checkPermission();
1913 
1914         // Will throw NPE if bundle is null.
1915         final String baseName = bundle.getBaseBundleName();
1916 
1917         // bundle must have a name
1918         if (baseName == null || baseName.isEmpty()) {
1919             throw new IllegalArgumentException("resource bundle must have a name");
1920         }
1921 
1922         synchronized (this) {
1923             final boolean canReplaceResourceBundle = resourceBundleName == null
1924                     || resourceBundleName.equals(baseName);

1925 
1926             if (!canReplaceResourceBundle) {
1927                 throw new IllegalArgumentException("can't replace resource bundle");
1928             }
1929 
1930 
1931             userBundle = bundle;
1932             resourceBundleName = baseName;
1933         }
1934     }
1935 
1936     /**
1937      * Return the parent for this Logger.
1938      * <p>
1939      * This method returns the nearest extant parent in the namespace.
1940      * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b"
1941      * has been created but no logger "a.b.c" exists, then a call of
1942      * getParent on the Logger "a.b.c.d" will return the Logger "a.b".
1943      * <p>
1944      * The result will be null if it is called on the root Logger
1945      * in the namespace.
1946      *
1947      * @return nearest existing parent Logger
1948      */
1949     public Logger getParent() {
1950         // Note: this used to be synchronized on treeLock.  However, this only
1951         // provided memory semantics, as there was no guarantee that the caller
1952         // would synchronize on treeLock (in fact, there is no way for external


2065         }
2066 
2067         levelValue = newLevelValue;
2068 
2069         // System.err.println("effective level: \"" + getName() + "\" := " + level);
2070 
2071         // Recursively update the level on each of our kids.
2072         if (kids != null) {
2073             for (int i = 0; i < kids.size(); i++) {
2074                 LogManager.LoggerWeakRef ref = kids.get(i);
2075                 Logger kid =  ref.get();
2076                 if (kid != null) {
2077                     kid.updateEffectiveLevel();
2078                 }
2079             }
2080         }
2081     }
2082 
2083 
2084     // Private method to get the potentially inherited
2085     // resource bundle name for this Logger.
2086     // May return null
2087     private String getEffectiveResourceBundleName() {
2088         Logger target = this;
2089         while (target != null) {
2090             String rbn = target.getResourceBundleName();
2091             if (rbn != null) {
2092                 return rbn;
2093             }
2094             target = target.getParent();
2095         }
2096         return null;









2097     }
2098 
2099 
2100     private ResourceBundle getEffectiveResourceBundle() {
2101         Logger target = this;
2102         if (SYSTEM_LOGGER_RB_NAME.equals(resourceBundleName)) return null;
2103         ResourceBundle localRB = getResourceBundle();
2104         if (localRB != null) {
2105             return localRB;
2106         }
2107 



2108         while (target != null) {
2109             final ResourceBundle rb = target.userBundle;
2110             if (rb != null) {
2111                 return rb;
2112             }
2113             final String rbn = target.getResourceBundleName();
2114             if (rbn != null) {
2115                 if (!SYSTEM_LOGGER_RB_NAME.equals(rbn)) {
2116                     return findResourceBundle(rbn, true);




2117                 } else {
2118                     return null;
2119                 }
2120             }
2121             target = target.getParent();
2122         }
2123         return null;
2124     }
2125 
2126 }


 201  * to reliably locate the calling class and method.
 202  * <P>
 203  * All methods on Logger are multi-thread safe.
 204  * <p>
 205  * <b>Subclassing Information:</b> Note that a LogManager class may
 206  * provide its own implementation of named Loggers for any point in
 207  * the namespace.  Therefore, any subclasses of Logger (unless they
 208  * are implemented in conjunction with a new LogManager class) should
 209  * take care to obtain a Logger instance from the LogManager class and
 210  * should delegate operations such as "isLoggable" and "log(LogRecord)"
 211  * to that instance.  Note that in order to intercept all logging
 212  * output, subclasses need only override the log(LogRecord) method.
 213  * All the other logging methods are implemented as calls on this
 214  * log(LogRecord) method.
 215  *
 216  * @since 1.4
 217  */
 218 public class Logger {
 219     private static final Handler emptyHandlers[] = new Handler[0];
 220     private static final int offValue = Level.OFF.intValue();
 221 
 222     static final String SYSTEM_LOGGER_RB_NAME = "sun.util.logging.resources.logging";
 223 
 224     // This class is immutable and it is important that it remains so.
 225     private static final class LoggerBundle {
 226         final String resourceBundleName; // Base name of the bundle.
 227         final ResourceBundle userBundle; // Bundle set through setResourceBundle.
 228         private LoggerBundle(String resourceBundleName, ResourceBundle bundle) {
 229             this.resourceBundleName = resourceBundleName;
 230             this.userBundle = bundle;
 231         }
 232         boolean isSystemBundle() {
 233             return SYSTEM_LOGGER_RB_NAME.equals(resourceBundleName);
 234         }
 235         static LoggerBundle get(String name, ResourceBundle bundle) {
 236             if (name == null && bundle == null) {
 237                 return NO_RESOURCE_BUNDLE;
 238             } else if (SYSTEM_LOGGER_RB_NAME.equals(name) && bundle == null) {
 239                 return SYSTEM_BUNDLE;
 240             } else {
 241                 return new LoggerBundle(name, bundle);
 242             }
 243         }
 244     }
 245 
 246     // This instance will be shared by all loggers created by the system
 247     // code
 248     private static final LoggerBundle SYSTEM_BUNDLE =
 249             new LoggerBundle(SYSTEM_LOGGER_RB_NAME, null);
 250 
 251     // This instance indicates that no resource bundle has been specified yet,
 252     // and it will be shared by all loggers which have no resource bundle.
 253     private static final LoggerBundle NO_RESOURCE_BUNDLE =
 254             new LoggerBundle(null, null);
 255 
 256     private volatile LogManager manager;
 257     private String name;
 258     private final CopyOnWriteArrayList<Handler> handlers =
 259         new CopyOnWriteArrayList<>();
 260     private volatile LoggerBundle loggerBundle = NO_RESOURCE_BUNDLE;

 261     private volatile boolean useParentHandlers = true;
 262     private volatile Filter filter;
 263     private boolean anonymous;
 264 
 265     // Cache to speed up behavior of findResourceBundle:
 266     private ResourceBundle catalog;     // Cached resource bundle
 267     private String catalogName;         // name associated with catalog
 268     private Locale catalogLocale;       // locale associated with catalog
 269 
 270     // The fields relating to parent-child relationships and levels
 271     // are managed under a separate lock, the treeLock.
 272     private static final Object treeLock = new Object();
 273     // We keep weak references from parents to children, but strong
 274     // references from children to parents.
 275     private volatile Logger parent;    // our nearest parent.
 276     private ArrayList<LogManager.LoggerWeakRef> kids;   // WeakReferences to loggers that have us as parent
 277     private volatile Level levelObject;
 278     private volatile int levelValue;  // current effective level value
 279     private WeakReference<ClassLoader> callersClassLoaderRef;
 280 


 358      * The logger will be initially configured with a null Level
 359      * and with useParentHandlers set to true.
 360      *
 361      * @param   name    A name for the logger.  This should
 362      *                          be a dot-separated name and should normally
 363      *                          be based on the package name or class name
 364      *                          of the subsystem, such as java.net
 365      *                          or javax.swing.  It may be null for anonymous Loggers.
 366      * @param   resourceBundleName  name of ResourceBundle to be used for localizing
 367      *                          messages for this logger.  May be null if none
 368      *                          of the messages require localization.
 369      * @throws MissingResourceException if the resourceBundleName is non-null and
 370      *             no corresponding resource can be found.
 371      */
 372     protected Logger(String name, String resourceBundleName) {
 373         this(name, resourceBundleName, null, LogManager.getLogManager());
 374     }
 375 
 376     Logger(String name, String resourceBundleName, Class<?> caller, LogManager manager) {
 377         this.manager = manager;
 378         assert this.loggerBundle == NO_RESOURCE_BUNDLE;
 379         setupResourceInfo(resourceBundleName, caller);
 380         this.name = name;
 381         levelValue = Level.INFO.intValue();
 382     }
 383 
 384     private void setCallersClassLoaderRef(Class<?> caller) {
 385         ClassLoader callersClassLoader = ((caller != null)
 386                                          ? caller.getClassLoader()
 387                                          : null);
 388         if (callersClassLoader != null) {
 389             this.callersClassLoaderRef = new WeakReference<>(callersClassLoader);
 390         }
 391     }
 392 
 393     private ClassLoader getCallersClassLoader() {
 394         return (callersClassLoaderRef != null)
 395                 ? callersClassLoaderRef.get()
 396                 : null;
 397     }
 398 
 399     // This constructor is used only to create the global Logger.
 400     // It is needed to break a cyclic dependence between the LogManager
 401     // and Logger static initializers causing deadlocks.
 402     private Logger(String name) {
 403         // The manager field is not initialized here.
 404         assert this.loggerBundle == NO_RESOURCE_BUNDLE;
 405         this.name = name;
 406         levelValue = Level.INFO.intValue();
 407     }
 408 
 409     // It is called from LoggerContext.addLocalLogger() when the logger
 410     // is actually added to a LogManager.
 411     void setLogManager(LogManager manager) {
 412         this.manager = manager;
 413     }
 414 
 415     private void checkPermission() throws SecurityException {
 416         if (!anonymous) {
 417             if (manager == null) {
 418                 // Complete initialization of the global Logger.
 419                 manager = LogManager.getLogManager();
 420             }
 421             manager.checkPermission();
 422         }
 423     }
 424 


 660      * @return localization bundle (may be {@code null})
 661      */
 662     public ResourceBundle getResourceBundle() {
 663         return findResourceBundle(getResourceBundleName(), true);
 664     }
 665 
 666     /**
 667      * Retrieve the localization resource bundle name for this
 668      * logger.
 669      * This is either the name specified through the {@link
 670      * #getLogger(java.lang.String, java.lang.String) getLogger} factory method,
 671      * or the {@linkplain ResourceBundle#getBaseBundleName() base name} of the
 672      * ResourceBundle set through {@link
 673      * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method.
 674      * <br>Note that if the result is {@code null}, then the Logger will use a resource
 675      * bundle or resource bundle name inherited from its parent.
 676      *
 677      * @return localization bundle name (may be {@code null})
 678      */
 679     public String getResourceBundleName() {
 680         return loggerBundle.resourceBundleName;
 681     }
 682 
 683     /**
 684      * Set a filter to control output on this Logger.
 685      * <P>
 686      * After passing the initial "level" check, the Logger will
 687      * call this Filter to check if a log record should really
 688      * be published.
 689      *
 690      * @param   newFilter  a filter object (may be null)
 691      * @throws  SecurityException if a security manager exists,
 692      *          this logger is not anonymous, and the caller
 693      *          does not have LoggingPermission("control").
 694      */
 695     public void setFilter(Filter newFilter) throws SecurityException {
 696         checkPermission();
 697         filter = newFilter;
 698     }
 699 
 700     /**


 729 
 730         Logger logger = this;
 731         while (logger != null) {
 732             for (Handler handler : logger.getHandlers()) {
 733                 handler.publish(record);
 734             }
 735 
 736             if (!logger.getUseParentHandlers()) {
 737                 break;
 738             }
 739 
 740             logger = logger.getParent();
 741         }
 742     }
 743 
 744     // private support method for logging.
 745     // We fill in the logger name, resource bundle name, and
 746     // resource bundle and then call "void log(LogRecord)".
 747     private void doLog(LogRecord lr) {
 748         lr.setLoggerName(name);
 749         final LoggerBundle lb = getEffectiveLoggerBundle();
 750         final ResourceBundle  bundle = lb.userBundle;
 751         final String ebname = lb.resourceBundleName;
 752         if (ebname != null && bundle != null) {
 753             lr.setResourceBundleName(ebname);
 754             lr.setResourceBundle(bundle);
 755         }
 756         log(lr);
 757     }
 758 
 759 
 760     //================================================================
 761     // Start of convenience methods WITHOUT className and methodName
 762     //================================================================
 763 
 764     /**
 765      * Log a message, with no arguments.
 766      * <p>
 767      * If the logger is currently enabled for the given message
 768      * level then the given message is forwarded to all the
 769      * registered output Handler objects.
 770      * <p>
 771      * @param   level   One of the message level identifiers, e.g., SEVERE


1777      *          logger's parent.
1778      * @throws  SecurityException if a security manager exists,
1779      *          this logger is not anonymous, and the caller
1780      *          does not have LoggingPermission("control").
1781      */
1782     public void setUseParentHandlers(boolean useParentHandlers) {
1783         checkPermission();
1784         this.useParentHandlers = useParentHandlers;
1785     }
1786 
1787     /**
1788      * Discover whether or not this logger is sending its output
1789      * to its parent logger.
1790      *
1791      * @return  true if output is to be sent to the logger's parent
1792      */
1793     public boolean getUseParentHandlers() {
1794         return useParentHandlers;
1795     }
1796 


1797     private static ResourceBundle findSystemResourceBundle(final Locale locale) {
1798         // the resource bundle is in a restricted package
1799         return AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() {
1800             @Override
1801             public ResourceBundle run() {
1802                 try {
1803                     return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME,
1804                                                     locale,
1805                                                     ClassLoader.getSystemClassLoader());
1806                 } catch (MissingResourceException e) {
1807                     throw new InternalError(e.toString());
1808                 }
1809             }
1810         });
1811     }
1812 
1813     /**
1814      * Private utility method to map a resource bundle name to an
1815      * actual resource bundle, using a simple one-entry cache.
1816      * Returns null for a null name.


1819      *
1820      * @param name the ResourceBundle to locate
1821      * @param userCallersClassLoader if true search using the caller's ClassLoader
1822      * @return ResourceBundle specified by name or null if not found
1823      */
1824     private synchronized ResourceBundle findResourceBundle(String name,
1825                                                            boolean useCallersClassLoader) {
1826         // For all lookups, we first check the thread context class loader
1827         // if it is set.  If not, we use the system classloader.  If we
1828         // still haven't found it we use the callersClassLoaderRef if it
1829         // is set and useCallersClassLoader is true.  We set
1830         // callersClassLoaderRef initially upon creating the logger with a
1831         // non-null resource bundle name.
1832 
1833         // Return a null bundle for a null name.
1834         if (name == null) {
1835             return null;
1836         }
1837 
1838         Locale currentLocale = Locale.getDefault();
1839         final LoggerBundle lb = loggerBundle;
1840 
1841         // Normally we should hit on our simple one entry cache.
1842         if (lb.userBundle != null &&
1843                 name.equals(lb.resourceBundleName)) {
1844             return lb.userBundle;
1845         } else if (catalog != null && currentLocale.equals(catalogLocale)
1846                 && name.equals(catalogName)) {
1847             return catalog;
1848         }
1849 
1850         if (name.equals(SYSTEM_LOGGER_RB_NAME)) {
1851             catalog = findSystemResourceBundle(currentLocale);
1852             catalogName = name;
1853             catalogLocale = currentLocale;
1854             return catalog;
1855         }
1856 
1857         // Use the thread's context ClassLoader.  If there isn't one, use the
1858         // {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader}.
1859         ClassLoader cl = Thread.currentThread().getContextClassLoader();
1860         if (cl == null) {
1861             cl = ClassLoader.getSystemClassLoader();
1862         }
1863         try {
1864             catalog = ResourceBundle.getBundle(name, currentLocale, cl);


1883                                                    callersClassLoader);
1884                 catalogName = name;
1885                 catalogLocale = currentLocale;
1886                 return catalog;
1887             } catch (MissingResourceException ex) {
1888                 return null; // no luck
1889             }
1890         } else {
1891             return null;
1892         }
1893     }
1894 
1895     // Private utility method to initialize our one entry
1896     // resource bundle name cache and the callers ClassLoader
1897     // Note: for consistency reasons, we are careful to check
1898     // that a suitable ResourceBundle exists before setting the
1899     // resourceBundleName field.
1900     // Synchronized to prevent races in setting the fields.
1901     private synchronized void setupResourceInfo(String name,
1902                                                 Class<?> callersClass) {
1903         final LoggerBundle lb = loggerBundle;
1904         if (lb.resourceBundleName != null) {
1905             // this Logger already has a ResourceBundle
1906 
1907             if (lb.resourceBundleName.equals(name)) {
1908                 // the names match so there is nothing more to do
1909                 return;
1910             }
1911 
1912             // cannot change ResourceBundles once they are set
1913             throw new IllegalArgumentException(
1914                 lb.resourceBundleName + " != " + name);
1915         }
1916 
1917         if (name == null) {
1918             return;
1919         }
1920 
1921         setCallersClassLoaderRef(callersClass);
1922         if (findResourceBundle(name, true) == null) {
1923             // We've failed to find an expected ResourceBundle.
1924             // unset the caller's ClassLoader since we were unable to find the
1925             // the bundle using it
1926             this.callersClassLoaderRef = null;
1927             throw new MissingResourceException("Can't find " + name + " bundle",
1928                                                 name, "");
1929         }
1930         loggerBundle = LoggerBundle.get(name, lb.userBundle);
1931     }
1932 
1933     /**
1934      * Sets a resource bundle on this logger.
1935      * All messages will be logged using the given resource bundle for its
1936      * specific {@linkplain ResourceBundle#getLocale locale}.
1937      * @param bundle The resource bundle that this logger shall use.
1938      * @throws NullPointerException if the given bundle is {@code null}.
1939      * @throws IllegalArgumentException if the given bundle doesn't have a
1940      *         {@linkplain ResourceBundle#getBaseBundleName base name},
1941      *         or if this logger already has a resource bundle set but
1942      *         the given bundle has a different base name.
1943      * @throws SecurityException if a security manager exists,
1944      *         this logger is not anonymous, and the caller
1945      *         does not have LoggingPermission("control").
1946      * @since 1.8
1947      */
1948     public void setResourceBundle(ResourceBundle bundle) {
1949         checkPermission();
1950 
1951         // Will throw NPE if bundle is null.
1952         final String baseName = bundle.getBaseBundleName();
1953 
1954         // bundle must have a name
1955         if (baseName == null || baseName.isEmpty()) {
1956             throw new IllegalArgumentException("resource bundle must have a name");
1957         }
1958 
1959         synchronized (this) {
1960             LoggerBundle lb = loggerBundle;
1961             final boolean canReplaceResourceBundle = lb.resourceBundleName == null
1962                     || lb.resourceBundleName.equals(baseName);
1963 
1964             if (!canReplaceResourceBundle) {
1965                 throw new IllegalArgumentException("can't replace resource bundle");
1966             }
1967 
1968 
1969             loggerBundle = LoggerBundle.get(baseName, bundle);

1970         }
1971     }
1972 
1973     /**
1974      * Return the parent for this Logger.
1975      * <p>
1976      * This method returns the nearest extant parent in the namespace.
1977      * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b"
1978      * has been created but no logger "a.b.c" exists, then a call of
1979      * getParent on the Logger "a.b.c.d" will return the Logger "a.b".
1980      * <p>
1981      * The result will be null if it is called on the root Logger
1982      * in the namespace.
1983      *
1984      * @return nearest existing parent Logger
1985      */
1986     public Logger getParent() {
1987         // Note: this used to be synchronized on treeLock.  However, this only
1988         // provided memory semantics, as there was no guarantee that the caller
1989         // would synchronize on treeLock (in fact, there is no way for external


2102         }
2103 
2104         levelValue = newLevelValue;
2105 
2106         // System.err.println("effective level: \"" + getName() + "\" := " + level);
2107 
2108         // Recursively update the level on each of our kids.
2109         if (kids != null) {
2110             for (int i = 0; i < kids.size(); i++) {
2111                 LogManager.LoggerWeakRef ref = kids.get(i);
2112                 Logger kid =  ref.get();
2113                 if (kid != null) {
2114                     kid.updateEffectiveLevel();
2115                 }
2116             }
2117         }
2118     }
2119 
2120 
2121     // Private method to get the potentially inherited
2122     // resource bundle and resource bundle name for this Logger.
2123     // This method never returns null.
2124     private LoggerBundle getEffectiveLoggerBundle() {
2125         final LoggerBundle lb = loggerBundle;
2126         if (lb.isSystemBundle()) {
2127             return SYSTEM_BUNDLE;
2128         }
2129 
2130         // first take care of this logger
2131         final ResourceBundle b = getResourceBundle();
2132         if (b != null && b == lb.userBundle) {
2133             return lb;
2134         } else if (b != null) {
2135             // either lb.userBundle is null or getResourceBundle() is
2136             // overriden
2137             final String rbName = getResourceBundleName();
2138             if (!SYSTEM_LOGGER_RB_NAME.equals(rbName)
2139                     && !SYSTEM_LOGGER_RB_NAME.equals(b.getBaseBundleName())) {
2140                 return LoggerBundle.get(rbName, b);
2141             } else {
2142                 return SYSTEM_BUNDLE;
2143             }








2144         }
2145 
2146         // no resource bundle was specified on this logger, look up the
2147         // parent stack.
2148         Logger target = this.parent;
2149         while (target != null) {
2150             final LoggerBundle trb = target.loggerBundle;
2151             if (trb.isSystemBundle()) {
2152                 return SYSTEM_BUNDLE;
2153             }
2154             if (trb.userBundle != null) {
2155                 return trb;
2156             }
2157             final String rbName = target.getResourceBundleName();
2158             if (rbName != null) {
2159                 if (!SYSTEM_LOGGER_RB_NAME.equals(rbName)) {
2160                     return LoggerBundle.get(rbName,
2161                             findResourceBundle(rbName, true));
2162                 } else {
2163                     return SYSTEM_BUNDLE;
2164                 }
2165             }
2166             target = target.getParent();
2167         }
2168         return NO_RESOURCE_BUNDLE;
2169     }
2170 
2171 }