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 }
|