1. /*
  2. * @(#)Logger.java 1.35 03/01/27
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.util.logging;
  8. import java.util.*;
  9. import java.security.*;
  10. import java.lang.ref.WeakReference;
  11. /**
  12. * A Logger object is used to log messages for a specific
  13. * system or application component. Loggers are normally named,
  14. * using a hierarchical dot-separated namespace. Logger names
  15. * can be arbitrary strings, but they should normally be based on
  16. * the package name or class name of the logged component, such
  17. * as java.net or javax.swing. In additon it is possible to create
  18. * "anonymous" Loggers that are not stored in the Logger namespace.
  19. * <p>
  20. * Logger objects may be obtained by calls on one of the getLogger
  21. * factory methods. These will either create a new Logger or
  22. * return a suitable existing Logger.
  23. * <p>
  24. * Logging messages will be forwarded to registered Handler
  25. * objects, which can forward the messages to a variety of
  26. * destinations, including consoles, files, OS logs, etc.
  27. * <p>
  28. * Each Logger keeps track of a "parent" Logger, which is its
  29. * nearest existing ancestor in the Logger namespace.
  30. * <p>
  31. * Each Logger has a "Level" associated with it. This reflects
  32. * a minimum Level that this logger cares about. If a Logger's
  33. * level is set to <tt>null</tt>, then its effective level is inherited
  34. * from its parent, which may in turn obtain it recursively from its
  35. * parent, and so on up the tree.
  36. * <p>
  37. * The log level can be configured based on the properties from the
  38. * logging configuration file, as described in the description
  39. * of the LogManager class. However it may also be dynamically changed
  40. * by calls on the Logger.setLevel method. If a logger's level is
  41. * changed the change may also affect child loggers, since any child
  42. * logger that has <tt>null</tt> as its level will inherit its
  43. * effective level from its parent.
  44. * <p>
  45. * On each logging call the Logger initially performs a cheap
  46. * check of the request level (e.g. SEVERE or FINE) against the
  47. * effective log level of the logger. If the request level is
  48. * lower than the log level, the logging call returns immediately.
  49. * <p>
  50. * After passing this initial (cheap) test, the Logger will allocate
  51. * a LogRecord to describe the logging message. It will then call a
  52. * Filter (if present) to do a more detailed check on whether the
  53. * record should be published. If that passes it will then publish
  54. * the LogRecord to its output Handlers. By default, loggers also
  55. * publish to their parent's Handlers, recursively up the tree.
  56. * <p>
  57. * Each Logger may have a ResourceBundle name associated with it.
  58. * The named bundle will be used for localizing logging messages.
  59. * If a Logger does not have its own ResourceBundle name, then
  60. * it will inherit the ResourceBundle name from its parent,
  61. * recursively up the tree.
  62. * <p>
  63. * Most of the logger output methods take a "msg" argument. This
  64. * msg argument may be either a raw value or a localization key.
  65. * During formatting, if the logger has (or inherits) a localization
  66. * ResourceBundle and if the ResourceBundle has a mapping for the msg
  67. * string, then the msg string is replaced by the localized value.
  68. * Otherwise the original msg string is used. Typically, formatters use
  69. * java.text.MessageFormat style formatting to format parameters, so
  70. * for example a format string "{0} {1}" would format two parameters
  71. * as strings.
  72. * <p>
  73. * When mapping ResourceBundle names to ResourceBundles, the Logger
  74. * will first try to use the Thread's ContextClassLoader. If that
  75. * is null it will try the SystemClassLoader instead. As a temporary
  76. * transition feature in the initial implementation, if the Logger is
  77. * unable to locate a ResourceBundle from the ContextClassLoader or
  78. * SystemClassLoader the Logger will also search up the class stack
  79. * and use successive calling ClassLoaders to try to locate a ResourceBundle.
  80. * (This call stack search is to allow containers to transition to
  81. * using ContextClassLoaders and is likely to be removed in future
  82. * versions.)
  83. * <p>
  84. * Formatting (including localization) is the responsibility of
  85. * the output Handler, which will typically call a Formatter.
  86. * <p>
  87. * Note that formatting need not occur synchronously. It may be delayed
  88. * until a LogRecord is actually written to an external sink.
  89. * <p>
  90. * The logging methods are grouped in five main categories:
  91. * <ul>
  92. * <li><p>
  93. * There are a set of "log" methods that take a log level, a message
  94. * string, and optionally some parameters to the message string.
  95. * <li><p>
  96. * There are a set of "logp" methods (for "log precise") that are
  97. * like the "log" methods, but also take an explicit source class name
  98. * and method name.
  99. * <li><p>
  100. * There are a set of "logrb" method (for "log with resource bundle")
  101. * that are like the "logp" method, but also take an explicit resource
  102. * bundle name for use in localizing the log message.
  103. * <li><p>
  104. * There are convenience methods for tracing method entries (the
  105. * "entering" methods), method returns (the "exiting" methods) and
  106. * throwing exceptions (the "throwing" methods).
  107. * <li><p>
  108. * Finally, there are a set of convenience methods for use in the
  109. * very simplest cases, when a developer simply wants to log a
  110. * simple string at a given log level. These methods are named
  111. * after the standard Level names ("severe", "warning", "info", etc.)
  112. * and take a single argument, a message string.
  113. * </ul>
  114. * <p>
  115. * For the methods that do not take an explicit source name and
  116. * method name, the Logging framework will make a "best effort"
  117. * to determine which class and method called into the logging method.
  118. * However, it is important to realize that this automatically inferred
  119. * information may only be approximate (or may even be quite wrong!).
  120. * Virtual machines are allowed to do extensive optimizations when
  121. * JITing and may entirely remove stack frames, making it impossible
  122. * to reliably locate the calling class and method.
  123. * <P>
  124. * All methods on Logger are multi-thread safe.
  125. * <p>
  126. * <b>Subclassing Information:</b> Note that a LogManager class may
  127. * provide its own implementation of named Loggers for any point in
  128. * the namespace. Therefore, any subclasses of Logger (unless they
  129. * are implemented in conjunction with a new LogManager class) should
  130. * take care to obtain a Logger instance from the LogManager class and
  131. * should delegate operations such as "isLoggable" and "log(LogRecord)"
  132. * to that instance. Note that in order to intercept all logging
  133. * output, subclasses need only override the log(LogRecord) method.
  134. * All the other logging methods are implemented as calls on this
  135. * log(LogRecord) method.
  136. *
  137. * @version 1.35, 01/27/03
  138. * @since 1.4
  139. */
  140. public class Logger {
  141. private static final Handler emptyHandlers[] = new Handler[0];
  142. private static final int offValue = Level.OFF.intValue();
  143. private LogManager manager = LogManager.getLogManager();
  144. private String name;
  145. private ArrayList handlers;
  146. private String resourceBundleName;
  147. private boolean useParentHandlers = true;
  148. private Filter filter;
  149. private boolean anonymous;
  150. private ResourceBundle catalog; // Cached resource bundle
  151. private String catalogName; // name associated with catalog
  152. private Locale catalogLocale; // locale associated with catalog
  153. // The fields relating to parent-child relationships and levels
  154. // are managed under a separate lock, the treeLock.
  155. private static Object treeLock = new Object();
  156. // We keep weak references from parents to children, but strong
  157. // references from children to parents.
  158. private Logger parent; // our nearest parent.
  159. private ArrayList kids; // WeakReferences to loggers that have us as parent
  160. private Level levelObject;
  161. private volatile int levelValue; // current effective level value
  162. /**
  163. * The "global" Logger object is provided as a convenience to developers
  164. * who are making casual use of the Logging package. Developers
  165. * who are making serious use of the logging package (for example
  166. * in products) should create and use their own Logger objects,
  167. * with appropriate names, so that logging can be controlled on a
  168. * suitable per-Logger granularity.
  169. * <p>
  170. * The global logger is initialized by calling Logger.getLogger("global").
  171. */
  172. public static final Logger global = getLogger("global");
  173. /**
  174. * Protected method to construct a logger for a named subsystem.
  175. * <p>
  176. * The logger will be initially configured with a null Level
  177. * and with useParentHandlers true.
  178. *
  179. * @param name A name for the logger. This should
  180. * be a dot-separated name and should normally
  181. * be based on the package name or class name
  182. * of the subsystem, such as java.net
  183. * or javax.swing. It may be null for anonymous Loggers.
  184. * @param resourceBundleName name of ResourceBundle to be used for localizing
  185. * messages for this logger. May be null if none
  186. * of the messages require localization.
  187. * @throws MissingResourceException if the ResourceBundleName is non-null and
  188. * no corresponding resource can be found.
  189. */
  190. protected Logger(String name, String resourceBundleName) {
  191. if (resourceBundleName != null) {
  192. // Note: we may get a MissingResourceException here.
  193. setupResourceInfo(resourceBundleName);
  194. }
  195. this.name = name;
  196. levelValue = Level.INFO.intValue();
  197. }
  198. /**
  199. * Find or create a logger for a named subsystem. If a logger has
  200. * already been created with the given name it is returned. Otherwise
  201. * a new logger is created.
  202. * <p>
  203. * If a new logger is created its log level will be configured
  204. * based on the LogManager configuration and it will configured
  205. * to also send logging output to its parent's handlers. It will
  206. * be registered in the LogManager global namespace.
  207. *
  208. * @param name A name for the logger. This should
  209. * be a dot-separated name and should normally
  210. * be based on the package name or class name
  211. * of the subsystem, such as java.net
  212. * or javax.swing
  213. * @return a suitable Logger
  214. */
  215. public static synchronized Logger getLogger(String name) {
  216. LogManager manager = LogManager.getLogManager();
  217. Logger result = manager.getLogger(name);
  218. if (result == null) {
  219. result = new Logger(name, null);
  220. manager.addLogger(result);
  221. result = manager.getLogger(name);
  222. }
  223. return result;
  224. }
  225. /**
  226. * Find or create a logger for a named subsystem. If a logger has
  227. * already been created with the given name it is returned. Otherwise
  228. * a new logger is created.
  229. * <p>
  230. * If a new logger is created its log level will be configured
  231. * based on the LogManager and it will configured to also send logging
  232. * output to its parent loggers Handlers. It will be registered in
  233. * the LogManager global namespace.
  234. * <p>
  235. * If the named Logger already exists and does not yet have a
  236. * localization resource bundle then the given resource bundle
  237. * name is used. If the named Logger already exists and has
  238. * a different resource bundle name then an IllegalArgumentException
  239. * is thrown.
  240. * <p>
  241. * @param name A name for the logger. This should
  242. * be a dot-separated name and should normally
  243. * be based on the package name or class name
  244. * of the subsystem, such as java.net
  245. * or javax.swing
  246. * @param resourceBundleName name of ResourceBundle to be used for localizing
  247. * messages for this logger.
  248. * @return a suitable Logger
  249. * @throws MissingResourceException if the named ResourceBundle cannot be found.
  250. * @throws IllegalArgumentException if the Logger already exists and uses
  251. * a different resource bundle name.
  252. */
  253. public static synchronized Logger getLogger(String name, String resourceBundleName) {
  254. LogManager manager = LogManager.getLogManager();
  255. Logger result = manager.getLogger(name);
  256. if (result == null) {
  257. // Create a new logger.
  258. // Note: we may get a MissingResourceException here.
  259. result = new Logger(name, resourceBundleName);
  260. manager.addLogger(result);
  261. result = manager.getLogger(name);
  262. }
  263. if (result.resourceBundleName == null) {
  264. // Note: we may get a MissingResourceException here.
  265. result.setupResourceInfo(resourceBundleName);
  266. } else if (!result.resourceBundleName.equals(resourceBundleName)) {
  267. throw new IllegalArgumentException(result.resourceBundleName +
  268. " != " + resourceBundleName);
  269. }
  270. return result;
  271. }
  272. /**
  273. * Create an anonymous Logger. The newly created Logger is not
  274. * registered in the LogManager namespace. There will be no
  275. * access checks on updates to the logger.
  276. * <p>
  277. * This factory method is primarily intended for use from applets.
  278. * Because the resulting Logger is anonymous it can be kept private
  279. * by the creating class. This removes the need for normal security
  280. * checks, which in turn allows untrusted applet code to update
  281. * the control state of the Logger. For example an applet can do
  282. * a setLevel or an addHandler on an anonymous Logger.
  283. * <p>
  284. * Even although the new logger is anonymous, it is configured
  285. * to have the root logger ("") as its parent. This means that
  286. * by default it inherits its effective level and handlers
  287. * from the root logger.
  288. * <p>
  289. *
  290. * @return a newly created private Logger
  291. */
  292. public static synchronized Logger getAnonymousLogger() {
  293. LogManager manager = LogManager.getLogManager();
  294. Logger result = new Logger(null, null);
  295. result.anonymous = true;
  296. Logger root = manager.getLogger("");
  297. result.doSetParent(root);
  298. return result;
  299. }
  300. /**
  301. * Create an anonymous Logger. The newly created Logger is not
  302. * registered in the LogManager namespace. There will be no
  303. * access checks on updates to the logger.
  304. * <p>
  305. * This factory method is primarily intended for use from applets.
  306. * Because the resulting Logger is anonymous it can be kept private
  307. * by the creating class. This removes the need for normal security
  308. * checks, which in turn allows untrusted applet code to update
  309. * the control state of the Logger. For example an applet can do
  310. * a setLevel or an addHandler on an anonymous Logger.
  311. * <p>
  312. * Even although the new logger is anonymous, it is configured
  313. * to have the root logger ("") as its parent. This means that
  314. * by default it inherits its effective level and handlers
  315. * from the root logger.
  316. * <p>
  317. * @param resourceBundleName name of ResourceBundle to be used for localizing
  318. * messages for this logger.
  319. * @return a newly created private Logger
  320. * @throws MissingResourceException if the named ResourceBundle cannot be found.
  321. */
  322. public static synchronized Logger getAnonymousLogger(String resourceBundleName) {
  323. LogManager manager = LogManager.getLogManager();
  324. Logger result = new Logger(null, resourceBundleName);
  325. result.anonymous = true;
  326. Logger root = manager.getLogger("");
  327. result.doSetParent(root);
  328. return result;
  329. }
  330. /**
  331. * Retrieve the localization resource bundle for this
  332. * logger for the current default locale. Note that if
  333. * the result is null, then the Logger will use a resource
  334. * bundle inherited from its parent.
  335. *
  336. * @return localization bundle (may be null)
  337. */
  338. public ResourceBundle getResourceBundle() {
  339. return findResourceBundle(getResourceBundleName());
  340. }
  341. /**
  342. * Retrieve the localization resource bundle name for this
  343. * logger. Note that if the result is null, then the Logger
  344. * will use a resource bundle name inherited from its parent.
  345. *
  346. * @return localization bundle name (may be null)
  347. */
  348. public String getResourceBundleName() {
  349. return resourceBundleName;
  350. }
  351. /**
  352. * Set a filter to control output on this Logger.
  353. * <P>
  354. * After passing the initial "level" check, the Logger will
  355. * call this Filter to check if a log record should really
  356. * be published.
  357. *
  358. * @param newFilter a filter object (may be null)
  359. * @exception SecurityException if a security manager exists and if
  360. * the caller does not have LoggingPermission("control").
  361. */
  362. public void setFilter(Filter newFilter) throws SecurityException {
  363. if (!anonymous) {
  364. manager.checkAccess();
  365. }
  366. filter = newFilter;
  367. }
  368. /**
  369. * Get the current filter for this Logger.
  370. *
  371. * @return a filter object (may be null)
  372. */
  373. public Filter getFilter() {
  374. return filter;
  375. }
  376. /**
  377. * Log a LogRecord.
  378. * <p>
  379. * All the other logging methods in this class call through
  380. * this method to actually perform any logging. Subclasses can
  381. * override this single method to capture all log activity.
  382. *
  383. * @param record the LogRecord to be published
  384. */
  385. public void log(LogRecord record) {
  386. if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
  387. return;
  388. }
  389. synchronized (this) {
  390. if (filter != null && !filter.isLoggable(record)) {
  391. return;
  392. }
  393. }
  394. // Post the LogRecord to all our Handlers, and then to
  395. // our parents' handlers, all the way up the tree.
  396. Logger logger = this;
  397. while (logger != null) {
  398. Handler targets[] = logger.getHandlers();
  399. if (targets != null) {
  400. for (int i = 0; i < targets.length; i++) {
  401. targets[i].publish(record);
  402. }
  403. }
  404. if (!logger.getUseParentHandlers()) {
  405. break;
  406. }
  407. logger = logger.getParent();
  408. }
  409. }
  410. // private support method for logging.
  411. // We fill in the logger name, resource bundle name, and
  412. // resource bundle and then call "void log(LogRecord)".
  413. private void doLog(LogRecord lr) {
  414. lr.setLoggerName(name);
  415. String ebname = getEffectiveResourceBundleName();
  416. if (ebname != null) {
  417. lr.setResourceBundleName(ebname);
  418. lr.setResourceBundle(findResourceBundle(ebname));
  419. }
  420. log(lr);
  421. }
  422. //================================================================
  423. // Start of convenience methods WITHOUT className and methodName
  424. //================================================================
  425. /**
  426. * Log a message, with no arguments.
  427. * <p>
  428. * If the logger is currently enabled for the given message
  429. * level then the given message is forwarded to all the
  430. * registered output Handler objects.
  431. * <p>
  432. * @param level One of the message level identifiers, e.g. SEVERE
  433. * @param msg The string message (or a key in the message catalog)
  434. */
  435. public void log(Level level, String msg) {
  436. if (level.intValue() < levelValue || levelValue == offValue) {
  437. return;
  438. }
  439. LogRecord lr = new LogRecord(level, msg);
  440. doLog(lr);
  441. }
  442. /**
  443. * Log a message, with one object parameter.
  444. * <p>
  445. * If the logger is currently enabled for the given message
  446. * level then a corresponding LogRecord is created and forwarded
  447. * to all the registered output Handler objects.
  448. * <p>
  449. * @param level One of the message level identifiers, e.g. SEVERE
  450. * @param msg The string message (or a key in the message catalog)
  451. * @param param1 parameter to the message
  452. */
  453. public void log(Level level, String msg, Object param1) {
  454. if (level.intValue() < levelValue || levelValue == offValue) {
  455. return;
  456. }
  457. LogRecord lr = new LogRecord(level, msg);
  458. Object params[] = { param1 };
  459. lr.setParameters(params);
  460. doLog(lr);
  461. }
  462. /**
  463. * Log a message, with an array of object arguments.
  464. * <p>
  465. * If the logger is currently enabled for the given message
  466. * level then a corresponding LogRecord is created and forwarded
  467. * to all the registered output Handler objects.
  468. * <p>
  469. * @param level One of the message level identifiers, e.g. SEVERE
  470. * @param msg The string message (or a key in the message catalog)
  471. * @param params array of parameters to the message
  472. */
  473. public void log(Level level, String msg, Object params[]) {
  474. if (level.intValue() < levelValue || levelValue == offValue) {
  475. return;
  476. }
  477. LogRecord lr = new LogRecord(level, msg);
  478. lr.setParameters(params);
  479. doLog(lr);
  480. }
  481. /**
  482. * Log a message, with associated Throwable information.
  483. * <p>
  484. * If the logger is currently enabled for the given message
  485. * level then the given arguments are stored in a LogRecord
  486. * which is forwarded to all registered output handlers.
  487. * <p>
  488. * Note that the thrown argument is stored in the LogRecord thrown
  489. * property, rather than the LogRecord parameters property. Thus is it
  490. * processed specially by output Formatters and is not treated
  491. * as a formatting parameter to the LogRecord message property.
  492. * <p>
  493. * @param level One of the message level identifiers, e.g. SEVERE
  494. * @param msg The string message (or a key in the message catalog)
  495. * @param thrown Throwable associated with log message.
  496. */
  497. public void log(Level level, String msg, Throwable thrown) {
  498. if (level.intValue() < levelValue || levelValue == offValue) {
  499. return;
  500. }
  501. LogRecord lr = new LogRecord(level, msg);
  502. lr.setThrown(thrown);
  503. doLog(lr);
  504. }
  505. //================================================================
  506. // Start of convenience methods WITH className and methodName
  507. //================================================================
  508. /**
  509. * Log a message, specifying source class and method,
  510. * with no arguments.
  511. * <p>
  512. * If the logger is currently enabled for the given message
  513. * level then the given message is forwarded to all the
  514. * registered output Handler objects.
  515. * <p>
  516. * @param level One of the message level identifiers, e.g. SEVERE
  517. * @param sourceClass name of class that issued the logging request
  518. * @param sourceMethod name of method that issued the logging request
  519. * @param msg The string message (or a key in the message catalog)
  520. */
  521. public void logp(Level level, String sourceClass, String sourceMethod, String msg) {
  522. if (level.intValue() < levelValue || levelValue == offValue) {
  523. return;
  524. }
  525. LogRecord lr = new LogRecord(level, msg);
  526. lr.setSourceClassName(sourceClass);
  527. lr.setSourceMethodName(sourceMethod);
  528. doLog(lr);
  529. }
  530. /**
  531. * Log a message, specifying source class and method,
  532. * with a single object parameter to the log message.
  533. * <p>
  534. * If the logger is currently enabled for the given message
  535. * level then a corresponding LogRecord is created and forwarded
  536. * to all the registered output Handler objects.
  537. * <p>
  538. * @param level One of the message level identifiers, e.g. SEVERE
  539. * @param sourceClass name of class that issued the logging request
  540. * @param sourceMethod name of method that issued the logging request
  541. * @param msg The string message (or a key in the message catalog)
  542. * @param param1 Parameter to the log message.
  543. */
  544. public void logp(Level level, String sourceClass, String sourceMethod,
  545. String msg, Object param1) {
  546. if (level.intValue() < levelValue || levelValue == offValue) {
  547. return;
  548. }
  549. LogRecord lr = new LogRecord(level, msg);
  550. lr.setSourceClassName(sourceClass);
  551. lr.setSourceMethodName(sourceMethod);
  552. Object params[] = { param1 };
  553. lr.setParameters(params);
  554. doLog(lr);
  555. }
  556. /**
  557. * Log a message, specifying source class and method,
  558. * with an array of object arguments.
  559. * <p>
  560. * If the logger is currently enabled for the given message
  561. * level then a corresponding LogRecord is created and forwarded
  562. * to all the registered output Handler objects.
  563. * <p>
  564. * @param level One of the message level identifiers, e.g. SEVERE
  565. * @param sourceClass name of class that issued the logging request
  566. * @param sourceMethod name of method that issued the logging request
  567. * @param msg The string message (or a key in the message catalog)
  568. * @param params Array of parameters to the message
  569. */
  570. public void logp(Level level, String sourceClass, String sourceMethod,
  571. String msg, Object params[]) {
  572. if (level.intValue() < levelValue || levelValue == offValue) {
  573. return;
  574. }
  575. LogRecord lr = new LogRecord(level, msg);
  576. lr.setSourceClassName(sourceClass);
  577. lr.setSourceMethodName(sourceMethod);
  578. lr.setParameters(params);
  579. doLog(lr);
  580. }
  581. /**
  582. * Log a message, specifying source class and method,
  583. * with associated Throwable information.
  584. * <p>
  585. * If the logger is currently enabled for the given message
  586. * level then the given arguments are stored in a LogRecord
  587. * which is forwarded to all registered output handlers.
  588. * <p>
  589. * Note that the thrown argument is stored in the LogRecord thrown
  590. * property, rather than the LogRecord parameters property. Thus is it
  591. * processed specially by output Formatters and is not treated
  592. * as a formatting parameter to the LogRecord message property.
  593. * <p>
  594. * @param level One of the message level identifiers, e.g. SEVERE
  595. * @param sourceClass name of class that issued the logging request
  596. * @param sourceMethod name of method that issued the logging request
  597. * @param msg The string message (or a key in the message catalog)
  598. * @param thrown Throwable associated with log message.
  599. */
  600. public void logp(Level level, String sourceClass, String sourceMethod,
  601. String msg, Throwable thrown) {
  602. if (level.intValue() < levelValue || levelValue == offValue) {
  603. return;
  604. }
  605. LogRecord lr = new LogRecord(level, msg);
  606. lr.setSourceClassName(sourceClass);
  607. lr.setSourceMethodName(sourceMethod);
  608. lr.setThrown(thrown);
  609. doLog(lr);
  610. }
  611. //=========================================================================
  612. // Start of convenience methods WITH className, methodName and bundle name.
  613. //=========================================================================
  614. // Private support method for logging for "logrb" methods.
  615. // We fill in the logger name, resource bundle name, and
  616. // resource bundle and then call "void log(LogRecord)".
  617. private void doLog(LogRecord lr, String rbname) {
  618. lr.setLoggerName(name);
  619. if (rbname != null) {
  620. lr.setResourceBundleName(rbname);
  621. lr.setResourceBundle(findResourceBundle(rbname));
  622. }
  623. log(lr);
  624. }
  625. /**
  626. * Log a message, specifying source class, method, and resource bundle name
  627. * with no arguments.
  628. * <p>
  629. * If the logger is currently enabled for the given message
  630. * level then the given message is forwarded to all the
  631. * registered output Handler objects.
  632. * <p>
  633. * The msg string is localized using the named resource bundle. If the
  634. * resource bundle name is null, then the msg string is not localized.
  635. * <p>
  636. * @param level One of the message level identifiers, e.g. SEVERE
  637. * @param sourceClass name of class that issued the logging request
  638. * @param sourceMethod name of method that issued the logging request
  639. * @param bundleName name of resource bundle to localize msg
  640. * @param msg The string message (or a key in the message catalog)
  641. * @throws MissingResourceException if no suitable ResourceBundle can
  642. * be found.
  643. */
  644. public void logrb(Level level, String sourceClass, String sourceMethod,
  645. String bundleName, String msg) {
  646. if (level.intValue() < levelValue || levelValue == offValue) {
  647. return;
  648. }
  649. LogRecord lr = new LogRecord(level, msg);
  650. lr.setSourceClassName(sourceClass);
  651. lr.setSourceMethodName(sourceMethod);
  652. doLog(lr, bundleName);
  653. }
  654. /**
  655. * Log a message, specifying source class, method, and resource bundle name,
  656. * with a single object parameter to the log message.
  657. * <p>
  658. * If the logger is currently enabled for the given message
  659. * level then a corresponding LogRecord is created and forwarded
  660. * to all the registered output Handler objects.
  661. * <p>
  662. * The msg string is localized using the named resource bundle. If the
  663. * resource bundle name is null, then the msg string is not localized.
  664. * <p>
  665. * @param level One of the message level identifiers, e.g. SEVERE
  666. * @param sourceClass name of class that issued the logging request
  667. * @param sourceMethod name of method that issued the logging request
  668. * @param bundleName name of resource bundle to localize msg
  669. * @param msg The string message (or a key in the message catalog)
  670. * @param param1 Parameter to the log message.
  671. * @throws MissingResourceException if no suitable ResourceBundle can
  672. * be found.
  673. */
  674. public void logrb(Level level, String sourceClass, String sourceMethod,
  675. String bundleName, String msg, Object param1) {
  676. if (level.intValue() < levelValue || levelValue == offValue) {
  677. return;
  678. }
  679. LogRecord lr = new LogRecord(level, msg);
  680. lr.setSourceClassName(sourceClass);
  681. lr.setSourceMethodName(sourceMethod);
  682. Object params[] = { param1 };
  683. lr.setParameters(params);
  684. doLog(lr, bundleName);
  685. }
  686. /**
  687. * Log a message, specifying source class, method, and resource bundle name,
  688. * with an array of object arguments.
  689. * <p>
  690. * If the logger is currently enabled for the given message
  691. * level then a corresponding LogRecord is created and forwarded
  692. * to all the registered output Handler objects.
  693. * <p>
  694. * The msg string is localized using the named resource bundle. If the
  695. * resource bundle name is null, then the msg string is not localized.
  696. * <p>
  697. * @param level One of the message level identifiers, e.g. SEVERE
  698. * @param sourceClass name of class that issued the logging request
  699. * @param sourceMethod name of method that issued the logging request
  700. * @param bundleName name of resource bundle to localize msg
  701. * @param msg The string message (or a key in the message catalog)
  702. * @param params Array of parameters to the message
  703. * @throws MissingResourceException if no suitable ResourceBundle can
  704. * be found.
  705. */
  706. public void logrb(Level level, String sourceClass, String sourceMethod,
  707. String bundleName, String msg, Object params[]) {
  708. if (level.intValue() < levelValue || levelValue == offValue) {
  709. return;
  710. }
  711. LogRecord lr = new LogRecord(level, msg);
  712. lr.setSourceClassName(sourceClass);
  713. lr.setSourceMethodName(sourceMethod);
  714. lr.setParameters(params);
  715. doLog(lr, bundleName);
  716. }
  717. /**
  718. * Log a message, specifying source class, method, and resource bundle name,
  719. * with associated Throwable information.
  720. * <p>
  721. * If the logger is currently enabled for the given message
  722. * level then the given arguments are stored in a LogRecord
  723. * which is forwarded to all registered output handlers.
  724. * <p>
  725. * The msg string is localized using the named resource bundle. If the
  726. * resource bundle name is null, then the msg string is not localized.
  727. * <p>
  728. * Note that the thrown argument is stored in the LogRecord thrown
  729. * property, rather than the LogRecord parameters property. Thus is it
  730. * processed specially by output Formatters and is not treated
  731. * as a formatting parameter to the LogRecord message property.
  732. * <p>
  733. * @param level One of the message level identifiers, e.g. SEVERE
  734. * @param sourceClass name of class that issued the logging request
  735. * @param sourceMethod name of method that issued the logging request
  736. * @param bundleName name of resource bundle to localize msg
  737. * @param msg The string message (or a key in the message catalog)
  738. * @param thrown Throwable associated with log message.
  739. * @throws MissingResourceException if no suitable ResourceBundle can
  740. * be found.
  741. */
  742. public void logrb(Level level, String sourceClass, String sourceMethod,
  743. String bundleName, String msg, Throwable thrown) {
  744. if (level.intValue() < levelValue || levelValue == offValue) {
  745. return;
  746. }
  747. LogRecord lr = new LogRecord(level, msg);
  748. lr.setSourceClassName(sourceClass);
  749. lr.setSourceMethodName(sourceMethod);
  750. lr.setThrown(thrown);
  751. doLog(lr, bundleName);
  752. }
  753. //======================================================================
  754. // Start of convenience methods for logging method entries and returns.
  755. //======================================================================
  756. /**
  757. * Log a method entry.
  758. * <p>
  759. * This is a convenience method that can be used to log entry
  760. * to a method. A LogRecord with message "ENTRY", log level
  761. * FINER, and the given sourceMethod and sourceClass is logged.
  762. * <p>
  763. * @param sourceClass name of class that issued the logging request
  764. * @param sourceMethod name of method that is being entered
  765. */
  766. public void entering(String sourceClass, String sourceMethod) {
  767. if (Level.FINER.intValue() < levelValue) {
  768. return;
  769. }
  770. logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
  771. }
  772. /**
  773. * Log a method entry, with one parameter.
  774. * <p>
  775. * This is a convenience method that can be used to log entry
  776. * to a method. A LogRecord with message "ENTRY {0}", log level
  777. * FINER, and the given sourceMethod, sourceClass, and parameter
  778. * is logged.
  779. * <p>
  780. * @param sourceClass name of class that issued the logging request
  781. * @param sourceMethod name of method that is being entered
  782. * @param param1 parameter to the method being entered
  783. */
  784. public void entering(String sourceClass, String sourceMethod, Object param1) {
  785. if (Level.FINER.intValue() < levelValue) {
  786. return;
  787. }
  788. Object params[] = { param1 };
  789. logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", params);
  790. }
  791. /**
  792. * Log a method entry, with an array of parameters.
  793. * <p>
  794. * This is a convenience method that can be used to log entry
  795. * to a method. A LogRecord with message "ENTRY" (followed by a
  796. * format {N} indicator for each entry in the parameter array),
  797. * log level FINER, and the given sourceMethod, sourceClass, and
  798. * parameters is logged.
  799. * <p>
  800. * @param sourceClass name of class that issued the logging request
  801. * @param sourceMethod name of method that is being entered
  802. * @param params array of parameters to the method being entered
  803. */
  804. public void entering(String sourceClass, String sourceMethod, Object params[]) {
  805. if (Level.FINER.intValue() < levelValue) {
  806. return;
  807. }
  808. String msg = "ENTRY";
  809. for (int i = 0; i < params.length; i++) {
  810. msg = msg + " {" + i + "}";
  811. }
  812. logp(Level.FINER, sourceClass, sourceMethod, msg, params);
  813. }
  814. /**
  815. * Log a method return.
  816. * <p>
  817. * This is a convenience method that can be used to log returning
  818. * from a method. A LogRecord with message "RETURN", log level
  819. * FINER, and the given sourceMethod and sourceClass is logged.
  820. * <p>
  821. * @param sourceClass name of class that issued the logging request
  822. * @param sourceMethod name of the method
  823. */
  824. public void exiting(String sourceClass, String sourceMethod) {
  825. if (Level.FINER.intValue() < levelValue) {
  826. return;
  827. }
  828. logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
  829. }
  830. /**
  831. * Log a method return, with result object.
  832. * <p>
  833. * This is a convenience method that can be used to log returning
  834. * from a method. A LogRecord with message "RETURN {0}", log level
  835. * FINER, and the gives sourceMethod, sourceClass, and result
  836. * object is logged.
  837. * <p>
  838. * @param sourceClass name of class that issued the logging request
  839. * @param sourceMethod name of the method
  840. * @param result Object that is being returned
  841. */
  842. public void exiting(String sourceClass, String sourceMethod, Object result) {
  843. if (Level.FINER.intValue() < levelValue) {
  844. return;
  845. }
  846. Object params[] = { result };
  847. logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
  848. }
  849. /**
  850. * Log throwing an exception.
  851. * <p>
  852. * This is a convenience method to log that a method is
  853. * terminating by throwing an exception. The logging is done
  854. * using the FINER level.
  855. * <p>
  856. * If the logger is currently enabled for the given message
  857. * level then the given arguments are stored in a LogRecord
  858. * which is forwarded to all registered output handlers. The
  859. * LogRecord's message is set to "THROW".
  860. * <p>
  861. * Note that the thrown argument is stored in the LogRecord thrown
  862. * property, rather than the LogRecord parameters property. Thus is it
  863. * processed specially by output Formatters and is not treated
  864. * as a formatting parameter to the LogRecord message property.
  865. * <p>
  866. * @param sourceClass name of class that issued the logging request
  867. * @param sourceMethod name of the method.
  868. * @param thrown The Throwable that is being thrown.
  869. */
  870. public void throwing(String sourceClass, String sourceMethod, Throwable thrown) {
  871. if (Level.FINER.intValue() < levelValue) {
  872. return;
  873. }
  874. LogRecord lr = new LogRecord(Level.FINER, "THROW");
  875. lr.setSourceClassName(sourceClass);
  876. lr.setSourceMethodName(sourceMethod);
  877. lr.setThrown(thrown);
  878. doLog(lr);
  879. }
  880. //=======================================================================
  881. // Start of simple convenience methods using level names as method names
  882. //=======================================================================
  883. /**
  884. * Log a SEVERE message.
  885. * <p>
  886. * If the logger is currently enabled for the SEVERE message
  887. * level then the given message is forwarded to all the
  888. * registered output Handler objects.
  889. * <p>
  890. * @param msg The string message (or a key in the message catalog)
  891. */
  892. public void severe(String msg) {
  893. if (Level.SEVERE.intValue() < levelValue) {
  894. return;
  895. }
  896. log(Level.SEVERE, msg);
  897. }
  898. /**
  899. * Log a WARNING message.
  900. * <p>
  901. * If the logger is currently enabled for the WARNING message
  902. * level then the given message is forwarded to all the
  903. * registered output Handler objects.
  904. * <p>
  905. * @param msg The string message (or a key in the message catalog)
  906. */
  907. public void warning(String msg) {
  908. if (Level.WARNING.intValue() < levelValue) {
  909. return;
  910. }
  911. log(Level.WARNING, msg);
  912. }
  913. /**
  914. * Log an INFO message.
  915. * <p>
  916. * If the logger is currently enabled for the INFO message
  917. * level then the given message is forwarded to all the
  918. * registered output Handler objects.
  919. * <p>
  920. * @param msg The string message (or a key in the message catalog)
  921. */
  922. public void info(String msg) {
  923. if (Level.INFO.intValue() < levelValue) {
  924. return;
  925. }
  926. log(Level.INFO, msg);
  927. }
  928. /**
  929. * Log a CONFIG message.
  930. * <p>
  931. * If the logger is currently enabled for the CONFIG message
  932. * level then the given message is forwarded to all the
  933. * registered output Handler objects.
  934. * <p>
  935. * @param msg The string message (or a key in the message catalog)
  936. */
  937. public void config(String msg) {
  938. if (Level.CONFIG.intValue() < levelValue) {
  939. return;
  940. }
  941. log(Level.CONFIG, msg);
  942. }
  943. /**
  944. * Log a FINE message.
  945. * <p>
  946. * If the logger is currently enabled for the FINE message
  947. * level then the given message is forwarded to all the
  948. * registered output Handler objects.
  949. * <p>
  950. * @param msg The string message (or a key in the message catalog)
  951. */
  952. public void fine(String msg) {
  953. if (Level.FINE.intValue() < levelValue) {
  954. return;
  955. }
  956. log(Level.FINE, msg);
  957. }
  958. /**
  959. * Log a FINER message.
  960. * <p>
  961. * If the logger is currently enabled for the FINER message
  962. * level then the given message is forwarded to all the
  963. * registered output Handler objects.
  964. * <p>
  965. * @param msg The string message (or a key in the message catalog)
  966. */
  967. public void finer(String msg) {
  968. if (Level.FINER.intValue() < levelValue) {
  969. return;
  970. }
  971. log(Level.FINER, msg);
  972. }
  973. /**
  974. * Log a FINEST message.
  975. * <p>
  976. * If the logger is currently enabled for the FINEST message
  977. * level then the given message is forwarded to all the
  978. * registered output Handler objects.
  979. * <p>
  980. * @param msg The string message (or a key in the message catalog)
  981. */
  982. public void finest(String msg) {
  983. if (Level.FINEST.intValue() < levelValue) {
  984. return;
  985. }
  986. log(Level.FINEST, msg);
  987. }
  988. //================================================================
  989. // End of convenience methods
  990. //================================================================
  991. /**
  992. * Set the log level specifying which message levels will be
  993. * logged by this logger. Message levels lower than this
  994. * value will be discarded. The level value Level.OFF
  995. * can be used to turn off logging.
  996. * <p>
  997. * If the new level is null, it means that this node should
  998. * inherit its level from its nearest ancestor with a specific
  999. * (non-null) level value.
  1000. *
  1001. * @param newLevel the new value for the log level (may be null)
  1002. * @exception SecurityException if a security manager exists and if
  1003. * the caller does not have LoggingPermission("control").
  1004. */
  1005. public void setLevel(Level newLevel) throws SecurityException {
  1006. if (!anonymous) {
  1007. manager.checkAccess();
  1008. }
  1009. synchronized (treeLock) {
  1010. levelObject = newLevel;
  1011. updateEffectiveLevel();
  1012. }
  1013. }
  1014. /**
  1015. * Get the log Level that has been specified for this Logger.
  1016. * The result may be null, which means that this logger's
  1017. * effective level will be inherited from its parent.
  1018. *
  1019. * @return this Logger's level
  1020. */
  1021. public Level getLevel() {
  1022. return levelObject;
  1023. }
  1024. /**
  1025. * Check if a message of the given level would actually be logged
  1026. * by this logger. This check is based on the Loggers effective level,
  1027. * which may be inherited from its parent.
  1028. *
  1029. * @param level a message logging level
  1030. * @return true if the given message level is currently being logged.
  1031. */
  1032. public boolean isLoggable(Level level) {
  1033. if (level.intValue() < levelValue || levelValue == offValue) {
  1034. return false;
  1035. }
  1036. return true;
  1037. }
  1038. /**
  1039. * Get the name for this logger.
  1040. * @return logger name. Will be null for anonymous Loggers.
  1041. */
  1042. public String getName() {
  1043. return name;
  1044. }
  1045. /**
  1046. * Add a log Handler to receive logging messages.
  1047. * <p>
  1048. * By default, Loggers also send their output to their parent logger.
  1049. * Typically the root Logger is configured with a set of Handlers
  1050. * that essentially act as default handlers for all loggers.
  1051. *
  1052. * @param handler a logging Handler
  1053. * @exception SecurityException if a security manager exists and if
  1054. * the caller does not have LoggingPermission("control").
  1055. */
  1056. public synchronized void addHandler(Handler handler) throws SecurityException {
  1057. // Check for null handler
  1058. handler.getClass();
  1059. if (!anonymous) {
  1060. manager.checkAccess();
  1061. }
  1062. if (handlers == null) {
  1063. handlers = new ArrayList();
  1064. }
  1065. handlers.add(handler);
  1066. }
  1067. /**
  1068. * Remove a log Handler.
  1069. * <P>
  1070. * Returns silently if the given Handler is not found.
  1071. *
  1072. * @param handler a logging Handler
  1073. * @exception SecurityException if a security manager exists and if
  1074. * the caller does not have LoggingPermission("control").
  1075. */
  1076. public synchronized void removeHandler(Handler handler) throws SecurityException {
  1077. if (!anonymous) {
  1078. manager.checkAccess();
  1079. }
  1080. if (handler == null) {
  1081. throw new NullPointerException();
  1082. }
  1083. if (handlers == null) {
  1084. return;
  1085. }
  1086. handlers.remove(handler);
  1087. }
  1088. /**
  1089. * Get the Handlers associated with this logger.
  1090. * <p>
  1091. * @return an array of all registered Handlers
  1092. */
  1093. public synchronized Handler[] getHandlers() {
  1094. if (handlers == null) {
  1095. return emptyHandlers;
  1096. }
  1097. Handler result[] = new Handler[handlers.size()];
  1098. result = (Handler [])handlers.toArray(result);
  1099. return result;
  1100. }
  1101. /**
  1102. * Specify whether or not this logger should send its output
  1103. * to it's parent Logger. This means that any LogRecords will
  1104. * also be written to the parent's Handlers, and potentially
  1105. * to its parent, recursively up the namespace.
  1106. *
  1107. * @param useParentHandlers true if output is to be sent to the
  1108. * logger's parent.
  1109. * @exception SecurityException if a security manager exists and if
  1110. * the caller does not have LoggingPermission("control").
  1111. */
  1112. public synchronized void setUseParentHandlers(boolean useParentHandlers) {
  1113. if (!anonymous) {
  1114. manager.checkAccess();
  1115. }
  1116. this.useParentHandlers = useParentHandlers;
  1117. }
  1118. /**
  1119. * Discover whether or not this logger is sending its output
  1120. * to its parent logger.
  1121. *
  1122. * @return true if output is to be sent to the logger's parent
  1123. */
  1124. public synchronized boolean getUseParentHandlers() {
  1125. return useParentHandlers;
  1126. }
  1127. // Private utility method to map a resource bundle name to an
  1128. // actual resource bundle, using a simple one-entry cache.
  1129. // Returns null for a null name.
  1130. // May also return null if we can't find the resource bundle and
  1131. // there is no suitable previous cached value.
  1132. private synchronized ResourceBundle findResourceBundle(String name) {
  1133. // Return a null bundle for a null name.
  1134. if (name == null) {
  1135. return null;
  1136. }
  1137. Locale currentLocale = Locale.getDefault();
  1138. // Normally we should hit on our simple one entry cache.
  1139. if (catalog != null && currentLocale == catalogLocale
  1140. && name == catalogName) {
  1141. return catalog;
  1142. }
  1143. // Use the thread's context ClassLoader. If there isn't one,
  1144. // use the SystemClassloader.
  1145. ClassLoader cl = Thread.currentThread().getContextClassLoader();
  1146. if (cl == null) {
  1147. cl = ClassLoader.getSystemClassLoader();
  1148. }
  1149. try {
  1150. catalog = ResourceBundle.getBundle(name, currentLocale, cl);
  1151. catalogName = name;
  1152. catalogLocale = currentLocale;
  1153. return catalog;
  1154. } catch (MissingResourceException ex) {
  1155. // Woops. We can't find the ResourceBundle in the default
  1156. // ClassLoader. Drop through.
  1157. }
  1158. // Fall back to searching up the call stack and trying each
  1159. // calling ClassLoader.
  1160. for (int ix = 0; ; ix++) {
  1161. Class clz = sun.reflect.Reflection.getCallerClass(ix);
  1162. if (clz == null) {
  1163. break;
  1164. }
  1165. ClassLoader cl2 = clz.getClassLoader();
  1166. if (cl2 == null) {
  1167. cl2 = ClassLoader.getSystemClassLoader();
  1168. }
  1169. if (cl == cl2) {
  1170. // We've already checked this classloader.
  1171. continue;
  1172. }
  1173. cl = cl2;
  1174. try {
  1175. catalog = ResourceBundle.getBundle(name, currentLocale, cl);
  1176. catalogName = name;
  1177. catalogLocale = currentLocale;
  1178. return catalog;
  1179. } catch (MissingResourceException ex) {
  1180. // Ok, this one didn't work either.
  1181. // Drop through, and try the next one.
  1182. }
  1183. }
  1184. if (name.equals(catalogName)) {
  1185. // Return the previous cached value for that name.
  1186. // This may be null.
  1187. return catalog;
  1188. }
  1189. // Sorry, we're out of luck.
  1190. return null;
  1191. }
  1192. // Private utility method to initialize our one entry
  1193. // resource bundle cache.
  1194. // Note: for consistency reasons, we are careful to check
  1195. // that a suitable ResourceBundle exists before setting the
  1196. // ResourceBundleName.
  1197. private synchronized void setupResourceInfo(String name) {
  1198. if (name == null) {
  1199. return;
  1200. }
  1201. ResourceBundle rb = findResourceBundle(name);
  1202. if (rb == null) {
  1203. // We've failed to find an expected ResourceBundle.
  1204. throw new MissingResourceException("Can't find " + name + " bundle", name, "");
  1205. }
  1206. resourceBundleName = name;
  1207. }
  1208. /**
  1209. * Return the parent for this Logger.
  1210. * <p>
  1211. * This method returns the nearest extant parent in the namespace.
  1212. * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b"
  1213. * has been created but no logger "a.b.c" exists, then a call of
  1214. * getParent on the Logger "a.b.c.d" will return the Logger "a.b".
  1215. * <p>
  1216. * The result will be null if it is called on the root Logger
  1217. * in the namespace.
  1218. *
  1219. * @return nearest existing parent Logger
  1220. */
  1221. public Logger getParent() {
  1222. synchronized (treeLock) {
  1223. return parent;
  1224. }
  1225. }
  1226. /**
  1227. * Set the parent for this Logger. This method is used by
  1228. * the LogManager to update a Logger when the namespace changes.
  1229. * <p>
  1230. * It should not be called from application code.
  1231. * <p>
  1232. * @param parent the new parent logger
  1233. * @exception SecurityException if a security manager exists and if
  1234. * the caller does not have LoggingPermission("control").
  1235. */
  1236. public void setParent(Logger parent) {
  1237. if (parent == null) {
  1238. throw new NullPointerException();
  1239. }
  1240. manager.checkAccess();
  1241. doSetParent(parent);
  1242. }
  1243. // Private method to do the work for parenting a child
  1244. // Loggger onto a parent logger.
  1245. private void doSetParent(Logger newParent) {
  1246. // System.err.println("doSetParent \"" + getName() + "\" \""
  1247. // + newParent.getName() + "\"");
  1248. synchronized (treeLock) {
  1249. // Remove ourself from any previous parent.
  1250. if (parent != null) {
  1251. // assert parent.kids != null;
  1252. for (Iterator iter = parent.kids.iterator(); iter.hasNext(); ) {
  1253. WeakReference ref = (WeakReference) iter.next();
  1254. Logger kid = (Logger) ref.get();
  1255. if (kid == this) {
  1256. iter.remove();
  1257. break;
  1258. }
  1259. }
  1260. // We have now removed ourself from our parents' kids.
  1261. }
  1262. // Set our new parent.
  1263. parent = newParent;
  1264. if (parent.kids == null) {
  1265. parent.kids = new ArrayList(2);
  1266. }
  1267. parent.kids.add(new WeakReference(this));
  1268. // As a result of the reparenting, the effective level
  1269. // may have changed for us and our children.
  1270. updateEffectiveLevel();
  1271. }
  1272. }
  1273. // Recalculate the effective level for this node and
  1274. // recursively for our children.
  1275. private void updateEffectiveLevel() {
  1276. // assert Thread.holdsLock(treeLock);
  1277. // Figure out our current effective level.
  1278. int newLevelValue;
  1279. if (levelObject != null) {
  1280. newLevelValue = levelObject.intValue();
  1281. } else {
  1282. if (parent != null) {
  1283. newLevelValue = parent.levelValue;
  1284. } else {
  1285. // This may happen during initialization.
  1286. newLevelValue = Level.INFO.intValue();
  1287. }
  1288. }
  1289. // If our effective value hasn't changed, we're done.
  1290. if (levelValue == newLevelValue) {
  1291. return;
  1292. }
  1293. levelValue = newLevelValue;
  1294. // System.err.println("effective level: \"" + getName() + "\" := " + level);
  1295. // Recursively update the level on each of our kids.
  1296. if (kids != null) {
  1297. for (int i = 0; i < kids.size(); i++) {
  1298. WeakReference ref = (WeakReference)kids.get(i);
  1299. Logger kid = (Logger) ref.get();
  1300. if (kid != null) {
  1301. kid.updateEffectiveLevel();
  1302. }
  1303. }
  1304. }
  1305. }
  1306. // Private method to get the potentially inherited
  1307. // resource bundle name for this Logger.
  1308. // May return null
  1309. private String getEffectiveResourceBundleName() {
  1310. Logger target = this;
  1311. while (target != null) {
  1312. String rbn = target.getResourceBundleName();
  1313. if (rbn != null) {
  1314. return rbn;
  1315. }
  1316. target = target.getParent();
  1317. }
  1318. return null;
  1319. }
  1320. }