1. /*
  2. * @(#)Logger.java 1.45 04/02/24
  3. *
  4. * Copyright 2004 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 addition 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.45, 02/24/04
  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. * @throws NullPointerException if the name is null.
  215. */
  216. public static synchronized Logger getLogger(String name) {
  217. LogManager manager = LogManager.getLogManager();
  218. Logger result = manager.getLogger(name);
  219. if (result == null) {
  220. result = new Logger(name, null);
  221. manager.addLogger(result);
  222. result = manager.getLogger(name);
  223. }
  224. return result;
  225. }
  226. /**
  227. * Find or create a logger for a named subsystem. If a logger has
  228. * already been created with the given name it is returned. Otherwise
  229. * a new logger is created.
  230. * <p>
  231. * If a new logger is created its log level will be configured
  232. * based on the LogManager and it will configured to also send logging
  233. * output to its parent loggers Handlers. It will be registered in
  234. * the LogManager global namespace.
  235. * <p>
  236. * If the named Logger already exists and does not yet have a
  237. * localization resource bundle then the given resource bundle
  238. * name is used. If the named Logger already exists and has
  239. * a different resource bundle name then an IllegalArgumentException
  240. * is thrown.
  241. * <p>
  242. * @param name A name for the logger. This should
  243. * be a dot-separated name and should normally
  244. * be based on the package name or class name
  245. * of the subsystem, such as java.net
  246. * or javax.swing
  247. * @param resourceBundleName name of ResourceBundle to be used for localizing
  248. * messages for this logger. May be <CODE>null</CODE> if none of
  249. * the messages require localization.
  250. * @return a suitable Logger
  251. * @throws MissingResourceException if the named ResourceBundle cannot be found.
  252. * @throws IllegalArgumentException if the Logger already exists and uses
  253. * a different resource bundle name.
  254. * @throws NullPointerException if the name is null.
  255. */
  256. public static synchronized Logger getLogger(String name, String resourceBundleName) {
  257. LogManager manager = LogManager.getLogManager();
  258. Logger result = manager.getLogger(name);
  259. if (result == null) {
  260. // Create a new logger.
  261. // Note: we may get a MissingResourceException here.
  262. result = new Logger(name, resourceBundleName);
  263. manager.addLogger(result);
  264. result = manager.getLogger(name);
  265. }
  266. if (result.resourceBundleName == null) {
  267. // Note: we may get a MissingResourceException here.
  268. result.setupResourceInfo(resourceBundleName);
  269. } else if (!result.resourceBundleName.equals(resourceBundleName)) {
  270. throw new IllegalArgumentException(result.resourceBundleName +
  271. " != " + resourceBundleName);
  272. }
  273. return result;
  274. }
  275. /**
  276. * Create an anonymous Logger. The newly created Logger is not
  277. * registered in the LogManager namespace. There will be no
  278. * access checks on updates to the logger.
  279. * <p>
  280. * This factory method is primarily intended for use from applets.
  281. * Because the resulting Logger is anonymous it can be kept private
  282. * by the creating class. This removes the need for normal security
  283. * checks, which in turn allows untrusted applet code to update
  284. * the control state of the Logger. For example an applet can do
  285. * a setLevel or an addHandler on an anonymous Logger.
  286. * <p>
  287. * Even although the new logger is anonymous, it is configured
  288. * to have the root logger ("") as its parent. This means that
  289. * by default it inherits its effective level and handlers
  290. * from the root logger.
  291. * <p>
  292. *
  293. * @return a newly created private Logger
  294. */
  295. public static synchronized Logger getAnonymousLogger() {
  296. LogManager manager = LogManager.getLogManager();
  297. Logger result = new Logger(null, null);
  298. result.anonymous = true;
  299. Logger root = manager.getLogger("");
  300. result.doSetParent(root);
  301. return result;
  302. }
  303. /**
  304. * Create an anonymous Logger. The newly created Logger is not
  305. * registered in the LogManager namespace. There will be no
  306. * access checks on updates to the logger.
  307. * <p>
  308. * This factory method is primarily intended for use from applets.
  309. * Because the resulting Logger is anonymous it can be kept private
  310. * by the creating class. This removes the need for normal security
  311. * checks, which in turn allows untrusted applet code to update
  312. * the control state of the Logger. For example an applet can do
  313. * a setLevel or an addHandler on an anonymous Logger.
  314. * <p>
  315. * Even although the new logger is anonymous, it is configured
  316. * to have the root logger ("") as its parent. This means that
  317. * by default it inherits its effective level and handlers
  318. * from the root logger.
  319. * <p>
  320. * @param resourceBundleName name of ResourceBundle to be used for localizing
  321. * messages for this logger.
  322. * May be null if none of the messages require localization.
  323. * @return a newly created private Logger
  324. * @throws MissingResourceException if the named ResourceBundle cannot be found.
  325. */
  326. public static synchronized Logger getAnonymousLogger(String resourceBundleName) {
  327. LogManager manager = LogManager.getLogManager();
  328. Logger result = new Logger(null, resourceBundleName);
  329. result.anonymous = true;
  330. Logger root = manager.getLogger("");
  331. result.doSetParent(root);
  332. return result;
  333. }
  334. /**
  335. * Retrieve the localization resource bundle for this
  336. * logger for the current default locale. Note that if
  337. * the result is null, then the Logger will use a resource
  338. * bundle inherited from its parent.
  339. *
  340. * @return localization bundle (may be null)
  341. */
  342. public ResourceBundle getResourceBundle() {
  343. return findResourceBundle(getResourceBundleName());
  344. }
  345. /**
  346. * Retrieve the localization resource bundle name for this
  347. * logger. Note that if the result is null, then the Logger
  348. * will use a resource bundle name inherited from its parent.
  349. *
  350. * @return localization bundle name (may be null)
  351. */
  352. public String getResourceBundleName() {
  353. return resourceBundleName;
  354. }
  355. /**
  356. * Set a filter to control output on this Logger.
  357. * <P>
  358. * After passing the initial "level" check, the Logger will
  359. * call this Filter to check if a log record should really
  360. * be published.
  361. *
  362. * @param newFilter a filter object (may be null)
  363. * @exception SecurityException if a security manager exists and if
  364. * the caller does not have LoggingPermission("control").
  365. */
  366. public void setFilter(Filter newFilter) throws SecurityException {
  367. if (!anonymous) {
  368. manager.checkAccess();
  369. }
  370. filter = newFilter;
  371. }
  372. /**
  373. * Get the current filter for this Logger.
  374. *
  375. * @return a filter object (may be null)
  376. */
  377. public Filter getFilter() {
  378. return filter;
  379. }
  380. /**
  381. * Log a LogRecord.
  382. * <p>
  383. * All the other logging methods in this class call through
  384. * this method to actually perform any logging. Subclasses can
  385. * override this single method to capture all log activity.
  386. *
  387. * @param record the LogRecord to be published
  388. */
  389. public void log(LogRecord record) {
  390. if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
  391. return;
  392. }
  393. synchronized (this) {
  394. if (filter != null && !filter.isLoggable(record)) {
  395. return;
  396. }
  397. }
  398. // Post the LogRecord to all our Handlers, and then to
  399. // our parents' handlers, all the way up the tree.
  400. Logger logger = this;
  401. while (logger != null) {
  402. Handler targets[] = logger.getHandlers();
  403. if (targets != null) {
  404. for (int i = 0; i < targets.length; i++) {
  405. targets[i].publish(record);
  406. }
  407. }
  408. if (!logger.getUseParentHandlers()) {
  409. break;
  410. }
  411. logger = logger.getParent();
  412. }
  413. }
  414. // private support method for logging.
  415. // We fill in the logger name, resource bundle name, and
  416. // resource bundle and then call "void log(LogRecord)".
  417. private void doLog(LogRecord lr) {
  418. lr.setLoggerName(name);
  419. String ebname = getEffectiveResourceBundleName();
  420. if (ebname != null) {
  421. lr.setResourceBundleName(ebname);
  422. lr.setResourceBundle(findResourceBundle(ebname));
  423. }
  424. log(lr);
  425. }
  426. //================================================================
  427. // Start of convenience methods WITHOUT className and methodName
  428. //================================================================
  429. /**
  430. * Log a message, with no arguments.
  431. * <p>
  432. * If the logger is currently enabled for the given message
  433. * level then the given message is forwarded to all the
  434. * registered output Handler objects.
  435. * <p>
  436. * @param level One of the message level identifiers, e.g. SEVERE
  437. * @param msg The string message (or a key in the message catalog)
  438. */
  439. public void log(Level level, String msg) {
  440. if (level.intValue() < levelValue || levelValue == offValue) {
  441. return;
  442. }
  443. LogRecord lr = new LogRecord(level, msg);
  444. doLog(lr);
  445. }
  446. /**
  447. * Log a message, with one object parameter.
  448. * <p>
  449. * If the logger is currently enabled for the given message
  450. * level then a corresponding LogRecord is created and forwarded
  451. * to all the registered output Handler objects.
  452. * <p>
  453. * @param level One of the message level identifiers, e.g. SEVERE
  454. * @param msg The string message (or a key in the message catalog)
  455. * @param param1 parameter to the message
  456. */
  457. public void log(Level level, String msg, Object param1) {
  458. if (level.intValue() < levelValue || levelValue == offValue) {
  459. return;
  460. }
  461. LogRecord lr = new LogRecord(level, msg);
  462. Object params[] = { param1 };
  463. lr.setParameters(params);
  464. doLog(lr);
  465. }
  466. /**
  467. * Log a message, with an array of object arguments.
  468. * <p>
  469. * If the logger is currently enabled for the given message
  470. * level then a corresponding LogRecord is created and forwarded
  471. * to all the registered output Handler objects.
  472. * <p>
  473. * @param level One of the message level identifiers, e.g. SEVERE
  474. * @param msg The string message (or a key in the message catalog)
  475. * @param params array of parameters to the message
  476. */
  477. public void log(Level level, String msg, Object params[]) {
  478. if (level.intValue() < levelValue || levelValue == offValue) {
  479. return;
  480. }
  481. LogRecord lr = new LogRecord(level, msg);
  482. lr.setParameters(params);
  483. doLog(lr);
  484. }
  485. /**
  486. * Log a message, with associated Throwable information.
  487. * <p>
  488. * If the logger is currently enabled for the given message
  489. * level then the given arguments are stored in a LogRecord
  490. * which is forwarded to all registered output handlers.
  491. * <p>
  492. * Note that the thrown argument is stored in the LogRecord thrown
  493. * property, rather than the LogRecord parameters property. Thus is it
  494. * processed specially by output Formatters and is not treated
  495. * as a formatting parameter to the LogRecord message property.
  496. * <p>
  497. * @param level One of the message level identifiers, e.g. SEVERE
  498. * @param msg The string message (or a key in the message catalog)
  499. * @param thrown Throwable associated with log message.
  500. */
  501. public void log(Level level, String msg, Throwable thrown) {
  502. if (level.intValue() < levelValue || levelValue == offValue) {
  503. return;
  504. }
  505. LogRecord lr = new LogRecord(level, msg);
  506. lr.setThrown(thrown);
  507. doLog(lr);
  508. }
  509. //================================================================
  510. // Start of convenience methods WITH className and methodName
  511. //================================================================
  512. /**
  513. * Log a message, specifying source class and method,
  514. * with no arguments.
  515. * <p>
  516. * If the logger is currently enabled for the given message
  517. * level then the given message is forwarded to all the
  518. * registered output Handler objects.
  519. * <p>
  520. * @param level One of the message level identifiers, e.g. SEVERE
  521. * @param sourceClass name of class that issued the logging request
  522. * @param sourceMethod name of method that issued the logging request
  523. * @param msg The string message (or a key in the message catalog)
  524. */
  525. public void logp(Level level, String sourceClass, String sourceMethod, String msg) {
  526. if (level.intValue() < levelValue || levelValue == offValue) {
  527. return;
  528. }
  529. LogRecord lr = new LogRecord(level, msg);
  530. lr.setSourceClassName(sourceClass);
  531. lr.setSourceMethodName(sourceMethod);
  532. doLog(lr);
  533. }
  534. /**
  535. * Log a message, specifying source class and method,
  536. * with a single object parameter to the log message.
  537. * <p>
  538. * If the logger is currently enabled for the given message
  539. * level then a corresponding LogRecord is created and forwarded
  540. * to all the registered output Handler objects.
  541. * <p>
  542. * @param level One of the message level identifiers, e.g. SEVERE
  543. * @param sourceClass name of class that issued the logging request
  544. * @param sourceMethod name of method that issued the logging request
  545. * @param msg The string message (or a key in the message catalog)
  546. * @param param1 Parameter to the log message.
  547. */
  548. public void logp(Level level, String sourceClass, String sourceMethod,
  549. String msg, Object param1) {
  550. if (level.intValue() < levelValue || levelValue == offValue) {
  551. return;
  552. }
  553. LogRecord lr = new LogRecord(level, msg);
  554. lr.setSourceClassName(sourceClass);
  555. lr.setSourceMethodName(sourceMethod);
  556. Object params[] = { param1 };
  557. lr.setParameters(params);
  558. doLog(lr);
  559. }
  560. /**
  561. * Log a message, specifying source class and method,
  562. * with an array of object arguments.
  563. * <p>
  564. * If the logger is currently enabled for the given message
  565. * level then a corresponding LogRecord is created and forwarded
  566. * to all the registered output Handler objects.
  567. * <p>
  568. * @param level One of the message level identifiers, e.g. SEVERE
  569. * @param sourceClass name of class that issued the logging request
  570. * @param sourceMethod name of method that issued the logging request
  571. * @param msg The string message (or a key in the message catalog)
  572. * @param params Array of parameters to the message
  573. */
  574. public void logp(Level level, String sourceClass, String sourceMethod,
  575. String msg, Object params[]) {
  576. if (level.intValue() < levelValue || levelValue == offValue) {
  577. return;
  578. }
  579. LogRecord lr = new LogRecord(level, msg);
  580. lr.setSourceClassName(sourceClass);
  581. lr.setSourceMethodName(sourceMethod);
  582. lr.setParameters(params);
  583. doLog(lr);
  584. }
  585. /**
  586. * Log a message, specifying source class and method,
  587. * with associated Throwable information.
  588. * <p>
  589. * If the logger is currently enabled for the given message
  590. * level then the given arguments are stored in a LogRecord
  591. * which is forwarded to all registered output handlers.
  592. * <p>
  593. * Note that the thrown argument is stored in the LogRecord thrown
  594. * property, rather than the LogRecord parameters property. Thus is it
  595. * processed specially by output Formatters and is not treated
  596. * as a formatting parameter to the LogRecord message property.
  597. * <p>
  598. * @param level One of the message level identifiers, e.g. SEVERE
  599. * @param sourceClass name of class that issued the logging request
  600. * @param sourceMethod name of method that issued the logging request
  601. * @param msg The string message (or a key in the message catalog)
  602. * @param thrown Throwable associated with log message.
  603. */
  604. public void logp(Level level, String sourceClass, String sourceMethod,
  605. String msg, Throwable thrown) {
  606. if (level.intValue() < levelValue || levelValue == offValue) {
  607. return;
  608. }
  609. LogRecord lr = new LogRecord(level, msg);
  610. lr.setSourceClassName(sourceClass);
  611. lr.setSourceMethodName(sourceMethod);
  612. lr.setThrown(thrown);
  613. doLog(lr);
  614. }
  615. //=========================================================================
  616. // Start of convenience methods WITH className, methodName and bundle name.
  617. //=========================================================================
  618. // Private support method for logging for "logrb" methods.
  619. // We fill in the logger name, resource bundle name, and
  620. // resource bundle and then call "void log(LogRecord)".
  621. private void doLog(LogRecord lr, String rbname) {
  622. lr.setLoggerName(name);
  623. if (rbname != null) {
  624. lr.setResourceBundleName(rbname);
  625. lr.setResourceBundle(findResourceBundle(rbname));
  626. }
  627. log(lr);
  628. }
  629. /**
  630. * Log a message, specifying source class, method, and resource bundle name
  631. * with no arguments.
  632. * <p>
  633. * If the logger is currently enabled for the given message
  634. * level then the given message is forwarded to all the
  635. * registered output Handler objects.
  636. * <p>
  637. * The msg string is localized using the named resource bundle. If the
  638. * resource bundle name is null, or an empty String or invalid
  639. * then the msg string is not localized.
  640. * <p>
  641. * @param level One of the message level identifiers, e.g. SEVERE
  642. * @param sourceClass name of class that issued the logging request
  643. * @param sourceMethod name of method that issued the logging request
  644. * @param bundleName name of resource bundle to localize msg,
  645. * can be null
  646. * @param msg The string message (or a key in the message catalog)
  647. */
  648. public void logrb(Level level, String sourceClass, String sourceMethod,
  649. String bundleName, String msg) {
  650. if (level.intValue() < levelValue || levelValue == offValue) {
  651. return;
  652. }
  653. LogRecord lr = new LogRecord(level, msg);
  654. lr.setSourceClassName(sourceClass);
  655. lr.setSourceMethodName(sourceMethod);
  656. doLog(lr, bundleName);
  657. }
  658. /**
  659. * Log a message, specifying source class, method, and resource bundle name,
  660. * with a single object parameter to the log message.
  661. * <p>
  662. * If the logger is currently enabled for the given message
  663. * level then a corresponding LogRecord is created and forwarded
  664. * to all the registered output Handler objects.
  665. * <p>
  666. * The msg string is localized using the named resource bundle. If the
  667. * resource bundle name is null, or an empty String or invalid
  668. * then the msg string is not localized.
  669. * <p>
  670. * @param level One of the message level identifiers, e.g. SEVERE
  671. * @param sourceClass name of class that issued the logging request
  672. * @param sourceMethod name of method that issued the logging request
  673. * @param bundleName name of resource bundle to localize msg,
  674. * can be null
  675. * @param msg The string message (or a key in the message catalog)
  676. * @param param1 Parameter to the log message.
  677. */
  678. public void logrb(Level level, String sourceClass, String sourceMethod,
  679. String bundleName, String msg, Object param1) {
  680. if (level.intValue() < levelValue || levelValue == offValue) {
  681. return;
  682. }
  683. LogRecord lr = new LogRecord(level, msg);
  684. lr.setSourceClassName(sourceClass);
  685. lr.setSourceMethodName(sourceMethod);
  686. Object params[] = { param1 };
  687. lr.setParameters(params);
  688. doLog(lr, bundleName);
  689. }
  690. /**
  691. * Log a message, specifying source class, method, and resource bundle name,
  692. * with an array of object arguments.
  693. * <p>
  694. * If the logger is currently enabled for the given message
  695. * level then a corresponding LogRecord is created and forwarded
  696. * to all the registered output Handler objects.
  697. * <p>
  698. * The msg string is localized using the named resource bundle. If the
  699. * resource bundle name is null, or an empty String or invalid
  700. * then the msg string is not localized.
  701. * <p>
  702. * @param level One of the message level identifiers, e.g. SEVERE
  703. * @param sourceClass name of class that issued the logging request
  704. * @param sourceMethod name of method that issued the logging request
  705. * @param bundleName name of resource bundle to localize msg,
  706. * can be null.
  707. * @param msg The string message (or a key in the message catalog)
  708. * @param params Array of parameters to the message
  709. */
  710. public void logrb(Level level, String sourceClass, String sourceMethod,
  711. String bundleName, String msg, Object params[]) {
  712. if (level.intValue() < levelValue || levelValue == offValue) {
  713. return;
  714. }
  715. LogRecord lr = new LogRecord(level, msg);
  716. lr.setSourceClassName(sourceClass);
  717. lr.setSourceMethodName(sourceMethod);
  718. lr.setParameters(params);
  719. doLog(lr, bundleName);
  720. }
  721. /**
  722. * Log a message, specifying source class, method, and resource bundle name,
  723. * with associated Throwable information.
  724. * <p>
  725. * If the logger is currently enabled for the given message
  726. * level then the given arguments are stored in a LogRecord
  727. * which is forwarded to all registered output handlers.
  728. * <p>
  729. * The msg string is localized using the named resource bundle. If the
  730. * resource bundle name is null, or an empty String or invalid
  731. * then the msg string is not localized.
  732. * <p>
  733. * Note that the thrown argument is stored in the LogRecord thrown
  734. * property, rather than the LogRecord parameters property. Thus is it
  735. * processed specially by output Formatters and is not treated
  736. * as a formatting parameter to the LogRecord message property.
  737. * <p>
  738. * @param level One of the message level identifiers, e.g. SEVERE
  739. * @param sourceClass name of class that issued the logging request
  740. * @param sourceMethod name of method that issued the logging request
  741. * @param bundleName name of resource bundle to localize msg,
  742. * can be null
  743. * @param msg The string message (or a key in the message catalog)
  744. * @param thrown Throwable associated with log message.
  745. */
  746. public void logrb(Level level, String sourceClass, String sourceMethod,
  747. String bundleName, String msg, Throwable thrown) {
  748. if (level.intValue() < levelValue || levelValue == offValue) {
  749. return;
  750. }
  751. LogRecord lr = new LogRecord(level, msg);
  752. lr.setSourceClassName(sourceClass);
  753. lr.setSourceMethodName(sourceMethod);
  754. lr.setThrown(thrown);
  755. doLog(lr, bundleName);
  756. }
  757. //======================================================================
  758. // Start of convenience methods for logging method entries and returns.
  759. //======================================================================
  760. /**
  761. * Log a method entry.
  762. * <p>
  763. * This is a convenience method that can be used to log entry
  764. * to a method. A LogRecord with message "ENTRY", log level
  765. * FINER, and the given sourceMethod and sourceClass is logged.
  766. * <p>
  767. * @param sourceClass name of class that issued the logging request
  768. * @param sourceMethod name of method that is being entered
  769. */
  770. public void entering(String sourceClass, String sourceMethod) {
  771. if (Level.FINER.intValue() < levelValue) {
  772. return;
  773. }
  774. logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
  775. }
  776. /**
  777. * Log a method entry, with one parameter.
  778. * <p>
  779. * This is a convenience method that can be used to log entry
  780. * to a method. A LogRecord with message "ENTRY {0}", log level
  781. * FINER, and the given sourceMethod, sourceClass, and parameter
  782. * is logged.
  783. * <p>
  784. * @param sourceClass name of class that issued the logging request
  785. * @param sourceMethod name of method that is being entered
  786. * @param param1 parameter to the method being entered
  787. */
  788. public void entering(String sourceClass, String sourceMethod, Object param1) {
  789. if (Level.FINER.intValue() < levelValue) {
  790. return;
  791. }
  792. Object params[] = { param1 };
  793. logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", params);
  794. }
  795. /**
  796. * Log a method entry, with an array of parameters.
  797. * <p>
  798. * This is a convenience method that can be used to log entry
  799. * to a method. A LogRecord with message "ENTRY" (followed by a
  800. * format {N} indicator for each entry in the parameter array),
  801. * log level FINER, and the given sourceMethod, sourceClass, and
  802. * parameters is logged.
  803. * <p>
  804. * @param sourceClass name of class that issued the logging request
  805. * @param sourceMethod name of method that is being entered
  806. * @param params array of parameters to the method being entered
  807. */
  808. public void entering(String sourceClass, String sourceMethod, Object params[]) {
  809. if (Level.FINER.intValue() < levelValue) {
  810. return;
  811. }
  812. String msg = "ENTRY";
  813. if (params == null ) {
  814. logp(Level.FINER, sourceClass, sourceMethod, msg);
  815. return;
  816. }
  817. for (int i = 0; i < params.length; i++) {
  818. msg = msg + " {" + i + "}";
  819. }
  820. logp(Level.FINER, sourceClass, sourceMethod, msg, params);
  821. }
  822. /**
  823. * Log a method return.
  824. * <p>
  825. * This is a convenience method that can be used to log returning
  826. * from a method. A LogRecord with message "RETURN", log level
  827. * FINER, and the given sourceMethod and sourceClass is logged.
  828. * <p>
  829. * @param sourceClass name of class that issued the logging request
  830. * @param sourceMethod name of the method
  831. */
  832. public void exiting(String sourceClass, String sourceMethod) {
  833. if (Level.FINER.intValue() < levelValue) {
  834. return;
  835. }
  836. logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
  837. }
  838. /**
  839. * Log a method return, with result object.
  840. * <p>
  841. * This is a convenience method that can be used to log returning
  842. * from a method. A LogRecord with message "RETURN {0}", log level
  843. * FINER, and the gives sourceMethod, sourceClass, and result
  844. * object is logged.
  845. * <p>
  846. * @param sourceClass name of class that issued the logging request
  847. * @param sourceMethod name of the method
  848. * @param result Object that is being returned
  849. */
  850. public void exiting(String sourceClass, String sourceMethod, Object result) {
  851. if (Level.FINER.intValue() < levelValue) {
  852. return;
  853. }
  854. Object params[] = { result };
  855. logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
  856. }
  857. /**
  858. * Log throwing an exception.
  859. * <p>
  860. * This is a convenience method to log that a method is
  861. * terminating by throwing an exception. The logging is done
  862. * using the FINER level.
  863. * <p>
  864. * If the logger is currently enabled for the given message
  865. * level then the given arguments are stored in a LogRecord
  866. * which is forwarded to all registered output handlers. The
  867. * LogRecord's message is set to "THROW".
  868. * <p>
  869. * Note that the thrown argument is stored in the LogRecord thrown
  870. * property, rather than the LogRecord parameters property. Thus is it
  871. * processed specially by output Formatters and is not treated
  872. * as a formatting parameter to the LogRecord message property.
  873. * <p>
  874. * @param sourceClass name of class that issued the logging request
  875. * @param sourceMethod name of the method.
  876. * @param thrown The Throwable that is being thrown.
  877. */
  878. public void throwing(String sourceClass, String sourceMethod, Throwable thrown) {
  879. if (Level.FINER.intValue() < levelValue || levelValue == offValue ) {
  880. return;
  881. }
  882. LogRecord lr = new LogRecord(Level.FINER, "THROW");
  883. lr.setSourceClassName(sourceClass);
  884. lr.setSourceMethodName(sourceMethod);
  885. lr.setThrown(thrown);
  886. doLog(lr);
  887. }
  888. //=======================================================================
  889. // Start of simple convenience methods using level names as method names
  890. //=======================================================================
  891. /**
  892. * Log a SEVERE message.
  893. * <p>
  894. * If the logger is currently enabled for the SEVERE message
  895. * level then the given message is forwarded to all the
  896. * registered output Handler objects.
  897. * <p>
  898. * @param msg The string message (or a key in the message catalog)
  899. */
  900. public void severe(String msg) {
  901. if (Level.SEVERE.intValue() < levelValue) {
  902. return;
  903. }
  904. log(Level.SEVERE, msg);
  905. }
  906. /**
  907. * Log a WARNING message.
  908. * <p>
  909. * If the logger is currently enabled for the WARNING message
  910. * level then the given message is forwarded to all the
  911. * registered output Handler objects.
  912. * <p>
  913. * @param msg The string message (or a key in the message catalog)
  914. */
  915. public void warning(String msg) {
  916. if (Level.WARNING.intValue() < levelValue) {
  917. return;
  918. }
  919. log(Level.WARNING, msg);
  920. }
  921. /**
  922. * Log an INFO message.
  923. * <p>
  924. * If the logger is currently enabled for the INFO message
  925. * level then the given message is forwarded to all the
  926. * registered output Handler objects.
  927. * <p>
  928. * @param msg The string message (or a key in the message catalog)
  929. */
  930. public void info(String msg) {
  931. if (Level.INFO.intValue() < levelValue) {
  932. return;
  933. }
  934. log(Level.INFO, msg);
  935. }
  936. /**
  937. * Log a CONFIG message.
  938. * <p>
  939. * If the logger is currently enabled for the CONFIG message
  940. * level then the given message is forwarded to all the
  941. * registered output Handler objects.
  942. * <p>
  943. * @param msg The string message (or a key in the message catalog)
  944. */
  945. public void config(String msg) {
  946. if (Level.CONFIG.intValue() < levelValue) {
  947. return;
  948. }
  949. log(Level.CONFIG, msg);
  950. }
  951. /**
  952. * Log a FINE message.
  953. * <p>
  954. * If the logger is currently enabled for the FINE message
  955. * level then the given message is forwarded to all the
  956. * registered output Handler objects.
  957. * <p>
  958. * @param msg The string message (or a key in the message catalog)
  959. */
  960. public void fine(String msg) {
  961. if (Level.FINE.intValue() < levelValue) {
  962. return;
  963. }
  964. log(Level.FINE, msg);
  965. }
  966. /**
  967. * Log a FINER message.
  968. * <p>
  969. * If the logger is currently enabled for the FINER message
  970. * level then the given message is forwarded to all the
  971. * registered output Handler objects.
  972. * <p>
  973. * @param msg The string message (or a key in the message catalog)
  974. */
  975. public void finer(String msg) {
  976. if (Level.FINER.intValue() < levelValue) {
  977. return;
  978. }
  979. log(Level.FINER, msg);
  980. }
  981. /**
  982. * Log a FINEST message.
  983. * <p>
  984. * If the logger is currently enabled for the FINEST message
  985. * level then the given message is forwarded to all the
  986. * registered output Handler objects.
  987. * <p>
  988. * @param msg The string message (or a key in the message catalog)
  989. */
  990. public void finest(String msg) {
  991. if (Level.FINEST.intValue() < levelValue) {
  992. return;
  993. }
  994. log(Level.FINEST, msg);
  995. }
  996. //================================================================
  997. // End of convenience methods
  998. //================================================================
  999. /**
  1000. * Set the log level specifying which message levels will be
  1001. * logged by this logger. Message levels lower than this
  1002. * value will be discarded. The level value Level.OFF
  1003. * can be used to turn off logging.
  1004. * <p>
  1005. * If the new level is null, it means that this node should
  1006. * inherit its level from its nearest ancestor with a specific
  1007. * (non-null) level value.
  1008. *
  1009. * @param newLevel the new value for the log level (may be null)
  1010. * @exception SecurityException if a security manager exists and if
  1011. * the caller does not have LoggingPermission("control").
  1012. */
  1013. public void setLevel(Level newLevel) throws SecurityException {
  1014. if (!anonymous) {
  1015. manager.checkAccess();
  1016. }
  1017. synchronized (treeLock) {
  1018. levelObject = newLevel;
  1019. updateEffectiveLevel();
  1020. }
  1021. }
  1022. /**
  1023. * Get the log Level that has been specified for this Logger.
  1024. * The result may be null, which means that this logger's
  1025. * effective level will be inherited from its parent.
  1026. *
  1027. * @return this Logger's level
  1028. */
  1029. public Level getLevel() {
  1030. return levelObject;
  1031. }
  1032. /**
  1033. * Check if a message of the given level would actually be logged
  1034. * by this logger. This check is based on the Loggers effective level,
  1035. * which may be inherited from its parent.
  1036. *
  1037. * @param level a message logging level
  1038. * @return true if the given message level is currently being logged.
  1039. */
  1040. public boolean isLoggable(Level level) {
  1041. if (level.intValue() < levelValue || levelValue == offValue) {
  1042. return false;
  1043. }
  1044. return true;
  1045. }
  1046. /**
  1047. * Get the name for this logger.
  1048. * @return logger name. Will be null for anonymous Loggers.
  1049. */
  1050. public String getName() {
  1051. return name;
  1052. }
  1053. /**
  1054. * Add a log Handler to receive logging messages.
  1055. * <p>
  1056. * By default, Loggers also send their output to their parent logger.
  1057. * Typically the root Logger is configured with a set of Handlers
  1058. * that essentially act as default handlers for all loggers.
  1059. *
  1060. * @param handler a logging Handler
  1061. * @exception SecurityException if a security manager exists and if
  1062. * the caller does not have LoggingPermission("control").
  1063. */
  1064. public synchronized void addHandler(Handler handler) throws SecurityException {
  1065. // Check for null handler
  1066. handler.getClass();
  1067. if (!anonymous) {
  1068. manager.checkAccess();
  1069. }
  1070. if (handlers == null) {
  1071. handlers = new ArrayList();
  1072. }
  1073. handlers.add(handler);
  1074. }
  1075. /**
  1076. * Remove a log Handler.
  1077. * <P>
  1078. * Returns silently if the given Handler is not found or is null
  1079. *
  1080. * @param handler a logging Handler
  1081. * @exception SecurityException if a security manager exists and if
  1082. * the caller does not have LoggingPermission("control").
  1083. */
  1084. public synchronized void removeHandler(Handler handler) throws SecurityException {
  1085. if (!anonymous) {
  1086. manager.checkAccess();
  1087. }
  1088. if (handler == null) {
  1089. return;
  1090. }
  1091. if (handlers == null) {
  1092. return;
  1093. }
  1094. handlers.remove(handler);
  1095. }
  1096. /**
  1097. * Get the Handlers associated with this logger.
  1098. * <p>
  1099. * @return an array of all registered Handlers
  1100. */
  1101. public synchronized Handler[] getHandlers() {
  1102. if (handlers == null) {
  1103. return emptyHandlers;
  1104. }
  1105. Handler result[] = new Handler[handlers.size()];
  1106. result = (Handler [])handlers.toArray(result);
  1107. return result;
  1108. }
  1109. /**
  1110. * Specify whether or not this logger should send its output
  1111. * to it's parent Logger. This means that any LogRecords will
  1112. * also be written to the parent's Handlers, and potentially
  1113. * to its parent, recursively up the namespace.
  1114. *
  1115. * @param useParentHandlers true if output is to be sent to the
  1116. * logger's parent.
  1117. * @exception SecurityException if a security manager exists and if
  1118. * the caller does not have LoggingPermission("control").
  1119. */
  1120. public synchronized void setUseParentHandlers(boolean useParentHandlers) {
  1121. if (!anonymous) {
  1122. manager.checkAccess();
  1123. }
  1124. this.useParentHandlers = useParentHandlers;
  1125. }
  1126. /**
  1127. * Discover whether or not this logger is sending its output
  1128. * to its parent logger.
  1129. *
  1130. * @return true if output is to be sent to the logger's parent
  1131. */
  1132. public synchronized boolean getUseParentHandlers() {
  1133. return useParentHandlers;
  1134. }
  1135. // Private utility method to map a resource bundle name to an
  1136. // actual resource bundle, using a simple one-entry cache.
  1137. // Returns null for a null name.
  1138. // May also return null if we can't find the resource bundle and
  1139. // there is no suitable previous cached value.
  1140. private synchronized ResourceBundle findResourceBundle(String name) {
  1141. // Return a null bundle for a null name.
  1142. if (name == null) {
  1143. return null;
  1144. }
  1145. Locale currentLocale = Locale.getDefault();
  1146. // Normally we should hit on our simple one entry cache.
  1147. if (catalog != null && currentLocale == catalogLocale
  1148. && name == catalogName) {
  1149. return catalog;
  1150. }
  1151. // Use the thread's context ClassLoader. If there isn't one,
  1152. // use the SystemClassloader.
  1153. ClassLoader cl = Thread.currentThread().getContextClassLoader();
  1154. if (cl == null) {
  1155. cl = ClassLoader.getSystemClassLoader();
  1156. }
  1157. try {
  1158. catalog = ResourceBundle.getBundle(name, currentLocale, cl);
  1159. catalogName = name;
  1160. catalogLocale = currentLocale;
  1161. return catalog;
  1162. } catch (MissingResourceException ex) {
  1163. // Woops. We can't find the ResourceBundle in the default
  1164. // ClassLoader. Drop through.
  1165. }
  1166. // Fall back to searching up the call stack and trying each
  1167. // calling ClassLoader.
  1168. for (int ix = 0; ; ix++) {
  1169. Class clz = sun.reflect.Reflection.getCallerClass(ix);
  1170. if (clz == null) {
  1171. break;
  1172. }
  1173. ClassLoader cl2 = clz.getClassLoader();
  1174. if (cl2 == null) {
  1175. cl2 = ClassLoader.getSystemClassLoader();
  1176. }
  1177. if (cl == cl2) {
  1178. // We've already checked this classloader.
  1179. continue;
  1180. }
  1181. cl = cl2;
  1182. try {
  1183. catalog = ResourceBundle.getBundle(name, currentLocale, cl);
  1184. catalogName = name;
  1185. catalogLocale = currentLocale;
  1186. return catalog;
  1187. } catch (MissingResourceException ex) {
  1188. // Ok, this one didn't work either.
  1189. // Drop through, and try the next one.
  1190. }
  1191. }
  1192. if (name.equals(catalogName)) {
  1193. // Return the previous cached value for that name.
  1194. // This may be null.
  1195. return catalog;
  1196. }
  1197. // Sorry, we're out of luck.
  1198. return null;
  1199. }
  1200. // Private utility method to initialize our one entry
  1201. // resource bundle cache.
  1202. // Note: for consistency reasons, we are careful to check
  1203. // that a suitable ResourceBundle exists before setting the
  1204. // ResourceBundleName.
  1205. private synchronized void setupResourceInfo(String name) {
  1206. if (name == null) {
  1207. return;
  1208. }
  1209. ResourceBundle rb = findResourceBundle(name);
  1210. if (rb == null) {
  1211. // We've failed to find an expected ResourceBundle.
  1212. throw new MissingResourceException("Can't find " + name + " bundle", name, "");
  1213. }
  1214. resourceBundleName = name;
  1215. }
  1216. /**
  1217. * Return the parent for this Logger.
  1218. * <p>
  1219. * This method returns the nearest extant parent in the namespace.
  1220. * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b"
  1221. * has been created but no logger "a.b.c" exists, then a call of
  1222. * getParent on the Logger "a.b.c.d" will return the Logger "a.b".
  1223. * <p>
  1224. * The result will be null if it is called on the root Logger
  1225. * in the namespace.
  1226. *
  1227. * @return nearest existing parent Logger
  1228. */
  1229. public Logger getParent() {
  1230. synchronized (treeLock) {
  1231. return parent;
  1232. }
  1233. }
  1234. /**
  1235. * Set the parent for this Logger. This method is used by
  1236. * the LogManager to update a Logger when the namespace changes.
  1237. * <p>
  1238. * It should not be called from application code.
  1239. * <p>
  1240. * @param parent the new parent logger
  1241. * @exception SecurityException if a security manager exists and if
  1242. * the caller does not have LoggingPermission("control").
  1243. */
  1244. public void setParent(Logger parent) {
  1245. if (parent == null) {
  1246. throw new NullPointerException();
  1247. }
  1248. manager.checkAccess();
  1249. doSetParent(parent);
  1250. }
  1251. // Private method to do the work for parenting a child
  1252. // Logger onto a parent logger.
  1253. private void doSetParent(Logger newParent) {
  1254. // System.err.println("doSetParent \"" + getName() + "\" \""
  1255. // + newParent.getName() + "\"");
  1256. synchronized (treeLock) {
  1257. // Remove ourself from any previous parent.
  1258. if (parent != null) {
  1259. // assert parent.kids != null;
  1260. for (Iterator iter = parent.kids.iterator(); iter.hasNext(); ) {
  1261. WeakReference ref = (WeakReference) iter.next();
  1262. Logger kid = (Logger) ref.get();
  1263. if (kid == this) {
  1264. iter.remove();
  1265. break;
  1266. }
  1267. }
  1268. // We have now removed ourself from our parents' kids.
  1269. }
  1270. // Set our new parent.
  1271. parent = newParent;
  1272. if (parent.kids == null) {
  1273. parent.kids = new ArrayList(2);
  1274. }
  1275. parent.kids.add(new WeakReference(this));
  1276. // As a result of the reparenting, the effective level
  1277. // may have changed for us and our children.
  1278. updateEffectiveLevel();
  1279. }
  1280. }
  1281. // Recalculate the effective level for this node and
  1282. // recursively for our children.
  1283. private void updateEffectiveLevel() {
  1284. // assert Thread.holdsLock(treeLock);
  1285. // Figure out our current effective level.
  1286. int newLevelValue;
  1287. if (levelObject != null) {
  1288. newLevelValue = levelObject.intValue();
  1289. } else {
  1290. if (parent != null) {
  1291. newLevelValue = parent.levelValue;
  1292. } else {
  1293. // This may happen during initialization.
  1294. newLevelValue = Level.INFO.intValue();
  1295. }
  1296. }
  1297. // If our effective value hasn't changed, we're done.
  1298. if (levelValue == newLevelValue) {
  1299. return;
  1300. }
  1301. levelValue = newLevelValue;
  1302. // System.err.println("effective level: \"" + getName() + "\" := " + level);
  1303. // Recursively update the level on each of our kids.
  1304. if (kids != null) {
  1305. for (int i = 0; i < kids.size(); i++) {
  1306. WeakReference ref = (WeakReference)kids.get(i);
  1307. Logger kid = (Logger) ref.get();
  1308. if (kid != null) {
  1309. kid.updateEffectiveLevel();
  1310. }
  1311. }
  1312. }
  1313. }
  1314. // Private method to get the potentially inherited
  1315. // resource bundle name for this Logger.
  1316. // May return null
  1317. private String getEffectiveResourceBundleName() {
  1318. Logger target = this;
  1319. while (target != null) {
  1320. String rbn = target.getResourceBundleName();
  1321. if (rbn != null) {
  1322. return rbn;
  1323. }
  1324. target = target.getParent();
  1325. }
  1326. return null;
  1327. }
  1328. }