KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > util > logging > Logger


1 /*
2  * @(#)Logger.java 1.46 06/04/12
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8
9 package java.util.logging;
10
11 import java.util.*;
12 import java.security.*;
13 import java.lang.ref.WeakReference JavaDoc;
14
15 /**
16  * A Logger object is used to log messages for a specific
17  * system or application component. Loggers are normally named,
18  * using a hierarchical dot-separated namespace. Logger names
19  * can be arbitrary strings, but they should normally be based on
20  * the package name or class name of the logged component, such
21  * as java.net or javax.swing. In addition it is possible to create
22  * "anonymous" Loggers that are not stored in the Logger namespace.
23  * <p>
24  * Logger objects may be obtained by calls on one of the getLogger
25  * factory methods. These will either create a new Logger or
26  * return a suitable existing Logger.
27  * <p>
28  * Logging messages will be forwarded to registered Handler
29  * objects, which can forward the messages to a variety of
30  * destinations, including consoles, files, OS logs, etc.
31  * <p>
32  * Each Logger keeps track of a "parent" Logger, which is its
33  * nearest existing ancestor in the Logger namespace.
34  * <p>
35  * Each Logger has a "Level" associated with it. This reflects
36  * a minimum Level that this logger cares about. If a Logger's
37  * level is set to <tt>null</tt>, then its effective level is inherited
38  * from its parent, which may in turn obtain it recursively from its
39  * parent, and so on up the tree.
40  * <p>
41  * The log level can be configured based on the properties from the
42  * logging configuration file, as described in the description
43  * of the LogManager class. However it may also be dynamically changed
44  * by calls on the Logger.setLevel method. If a logger's level is
45  * changed the change may also affect child loggers, since any child
46  * logger that has <tt>null</tt> as its level will inherit its
47  * effective level from its parent.
48  * <p>
49  * On each logging call the Logger initially performs a cheap
50  * check of the request level (e.g. SEVERE or FINE) against the
51  * effective log level of the logger. If the request level is
52  * lower than the log level, the logging call returns immediately.
53  * <p>
54  * After passing this initial (cheap) test, the Logger will allocate
55  * a LogRecord to describe the logging message. It will then call a
56  * Filter (if present) to do a more detailed check on whether the
57  * record should be published. If that passes it will then publish
58  * the LogRecord to its output Handlers. By default, loggers also
59  * publish to their parent's Handlers, recursively up the tree.
60  * <p>
61  * Each Logger may have a ResourceBundle name associated with it.
62  * The named bundle will be used for localizing logging messages.
63  * If a Logger does not have its own ResourceBundle name, then
64  * it will inherit the ResourceBundle name from its parent,
65  * recursively up the tree.
66  * <p>
67  * Most of the logger output methods take a "msg" argument. This
68  * msg argument may be either a raw value or a localization key.
69  * During formatting, if the logger has (or inherits) a localization
70  * ResourceBundle and if the ResourceBundle has a mapping for the msg
71  * string, then the msg string is replaced by the localized value.
72  * Otherwise the original msg string is used. Typically, formatters use
73  * java.text.MessageFormat style formatting to format parameters, so
74  * for example a format string "{0} {1}" would format two parameters
75  * as strings.
76  * <p>
77  * When mapping ResourceBundle names to ResourceBundles, the Logger
78  * will first try to use the Thread's ContextClassLoader. If that
79  * is null it will try the SystemClassLoader instead. As a temporary
80  * transition feature in the initial implementation, if the Logger is
81  * unable to locate a ResourceBundle from the ContextClassLoader or
82  * SystemClassLoader the Logger will also search up the class stack
83  * and use successive calling ClassLoaders to try to locate a ResourceBundle.
84  * (This call stack search is to allow containers to transition to
85  * using ContextClassLoaders and is likely to be removed in future
86  * versions.)
87  * <p>
88  * Formatting (including localization) is the responsibility of
89  * the output Handler, which will typically call a Formatter.
90  * <p>
91  * Note that formatting need not occur synchronously. It may be delayed
92  * until a LogRecord is actually written to an external sink.
93  * <p>
94  * The logging methods are grouped in five main categories:
95  * <ul>
96  * <li><p>
97  * There are a set of "log" methods that take a log level, a message
98  * string, and optionally some parameters to the message string.
99  * <li><p>
100  * There are a set of "logp" methods (for "log precise") that are
101  * like the "log" methods, but also take an explicit source class name
102  * and method name.
103  * <li><p>
104  * There are a set of "logrb" method (for "log with resource bundle")
105  * that are like the "logp" method, but also take an explicit resource
106  * bundle name for use in localizing the log message.
107  * <li><p>
108  * There are convenience methods for tracing method entries (the
109  * "entering" methods), method returns (the "exiting" methods) and
110  * throwing exceptions (the "throwing" methods).
111  * <li><p>
112  * Finally, there are a set of convenience methods for use in the
113  * very simplest cases, when a developer simply wants to log a
114  * simple string at a given log level. These methods are named
115  * after the standard Level names ("severe", "warning", "info", etc.)
116  * and take a single argument, a message string.
117  * </ul>
118  * <p>
119  * For the methods that do not take an explicit source name and
120  * method name, the Logging framework will make a "best effort"
121  * to determine which class and method called into the logging method.
122  * However, it is important to realize that this automatically inferred
123  * information may only be approximate (or may even be quite wrong!).
124  * Virtual machines are allowed to do extensive optimizations when
125  * JITing and may entirely remove stack frames, making it impossible
126  * to reliably locate the calling class and method.
127  * <P>
128  * All methods on Logger are multi-thread safe.
129  * <p>
130  * <b>Subclassing Information:</b> Note that a LogManager class may
131  * provide its own implementation of named Loggers for any point in
132  * the namespace. Therefore, any subclasses of Logger (unless they
133  * are implemented in conjunction with a new LogManager class) should
134  * take care to obtain a Logger instance from the LogManager class and
135  * should delegate operations such as "isLoggable" and "log(LogRecord)"
136  * to that instance. Note that in order to intercept all logging
137  * output, subclasses need only override the log(LogRecord) method.
138  * All the other logging methods are implemented as calls on this
139  * log(LogRecord) method.
140  *
141  * @version 1.46, 04/12/06
142  * @since 1.4
143  */

144
145
146 public class Logger {
147     private static final Handler JavaDoc emptyHandlers[] = new Handler JavaDoc[0];
148     private static final int offValue = Level.OFF.intValue();
149     private LogManager JavaDoc manager;
150     private String JavaDoc name;
151     private ArrayList handlers;
152     private String JavaDoc resourceBundleName;
153     private boolean useParentHandlers = true;
154     private Filter JavaDoc filter;
155     private boolean anonymous;
156
157     private ResourceBundle catalog; // Cached resource bundle
158
private String JavaDoc catalogName; // name associated with catalog
159
private Locale catalogLocale; // locale associated with catalog
160

161     // The fields relating to parent-child relationships and levels
162
// are managed under a separate lock, the treeLock.
163
private static Object JavaDoc treeLock = new Object JavaDoc();
164     // We keep weak references from parents to children, but strong
165
// references from children to parents.
166
private Logger JavaDoc parent; // our nearest parent.
167
private ArrayList kids; // WeakReferences to loggers that have us as parent
168
private Level JavaDoc levelObject;
169     private volatile int levelValue; // current effective level value
170

171     /**
172      * The "global" Logger object is provided as a convenience to developers
173      * who are making casual use of the Logging package. Developers
174      * who are making serious use of the logging package (for example
175      * in products) should create and use their own Logger objects,
176      * with appropriate names, so that logging can be controlled on a
177      * suitable per-Logger granularity.
178      * <p>
179      * The global logger is initialized by calling Logger.getLogger("global").
180      */

181     public static final Logger JavaDoc global = new Logger JavaDoc("global");
182
183     /**
184      * Protected method to construct a logger for a named subsystem.
185      * <p>
186      * The logger will be initially configured with a null Level
187      * and with useParentHandlers true.
188      *
189      * @param name A name for the logger. This should
190      * be a dot-separated name and should normally
191      * be based on the package name or class name
192      * of the subsystem, such as java.net
193      * or javax.swing. It may be null for anonymous Loggers.
194      * @param resourceBundleName name of ResourceBundle to be used for localizing
195      * messages for this logger. May be null if none
196      * of the messages require localization.
197      * @throws MissingResourceException if the ResourceBundleName is non-null and
198      * no corresponding resource can be found.
199      */

200     protected Logger(String JavaDoc name, String JavaDoc resourceBundleName) {
201         this.manager = LogManager.getLogManager();
202     if (resourceBundleName != null) {
203         // Note: we may get a MissingResourceException here.
204
setupResourceInfo(resourceBundleName);
205     }
206     this.name = name;
207     levelValue = Level.INFO.intValue();
208     }
209
210     // This constructor is used only to create the global Logger.
211
// It is needed to break a cyclic dependence between the LogManager
212
// and Logger static initializers causing deadlocks.
213
private Logger(String JavaDoc name) {
214         // The manager field is not initialized here.
215
this.name = name;
216     levelValue = Level.INFO.intValue();
217     }
218
219     // It is called from the LogManager.<clinit> to complete
220
// initialization of the global Logger.
221
void setLogManager(LogManager JavaDoc manager) {
222     this.manager = manager;
223     }
224
225     private void checkAccess() throws SecurityException JavaDoc {
226     if (!anonymous) {
227         if (manager == null) {
228                 // Complete initialization of the global Logger.
229
manager = LogManager.getLogManager();
230             }
231         manager.checkAccess();
232     }
233     }
234
235     /**
236      * Find or create a logger for a named subsystem. If a logger has
237      * already been created with the given name it is returned. Otherwise
238      * a new logger is created.
239      * <p>
240      * If a new logger is created its log level will be configured
241      * based on the LogManager configuration and it will configured
242      * to also send logging output to its parent's handlers. It will
243      * be registered in the LogManager global namespace.
244      *
245      * @param name A name for the logger. This should
246      * be a dot-separated name and should normally
247      * be based on the package name or class name
248      * of the subsystem, such as java.net
249      * or javax.swing
250      * @return a suitable Logger
251      * @throws NullPointerException if the name is null.
252      */

253     public static synchronized Logger JavaDoc getLogger(String JavaDoc name) {
254     LogManager JavaDoc manager = LogManager.getLogManager();
255     Logger JavaDoc result = manager.getLogger(name);
256     if (result == null) {
257         result = new Logger JavaDoc(name, null);
258         manager.addLogger(result);
259         result = manager.getLogger(name);
260     }
261     return result;
262     }
263
264     /**
265      * Find or create a logger for a named subsystem. If a logger has
266      * already been created with the given name it is returned. Otherwise
267      * a new logger is created.
268      * <p>
269      * If a new logger is created its log level will be configured
270      * based on the LogManager and it will configured to also send logging
271      * output to its parent loggers Handlers. It will be registered in
272      * the LogManager global namespace.
273      * <p>
274      * If the named Logger already exists and does not yet have a
275      * localization resource bundle then the given resource bundle
276      * name is used. If the named Logger already exists and has
277      * a different resource bundle name then an IllegalArgumentException
278      * is thrown.
279      * <p>
280      * @param name A name for the logger. This should
281      * be a dot-separated name and should normally
282      * be based on the package name or class name
283      * of the subsystem, such as java.net
284      * or javax.swing
285      * @param resourceBundleName name of ResourceBundle to be used for localizing
286      * messages for this logger. May be <CODE>null</CODE> if none of
287      * the messages require localization.
288      * @return a suitable Logger
289      * @throws MissingResourceException if the named ResourceBundle cannot be found.
290      * @throws IllegalArgumentException if the Logger already exists and uses
291      * a different resource bundle name.
292      * @throws NullPointerException if the name is null.
293      */

294     public static synchronized Logger JavaDoc getLogger(String JavaDoc name, String JavaDoc resourceBundleName) {
295     LogManager JavaDoc manager = LogManager.getLogManager();
296     Logger JavaDoc result = manager.getLogger(name);
297     if (result == null) {
298         // Create a new logger.
299
// Note: we may get a MissingResourceException here.
300
result = new Logger JavaDoc(name, resourceBundleName);
301         manager.addLogger(result);
302         result = manager.getLogger(name);
303     }
304     if (result.resourceBundleName == null) {
305         // Note: we may get a MissingResourceException here.
306
result.setupResourceInfo(resourceBundleName);
307     } else if (!result.resourceBundleName.equals(resourceBundleName)) {
308         throw new IllegalArgumentException JavaDoc(result.resourceBundleName +
309                 " != " + resourceBundleName);
310     }
311     return result;
312     }
313
314
315     /**
316      * Create an anonymous Logger. The newly created Logger is not
317      * registered in the LogManager namespace. There will be no
318      * access checks on updates to the logger.
319      * <p>
320      * This factory method is primarily intended for use from applets.
321      * Because the resulting Logger is anonymous it can be kept private
322      * by the creating class. This removes the need for normal security
323      * checks, which in turn allows untrusted applet code to update
324      * the control state of the Logger. For example an applet can do
325      * a setLevel or an addHandler on an anonymous Logger.
326      * <p>
327      * Even although the new logger is anonymous, it is configured
328      * to have the root logger ("") as its parent. This means that
329      * by default it inherits its effective level and handlers
330      * from the root logger.
331      * <p>
332      *
333      * @return a newly created private Logger
334      */

335     public static synchronized Logger JavaDoc getAnonymousLogger() {
336     LogManager JavaDoc manager = LogManager.getLogManager();
337     Logger JavaDoc result = new Logger JavaDoc(null, null);
338     result.anonymous = true;
339     Logger JavaDoc root = manager.getLogger("");
340     result.doSetParent(root);
341     return result;
342     }
343
344     /**
345      * Create an anonymous Logger. The newly created Logger is not
346      * registered in the LogManager namespace. There will be no
347      * access checks on updates to the logger.
348      * <p>
349      * This factory method is primarily intended for use from applets.
350      * Because the resulting Logger is anonymous it can be kept private
351      * by the creating class. This removes the need for normal security
352      * checks, which in turn allows untrusted applet code to update
353      * the control state of the Logger. For example an applet can do
354      * a setLevel or an addHandler on an anonymous Logger.
355      * <p>
356      * Even although the new logger is anonymous, it is configured
357      * to have the root logger ("") as its parent. This means that
358      * by default it inherits its effective level and handlers
359      * from the root logger.
360      * <p>
361      * @param resourceBundleName name of ResourceBundle to be used for localizing
362      * messages for this logger.
363      * May be null if none of the messages require localization.
364      * @return a newly created private Logger
365      * @throws MissingResourceException if the named ResourceBundle cannot be found.
366      */

367     public static synchronized Logger JavaDoc getAnonymousLogger(String JavaDoc resourceBundleName) {
368     LogManager JavaDoc manager = LogManager.getLogManager();
369     Logger JavaDoc result = new Logger JavaDoc(null, resourceBundleName);
370     result.anonymous = true;
371     Logger JavaDoc root = manager.getLogger("");
372     result.doSetParent(root);
373     return result;
374     }
375
376     /**
377      * Retrieve the localization resource bundle for this
378      * logger for the current default locale. Note that if
379      * the result is null, then the Logger will use a resource
380      * bundle inherited from its parent.
381      *
382      * @return localization bundle (may be null)
383      */

384     public ResourceBundle getResourceBundle() {
385     return findResourceBundle(getResourceBundleName());
386     }
387
388     /**
389      * Retrieve the localization resource bundle name for this
390      * logger. Note that if the result is null, then the Logger
391      * will use a resource bundle name inherited from its parent.
392      *
393      * @return localization bundle name (may be null)
394      */

395     public String JavaDoc getResourceBundleName() {
396     return resourceBundleName;
397     }
398
399     /**
400      * Set a filter to control output on this Logger.
401      * <P>
402      * After passing the initial "level" check, the Logger will
403      * call this Filter to check if a log record should really
404      * be published.
405      *
406      * @param newFilter a filter object (may be null)
407      * @exception SecurityException if a security manager exists and if
408      * the caller does not have LoggingPermission("control").
409      */

410     public void setFilter(Filter JavaDoc newFilter) throws SecurityException JavaDoc {
411     checkAccess();
412     filter = newFilter;
413     }
414
415     /**
416      * Get the current filter for this Logger.
417      *
418      * @return a filter object (may be null)
419      */

420     public Filter JavaDoc getFilter() {
421     return filter;
422     }
423
424     /**
425      * Log a LogRecord.
426      * <p>
427      * All the other logging methods in this class call through
428      * this method to actually perform any logging. Subclasses can
429      * override this single method to capture all log activity.
430      *
431      * @param record the LogRecord to be published
432      */

433     public void log(LogRecord JavaDoc record) {
434     if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
435         return;
436     }
437     synchronized (this) {
438         if (filter != null && !filter.isLoggable(record)) {
439             return;
440         }
441     }
442
443     // Post the LogRecord to all our Handlers, and then to
444
// our parents' handlers, all the way up the tree.
445

446     Logger JavaDoc logger = this;
447     while (logger != null) {
448         Handler JavaDoc targets[] = logger.getHandlers();
449
450         if (targets != null) {
451             for (int i = 0; i < targets.length; i++) {
452             targets[i].publish(record);
453         }
454         }
455
456         if (!logger.getUseParentHandlers()) {
457         break;
458         }
459
460         logger = logger.getParent();
461     }
462     }
463
464     // private support method for logging.
465
// We fill in the logger name, resource bundle name, and
466
// resource bundle and then call "void log(LogRecord)".
467
private void doLog(LogRecord JavaDoc lr) {
468     lr.setLoggerName(name);
469     String JavaDoc ebname = getEffectiveResourceBundleName();
470     if (ebname != null) {
471         lr.setResourceBundleName(ebname);
472         lr.setResourceBundle(findResourceBundle(ebname));
473     }
474     log(lr);
475     }
476
477
478     //================================================================
479
// Start of convenience methods WITHOUT className and methodName
480
//================================================================
481

482     /**
483      * Log a message, with no arguments.
484      * <p>
485      * If the logger is currently enabled for the given message
486      * level then the given message is forwarded to all the
487      * registered output Handler objects.
488      * <p>
489      * @param level One of the message level identifiers, e.g. SEVERE
490      * @param msg The string message (or a key in the message catalog)
491      */

492     public void log(Level JavaDoc level, String JavaDoc msg) {
493     if (level.intValue() < levelValue || levelValue == offValue) {
494         return;
495     }
496     LogRecord JavaDoc lr = new LogRecord JavaDoc(level, msg);
497     doLog(lr);
498     }
499
500     /**
501      * Log a message, with one object parameter.
502      * <p>
503      * If the logger is currently enabled for the given message
504      * level then a corresponding LogRecord is created and forwarded
505      * to all the registered output Handler objects.
506      * <p>
507      * @param level One of the message level identifiers, e.g. SEVERE
508      * @param msg The string message (or a key in the message catalog)
509      * @param param1 parameter to the message
510      */

511     public void log(Level JavaDoc level, String JavaDoc msg, Object JavaDoc param1) {
512     if (level.intValue() < levelValue || levelValue == offValue) {
513         return;
514     }
515     LogRecord JavaDoc lr = new LogRecord JavaDoc(level, msg);
516     Object JavaDoc params[] = { param1 };
517     lr.setParameters(params);
518     doLog(lr);
519     }
520
521     /**
522      * Log a message, with an array of object arguments.
523      * <p>
524      * If the logger is currently enabled for the given message
525      * level then a corresponding LogRecord is created and forwarded
526      * to all the registered output Handler objects.
527      * <p>
528      * @param level One of the message level identifiers, e.g. SEVERE
529      * @param msg The string message (or a key in the message catalog)
530      * @param params array of parameters to the message
531      */

532     public void log(Level JavaDoc level, String JavaDoc msg, Object JavaDoc params[]) {
533     if (level.intValue() < levelValue || levelValue == offValue) {
534         return;
535     }
536     LogRecord JavaDoc lr = new LogRecord JavaDoc(level, msg);
537     lr.setParameters(params);
538     doLog(lr);
539     }
540
541     /**
542      * Log a message, with associated Throwable information.
543      * <p>
544      * If the logger is currently enabled for the given message
545      * level then the given arguments are stored in a LogRecord
546      * which is forwarded to all registered output handlers.
547      * <p>
548      * Note that the thrown argument is stored in the LogRecord thrown
549      * property, rather than the LogRecord parameters property. Thus is it
550      * processed specially by output Formatters and is not treated
551      * as a formatting parameter to the LogRecord message property.
552      * <p>
553      * @param level One of the message level identifiers, e.g. SEVERE
554      * @param msg The string message (or a key in the message catalog)
555      * @param thrown Throwable associated with log message.
556      */

557     public void log(Level JavaDoc level, String JavaDoc msg, Throwable JavaDoc thrown) {
558     if (level.intValue() < levelValue || levelValue == offValue) {
559         return;
560     }
561     LogRecord JavaDoc lr = new LogRecord JavaDoc(level, msg);
562     lr.setThrown(thrown);
563     doLog(lr);
564     }
565
566     //================================================================
567
// Start of convenience methods WITH className and methodName
568
//================================================================
569

570     /**
571      * Log a message, specifying source class and method,
572      * with no arguments.
573      * <p>
574      * If the logger is currently enabled for the given message
575      * level then the given message is forwarded to all the
576      * registered output Handler objects.
577      * <p>
578      * @param level One of the message level identifiers, e.g. SEVERE
579      * @param sourceClass name of class that issued the logging request
580      * @param sourceMethod name of method that issued the logging request
581      * @param msg The string message (or a key in the message catalog)
582      */

583     public void logp(Level JavaDoc level, String JavaDoc sourceClass, String JavaDoc sourceMethod, String JavaDoc msg) {
584     if (level.intValue() < levelValue || levelValue == offValue) {
585         return;
586     }
587     LogRecord JavaDoc lr = new LogRecord JavaDoc(level, msg);
588     lr.setSourceClassName(sourceClass);
589     lr.setSourceMethodName(sourceMethod);
590     doLog(lr);
591     }
592
593     /**
594      * Log a message, specifying source class and method,
595      * with a single object parameter to the log message.
596      * <p>
597      * If the logger is currently enabled for the given message
598      * level then a corresponding LogRecord is created and forwarded
599      * to all the registered output Handler objects.
600      * <p>
601      * @param level One of the message level identifiers, e.g. SEVERE
602      * @param sourceClass name of class that issued the logging request
603      * @param sourceMethod name of method that issued the logging request
604      * @param msg The string message (or a key in the message catalog)
605      * @param param1 Parameter to the log message.
606      */

607     public void logp(Level JavaDoc level, String JavaDoc sourceClass, String JavaDoc sourceMethod,
608                         String JavaDoc msg, Object JavaDoc param1) {
609     if (level.intValue() < levelValue || levelValue == offValue) {
610         return;
611     }
612     LogRecord JavaDoc lr = new LogRecord JavaDoc(level, msg);
613     lr.setSourceClassName(sourceClass);
614     lr.setSourceMethodName(sourceMethod);
615     Object JavaDoc params[] = { param1 };
616     lr.setParameters(params);
617     doLog(lr);
618     }
619
620     /**
621      * Log a message, specifying source class and method,
622      * with an array of object arguments.
623      * <p>
624      * If the logger is currently enabled for the given message
625      * level then a corresponding LogRecord is created and forwarded
626      * to all the registered output Handler objects.
627      * <p>
628      * @param level One of the message level identifiers, e.g. SEVERE
629      * @param sourceClass name of class that issued the logging request
630      * @param sourceMethod name of method that issued the logging request
631      * @param msg The string message (or a key in the message catalog)
632      * @param params Array of parameters to the message
633      */

634     public void logp(Level JavaDoc level, String JavaDoc sourceClass, String JavaDoc sourceMethod,
635                         String JavaDoc msg, Object JavaDoc params[]) {
636     if (level.intValue() < levelValue || levelValue == offValue) {
637         return;
638     }
639     LogRecord JavaDoc lr = new LogRecord JavaDoc(level, msg);
640     lr.setSourceClassName(sourceClass);
641     lr.setSourceMethodName(sourceMethod);
642     lr.setParameters(params);
643     doLog(lr);
644     }
645
646     /**
647      * Log a message, specifying source class and method,
648      * with associated Throwable information.
649      * <p>
650      * If the logger is currently enabled for the given message
651      * level then the given arguments are stored in a LogRecord
652      * which is forwarded to all registered output handlers.
653      * <p>
654      * Note that the thrown argument is stored in the LogRecord thrown
655      * property, rather than the LogRecord parameters property. Thus is it
656      * processed specially by output Formatters and is not treated
657      * as a formatting parameter to the LogRecord message property.
658      * <p>
659      * @param level One of the message level identifiers, e.g. SEVERE
660      * @param sourceClass name of class that issued the logging request
661      * @param sourceMethod name of method that issued the logging request
662      * @param msg The string message (or a key in the message catalog)
663      * @param thrown Throwable associated with log message.
664      */

665     public void logp(Level JavaDoc level, String JavaDoc sourceClass, String JavaDoc sourceMethod,
666                             String JavaDoc msg, Throwable JavaDoc thrown) {
667     if (level.intValue() < levelValue || levelValue == offValue) {
668         return;
669     }
670     LogRecord JavaDoc lr = new LogRecord JavaDoc(level, msg);
671     lr.setSourceClassName(sourceClass);
672     lr.setSourceMethodName(sourceMethod);
673     lr.setThrown(thrown);
674     doLog(lr);
675     }
676
677
678     //=========================================================================
679
// Start of convenience methods WITH className, methodName and bundle name.
680
//=========================================================================
681

682     // Private support method for logging for "logrb" methods.
683
// We fill in the logger name, resource bundle name, and
684
// resource bundle and then call "void log(LogRecord)".
685
private void doLog(LogRecord JavaDoc lr, String JavaDoc rbname) {
686     lr.setLoggerName(name);
687     if (rbname != null) {
688         lr.setResourceBundleName(rbname);
689         lr.setResourceBundle(findResourceBundle(rbname));
690     }
691     log(lr);
692     }
693
694     /**
695      * Log a message, specifying source class, method, and resource bundle name
696      * with no arguments.
697      * <p>
698      * If the logger is currently enabled for the given message
699      * level then the given message is forwarded to all the
700      * registered output Handler objects.
701      * <p>
702      * The msg string is localized using the named resource bundle. If the
703      * resource bundle name is null, or an empty String or invalid
704      * then the msg string is not localized.
705      * <p>
706      * @param level One of the message level identifiers, e.g. SEVERE
707      * @param sourceClass name of class that issued the logging request
708      * @param sourceMethod name of method that issued the logging request
709      * @param bundleName name of resource bundle to localize msg,
710      * can be null
711      * @param msg The string message (or a key in the message catalog)
712      */

713
714     public void logrb(Level JavaDoc level, String JavaDoc sourceClass, String JavaDoc sourceMethod,
715                 String JavaDoc bundleName, String JavaDoc msg) {
716     if (level.intValue() < levelValue || levelValue == offValue) {
717         return;
718     }
719     LogRecord JavaDoc lr = new LogRecord JavaDoc(level, msg);
720     lr.setSourceClassName(sourceClass);
721     lr.setSourceMethodName(sourceMethod);
722     doLog(lr, bundleName);
723     }
724
725     /**
726      * Log a message, specifying source class, method, and resource bundle name,
727      * with a single object parameter to the log message.
728      * <p>
729      * If the logger is currently enabled for the given message
730      * level then a corresponding LogRecord is created and forwarded
731      * to all the registered output Handler objects.
732      * <p>
733      * The msg string is localized using the named resource bundle. If the
734      * resource bundle name is null, or an empty String or invalid
735      * then the msg string is not localized.
736      * <p>
737      * @param level One of the message level identifiers, e.g. SEVERE
738      * @param sourceClass name of class that issued the logging request
739      * @param sourceMethod name of method that issued the logging request
740      * @param bundleName name of resource bundle to localize msg,
741      * can be null
742      * @param msg The string message (or a key in the message catalog)
743      * @param param1 Parameter to the log message.
744      */

745     public void logrb(Level JavaDoc level, String JavaDoc sourceClass, String JavaDoc sourceMethod,
746                 String JavaDoc bundleName, String JavaDoc msg, Object JavaDoc param1) {
747     if (level.intValue() < levelValue || levelValue == offValue) {
748         return;
749     }
750     LogRecord JavaDoc lr = new LogRecord JavaDoc(level, msg);
751     lr.setSourceClassName(sourceClass);
752     lr.setSourceMethodName(sourceMethod);
753     Object JavaDoc params[] = { param1 };
754     lr.setParameters(params);
755     doLog(lr, bundleName);
756     }
757
758     /**
759      * Log a message, specifying source class, method, and resource bundle name,
760      * with an array of object arguments.
761      * <p>
762      * If the logger is currently enabled for the given message
763      * level then a corresponding LogRecord is created and forwarded
764      * to all the registered output Handler objects.
765      * <p>
766      * The msg string is localized using the named resource bundle. If the
767      * resource bundle name is null, or an empty String or invalid
768      * then the msg string is not localized.
769      * <p>
770      * @param level One of the message level identifiers, e.g. SEVERE
771      * @param sourceClass name of class that issued the logging request
772      * @param sourceMethod name of method that issued the logging request
773      * @param bundleName name of resource bundle to localize msg,
774      * can be null.
775      * @param msg The string message (or a key in the message catalog)
776      * @param params Array of parameters to the message
777      */

778     public void logrb(Level JavaDoc level, String JavaDoc sourceClass, String JavaDoc sourceMethod,
779                 String JavaDoc bundleName, String JavaDoc msg, Object JavaDoc params[]) {
780     if (level.intValue() < levelValue || levelValue == offValue) {
781         return;
782     }
783     LogRecord JavaDoc lr = new LogRecord JavaDoc(level, msg);
784     lr.setSourceClassName(sourceClass);
785     lr.setSourceMethodName(sourceMethod);
786     lr.setParameters(params);
787     doLog(lr, bundleName);
788     }
789
790     /**
791      * Log a message, specifying source class, method, and resource bundle name,
792      * with associated Throwable information.
793      * <p>
794      * If the logger is currently enabled for the given message
795      * level then the given arguments are stored in a LogRecord
796      * which is forwarded to all registered output handlers.
797      * <p>
798      * The msg string is localized using the named resource bundle. If the
799      * resource bundle name is null, or an empty String or invalid
800      * then the msg string is not localized.
801      * <p>
802      * Note that the thrown argument is stored in the LogRecord thrown
803      * property, rather than the LogRecord parameters property. Thus is it
804      * processed specially by output Formatters and is not treated
805      * as a formatting parameter to the LogRecord message property.
806      * <p>
807      * @param level One of the message level identifiers, e.g. SEVERE
808      * @param sourceClass name of class that issued the logging request
809      * @param sourceMethod name of method that issued the logging request
810      * @param bundleName name of resource bundle to localize msg,
811      * can be null
812      * @param msg The string message (or a key in the message catalog)
813      * @param thrown Throwable associated with log message.
814      */

815     public void logrb(Level JavaDoc level, String JavaDoc sourceClass, String JavaDoc sourceMethod,
816                     String JavaDoc bundleName, String JavaDoc msg, Throwable JavaDoc thrown) {
817     if (level.intValue() < levelValue || levelValue == offValue) {
818         return;
819     }
820     LogRecord JavaDoc lr = new LogRecord JavaDoc(level, msg);
821     lr.setSourceClassName(sourceClass);
822     lr.setSourceMethodName(sourceMethod);
823     lr.setThrown(thrown);
824     doLog(lr, bundleName);
825     }
826
827
828     //======================================================================
829
// Start of convenience methods for logging method entries and returns.
830
//======================================================================
831

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

842     public void entering(String JavaDoc sourceClass, String JavaDoc sourceMethod) {
843     if (Level.FINER.intValue() < levelValue) {
844         return;
845     }
846     logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
847     }
848
849     /**
850      * Log a method entry, with one parameter.
851      * <p>
852      * This is a convenience method that can be used to log entry
853      * to a method. A LogRecord with message "ENTRY {0}", log level
854      * FINER, and the given sourceMethod, sourceClass, and parameter
855      * is logged.
856      * <p>
857      * @param sourceClass name of class that issued the logging request
858      * @param sourceMethod name of method that is being entered
859      * @param param1 parameter to the method being entered
860      */

861     public void entering(String JavaDoc sourceClass, String JavaDoc sourceMethod, Object JavaDoc param1) {
862     if (Level.FINER.intValue() < levelValue) {
863         return;
864     }
865     Object JavaDoc params[] = { param1 };
866     logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", params);
867     }
868
869     /**
870      * Log a method entry, with an array of parameters.
871      * <p>
872      * This is a convenience method that can be used to log entry
873      * to a method. A LogRecord with message "ENTRY" (followed by a
874      * format {N} indicator for each entry in the parameter array),
875      * log level FINER, and the given sourceMethod, sourceClass, and
876      * parameters is logged.
877      * <p>
878      * @param sourceClass name of class that issued the logging request
879      * @param sourceMethod name of method that is being entered
880      * @param params array of parameters to the method being entered
881      */

882     public void entering(String JavaDoc sourceClass, String JavaDoc sourceMethod, Object JavaDoc params[]) {
883     if (Level.FINER.intValue() < levelValue) {
884         return;
885     }
886     String JavaDoc msg = "ENTRY";
887     if (params == null ) {
888        logp(Level.FINER, sourceClass, sourceMethod, msg);
889        return;
890     }
891     for (int i = 0; i < params.length; i++) {
892         msg = msg + " {" + i + "}";
893     }
894     logp(Level.FINER, sourceClass, sourceMethod, msg, params);
895     }
896
897     /**
898      * Log a method return.
899      * <p>
900      * This is a convenience method that can be used to log returning
901      * from a method. A LogRecord with message "RETURN", log level
902      * FINER, and the given sourceMethod and sourceClass is logged.
903      * <p>
904      * @param sourceClass name of class that issued the logging request
905      * @param sourceMethod name of the method
906      */

907     public void exiting(String JavaDoc sourceClass, String JavaDoc sourceMethod) {
908     if (Level.FINER.intValue() < levelValue) {
909         return;
910     }
911     logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
912     }
913
914
915     /**
916      * Log a method return, with result object.
917      * <p>
918      * This is a convenience method that can be used to log returning
919      * from a method. A LogRecord with message "RETURN {0}", log level
920      * FINER, and the gives sourceMethod, sourceClass, and result
921      * object is logged.
922      * <p>
923      * @param sourceClass name of class that issued the logging request
924      * @param sourceMethod name of the method
925      * @param result Object that is being returned
926      */

927     public void exiting(String JavaDoc sourceClass, String JavaDoc sourceMethod, Object JavaDoc result) {
928     if (Level.FINER.intValue() < levelValue) {
929         return;
930     }
931     Object JavaDoc params[] = { result };
932     logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
933     }
934
935     /**
936      * Log throwing an exception.
937      * <p>
938      * This is a convenience method to log that a method is
939      * terminating by throwing an exception. The logging is done
940      * using the FINER level.
941      * <p>
942      * If the logger is currently enabled for the given message
943      * level then the given arguments are stored in a LogRecord
944      * which is forwarded to all registered output handlers. The
945      * LogRecord's message is set to "THROW".
946      * <p>
947      * Note that the thrown argument is stored in the LogRecord thrown
948      * property, rather than the LogRecord parameters property. Thus is it
949      * processed specially by output Formatters and is not treated
950      * as a formatting parameter to the LogRecord message property.
951      * <p>
952      * @param sourceClass name of class that issued the logging request
953      * @param sourceMethod name of the method.
954      * @param thrown The Throwable that is being thrown.
955      */

956     public void throwing(String JavaDoc sourceClass, String JavaDoc sourceMethod, Throwable JavaDoc thrown) {
957     if (Level.FINER.intValue() < levelValue || levelValue == offValue ) {
958         return;
959     }
960     LogRecord JavaDoc lr = new LogRecord JavaDoc(Level.FINER, "THROW");
961     lr.setSourceClassName(sourceClass);
962     lr.setSourceMethodName(sourceMethod);
963     lr.setThrown(thrown);
964     doLog(lr);
965     }
966
967     //=======================================================================
968
// Start of simple convenience methods using level names as method names
969
//=======================================================================
970

971     /**
972      * Log a SEVERE message.
973      * <p>
974      * If the logger is currently enabled for the SEVERE message
975      * level then the given message is forwarded to all the
976      * registered output Handler objects.
977      * <p>
978      * @param msg The string message (or a key in the message catalog)
979      */

980     public void severe(String JavaDoc msg) {
981     if (Level.SEVERE.intValue() < levelValue) {
982         return;
983     }
984     log(Level.SEVERE, msg);
985     }
986
987     /**
988      * Log a WARNING message.
989      * <p>
990      * If the logger is currently enabled for the WARNING message
991      * level then the given message is forwarded to all the
992      * registered output Handler objects.
993      * <p>
994      * @param msg The string message (or a key in the message catalog)
995      */

996     public void warning(String JavaDoc msg) {
997     if (Level.WARNING.intValue() < levelValue) {
998         return;
999     }
1000    log(Level.WARNING, msg);
1001    }
1002
1003    /**
1004     * Log an INFO message.
1005     * <p>
1006     * If the logger is currently enabled for the INFO message
1007     * level then the given message is forwarded to all the
1008     * registered output Handler objects.
1009     * <p>
1010     * @param msg The string message (or a key in the message catalog)
1011     */

1012    public void info(String JavaDoc msg) {
1013    if (Level.INFO.intValue() < levelValue) {
1014        return;
1015    }
1016    log(Level.INFO, msg);
1017    }
1018
1019    /**
1020     * Log a CONFIG message.
1021     * <p>
1022     * If the logger is currently enabled for the CONFIG message
1023     * level then the given message is forwarded to all the
1024     * registered output Handler objects.
1025     * <p>
1026     * @param msg The string message (or a key in the message catalog)
1027     */

1028    public void config(String JavaDoc msg) {
1029    if (Level.CONFIG.intValue() < levelValue) {
1030        return;
1031    }
1032    log(Level.CONFIG, msg);
1033    }
1034
1035    /**
1036     * Log a FINE message.
1037     * <p>
1038     * If the logger is currently enabled for the FINE message
1039     * level then the given message is forwarded to all the
1040     * registered output Handler objects.
1041     * <p>
1042     * @param msg The string message (or a key in the message catalog)
1043     */

1044    public void fine(String JavaDoc msg) {
1045    if (Level.FINE.intValue() < levelValue) {
1046        return;
1047    }
1048    log(Level.FINE, msg);
1049    }
1050
1051    /**
1052     * Log a FINER message.
1053     * <p>
1054     * If the logger is currently enabled for the FINER message
1055     * level then the given message is forwarded to all the
1056     * registered output Handler objects.
1057     * <p>
1058     * @param msg The string message (or a key in the message catalog)
1059     */

1060    public void finer(String JavaDoc msg) {
1061    if (Level.FINER.intValue() < levelValue) {
1062        return;
1063    }
1064    log(Level.FINER, msg);
1065    }
1066
1067    /**
1068     * Log a FINEST message.
1069     * <p>
1070     * If the logger is currently enabled for the FINEST message
1071     * level then the given message is forwarded to all the
1072     * registered output Handler objects.
1073     * <p>
1074     * @param msg The string message (or a key in the message catalog)
1075     */

1076    public void finest(String JavaDoc msg) {
1077    if (Level.FINEST.intValue() < levelValue) {
1078        return;
1079    }
1080    log(Level.FINEST, msg);
1081    }
1082
1083    //================================================================
1084
// End of convenience methods
1085
//================================================================
1086

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

1101    public void setLevel(Level JavaDoc newLevel) throws SecurityException JavaDoc {
1102    checkAccess();
1103    synchronized (treeLock) {
1104        levelObject = newLevel;
1105        updateEffectiveLevel();
1106    }
1107    }
1108
1109    /**
1110     * Get the log Level that has been specified for this Logger.
1111     * The result may be null, which means that this logger's
1112     * effective level will be inherited from its parent.
1113     *
1114     * @return this Logger's level
1115     */

1116    public Level JavaDoc getLevel() {
1117    return levelObject;
1118    }
1119
1120    /**
1121     * Check if a message of the given level would actually be logged
1122     * by this logger. This check is based on the Loggers effective level,
1123     * which may be inherited from its parent.
1124     *
1125     * @param level a message logging level
1126     * @return true if the given message level is currently being logged.
1127     */

1128    public boolean isLoggable(Level JavaDoc level) {
1129    if (level.intValue() < levelValue || levelValue == offValue) {
1130        return false;
1131    }
1132    return true;
1133    }
1134
1135    /**
1136     * Get the name for this logger.
1137     * @return logger name. Will be null for anonymous Loggers.
1138     */

1139    public String JavaDoc getName() {
1140    return name;
1141    }
1142
1143    /**
1144     * Add a log Handler to receive logging messages.
1145     * <p>
1146     * By default, Loggers also send their output to their parent logger.
1147     * Typically the root Logger is configured with a set of Handlers
1148     * that essentially act as default handlers for all loggers.
1149     *
1150     * @param handler a logging Handler
1151     * @exception SecurityException if a security manager exists and if
1152     * the caller does not have LoggingPermission("control").
1153     */

1154    public synchronized void addHandler(Handler JavaDoc handler) throws SecurityException JavaDoc {
1155    // Check for null handler
1156
handler.getClass();
1157    checkAccess();
1158    if (handlers == null) {
1159        handlers = new ArrayList();
1160    }
1161    handlers.add(handler);
1162    }
1163
1164    /**
1165     * Remove a log Handler.
1166     * <P>
1167     * Returns silently if the given Handler is not found or is null
1168     *
1169     * @param handler a logging Handler
1170     * @exception SecurityException if a security manager exists and if
1171     * the caller does not have LoggingPermission("control").
1172     */

1173    public synchronized void removeHandler(Handler JavaDoc handler) throws SecurityException JavaDoc {
1174    checkAccess();
1175    if (handler == null) {
1176        return;
1177    }
1178    if (handlers == null) {
1179        return;
1180    }
1181    handlers.remove(handler);
1182    }
1183
1184    /**
1185     * Get the Handlers associated with this logger.
1186     * <p>
1187     * @return an array of all registered Handlers
1188     */

1189    public synchronized Handler JavaDoc[] getHandlers() {
1190    if (handlers == null) {
1191        return emptyHandlers;
1192    }
1193    Handler JavaDoc result[] = new Handler JavaDoc[handlers.size()];
1194    result = (Handler JavaDoc [])handlers.toArray(result);
1195    return result;
1196    }
1197
1198    /**
1199     * Specify whether or not this logger should send its output
1200     * to it's parent Logger. This means that any LogRecords will
1201     * also be written to the parent's Handlers, and potentially
1202     * to its parent, recursively up the namespace.
1203     *
1204     * @param useParentHandlers true if output is to be sent to the
1205     * logger's parent.
1206     * @exception SecurityException if a security manager exists and if
1207     * the caller does not have LoggingPermission("control").
1208     */

1209    public synchronized void setUseParentHandlers(boolean useParentHandlers) {
1210    checkAccess();
1211    this.useParentHandlers = useParentHandlers;
1212    }
1213
1214    /**
1215     * Discover whether or not this logger is sending its output
1216     * to its parent logger.
1217     *
1218     * @return true if output is to be sent to the logger's parent
1219     */

1220    public synchronized boolean getUseParentHandlers() {
1221    return useParentHandlers;
1222    }
1223
1224    // Private utility method to map a resource bundle name to an
1225
// actual resource bundle, using a simple one-entry cache.
1226
// Returns null for a null name.
1227
// May also return null if we can't find the resource bundle and
1228
// there is no suitable previous cached value.
1229

1230    private synchronized ResourceBundle findResourceBundle(String JavaDoc name) {
1231    // Return a null bundle for a null name.
1232
if (name == null) {
1233        return null;
1234    }
1235
1236    Locale currentLocale = Locale.getDefault();
1237
1238    // Normally we should hit on our simple one entry cache.
1239
if (catalog != null && currentLocale == catalogLocale
1240                    && name == catalogName) {
1241        return catalog;
1242    }
1243
1244    // Use the thread's context ClassLoader. If there isn't one,
1245
// use the SystemClassloader.
1246
ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
1247    if (cl == null) {
1248        cl = ClassLoader.getSystemClassLoader();
1249    }
1250    try {
1251        catalog = ResourceBundle.getBundle(name, currentLocale, cl);
1252        catalogName = name;
1253        catalogLocale = currentLocale;
1254        return catalog;
1255    } catch (MissingResourceException ex) {
1256        // Woops. We can't find the ResourceBundle in the default
1257
// ClassLoader. Drop through.
1258
}
1259
1260
1261    // Fall back to searching up the call stack and trying each
1262
// calling ClassLoader.
1263
for (int ix = 0; ; ix++) {
1264        Class JavaDoc clz = sun.reflect.Reflection.getCallerClass(ix);
1265        if (clz == null) {
1266        break;
1267        }
1268        ClassLoader JavaDoc cl2 = clz.getClassLoader();
1269        if (cl2 == null) {
1270        cl2 = ClassLoader.getSystemClassLoader();
1271        }
1272        if (cl == cl2) {
1273        // We've already checked this classloader.
1274
continue;
1275        }
1276        cl = cl2;
1277        try {
1278            catalog = ResourceBundle.getBundle(name, currentLocale, cl);
1279            catalogName = name;
1280            catalogLocale = currentLocale;
1281        return catalog;
1282        } catch (MissingResourceException ex) {
1283        // Ok, this one didn't work either.
1284
// Drop through, and try the next one.
1285
}
1286    }
1287
1288    if (name.equals(catalogName)) {
1289        // Return the previous cached value for that name.
1290
// This may be null.
1291
return catalog;
1292    }
1293    // Sorry, we're out of luck.
1294
return null;
1295    }
1296
1297    // Private utility method to initialize our one entry
1298
// resource bundle cache.
1299
// Note: for consistency reasons, we are careful to check
1300
// that a suitable ResourceBundle exists before setting the
1301
// ResourceBundleName.
1302
private synchronized void setupResourceInfo(String JavaDoc name) {
1303    if (name == null) {
1304        return;
1305    }
1306    ResourceBundle rb = findResourceBundle(name);
1307    if (rb == null) {
1308        // We've failed to find an expected ResourceBundle.
1309
throw new MissingResourceException("Can't find " + name + " bundle", name, "");
1310    }
1311    resourceBundleName = name;
1312    }
1313
1314    /**
1315     * Return the parent for this Logger.
1316     * <p>
1317     * This method returns the nearest extant parent in the namespace.
1318     * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b"
1319     * has been created but no logger "a.b.c" exists, then a call of
1320     * getParent on the Logger "a.b.c.d" will return the Logger "a.b".
1321     * <p>
1322     * The result will be null if it is called on the root Logger
1323     * in the namespace.
1324     *
1325     * @return nearest existing parent Logger
1326     */

1327    public Logger JavaDoc getParent() {
1328    synchronized (treeLock) {
1329        return parent;
1330    }
1331    }
1332
1333    /**
1334     * Set the parent for this Logger. This method is used by
1335     * the LogManager to update a Logger when the namespace changes.
1336     * <p>
1337     * It should not be called from application code.
1338     * <p>
1339     * @param parent the new parent logger
1340     * @exception SecurityException if a security manager exists and if
1341     * the caller does not have LoggingPermission("control").
1342     */

1343    public void setParent(Logger JavaDoc parent) {
1344    if (parent == null) {
1345        throw new NullPointerException JavaDoc();
1346    }
1347    manager.checkAccess();
1348    doSetParent(parent);
1349    }
1350
1351    // Private method to do the work for parenting a child
1352
// Logger onto a parent logger.
1353
private void doSetParent(Logger JavaDoc newParent) {
1354
1355    // System.err.println("doSetParent \"" + getName() + "\" \""
1356
// + newParent.getName() + "\"");
1357

1358    synchronized (treeLock) {
1359
1360        // Remove ourself from any previous parent.
1361
if (parent != null) {
1362        // assert parent.kids != null;
1363
for (Iterator iter = parent.kids.iterator(); iter.hasNext(); ) {
1364            WeakReference JavaDoc ref = (WeakReference JavaDoc) iter.next();
1365            Logger JavaDoc kid = (Logger JavaDoc) ref.get();
1366            if (kid == this) {
1367                iter.remove();
1368            break;
1369            }
1370        }
1371        // We have now removed ourself from our parents' kids.
1372
}
1373
1374        // Set our new parent.
1375
parent = newParent;
1376        if (parent.kids == null) {
1377            parent.kids = new ArrayList(2);
1378        }
1379        parent.kids.add(new WeakReference JavaDoc(this));
1380
1381        // As a result of the reparenting, the effective level
1382
// may have changed for us and our children.
1383
updateEffectiveLevel();
1384
1385    }
1386    }
1387
1388    // Recalculate the effective level for this node and
1389
// recursively for our children.
1390

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

1394    // Figure out our current effective level.
1395
int newLevelValue;
1396    if (levelObject != null) {
1397        newLevelValue = levelObject.intValue();
1398    } else {
1399        if (parent != null) {
1400            newLevelValue = parent.levelValue;
1401        } else {
1402        // This may happen during initialization.
1403
newLevelValue = Level.INFO.intValue();
1404        }
1405    }
1406
1407    // If our effective value hasn't changed, we're done.
1408
if (levelValue == newLevelValue) {
1409        return;
1410    }
1411
1412    levelValue = newLevelValue;
1413
1414    // System.err.println("effective level: \"" + getName() + "\" := " + level);
1415

1416    // Recursively update the level on each of our kids.
1417
if (kids != null) {
1418        for (int i = 0; i < kids.size(); i++) {
1419            WeakReference JavaDoc ref = (WeakReference JavaDoc)kids.get(i);
1420        Logger JavaDoc kid = (Logger JavaDoc) ref.get();
1421        if (kid != null) {
1422            kid.updateEffectiveLevel();
1423        }
1424        }
1425    }
1426    }
1427
1428
1429    // Private method to get the potentially inherited
1430
// resource bundle name for this Logger.
1431
// May return null
1432
private String JavaDoc getEffectiveResourceBundleName() {
1433    Logger JavaDoc target = this;
1434    while (target != null) {
1435        String JavaDoc rbn = target.getResourceBundleName();
1436        if (rbn != null) {
1437        return rbn;
1438        }
1439        target = target.getParent();
1440    }
1441    return null;
1442    }
1443
1444
1445}
1446
Popular Tags