9b304bc16a1f23f14cfae5962f78afbd47958427
[jalview.git] / srcjar / org / apache / log4j / Category.java
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  * 
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  * 
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 // Contibutors: Alex Blewitt <Alex.Blewitt@ioshq.com>
19 //              Markus Oestreicher <oes@zurich.ibm.com>
20 //              Frank Hoering <fhr@zurich.ibm.com>
21 //              Nelson Minar <nelson@media.mit.edu>
22 //              Jim Cakalic <jim_cakalic@na.biomerieux.com>
23 //              Avy Sharell <asharell@club-internet.fr>
24 //              Ciaran Treanor <ciaran@xelector.com>
25 //              Jeff Turner <jeff@socialchange.net.au>
26 //              Michael Horwitz <MHorwitz@siemens.co.za>
27 //              Calvin Chan <calvin.chan@hic.gov.au>
28 //              Aaron Greenhouse <aarong@cs.cmu.edu>
29 //              Beat Meier <bmeier@infovia.com.ar>
30 //              Colin Sampaleanu <colinml1@exis.com>
31
32 package org.apache.log4j;
33
34 import org.apache.log4j.spi.AppenderAttachable;
35 import org.apache.log4j.spi.LoggingEvent;
36 import org.apache.log4j.spi.LoggerRepository;
37 import org.apache.log4j.spi.HierarchyEventListener;
38 import org.apache.log4j.helpers.NullEnumeration;
39 import org.apache.log4j.helpers.AppenderAttachableImpl;
40
41 import java.util.Enumeration;
42 import java.util.MissingResourceException;
43 import java.util.ResourceBundle;
44 import java.util.Vector;
45
46
47 /**
48   * <font color="#AA2222"><b>This class has been deprecated and
49   * replaced by the {@link Logger} <em>subclass</em></b></font>. It
50   * will be kept around to preserve backward compatibility until mid
51   * 2003.
52   * 
53   * <p><code>Logger</code> is a subclass of Category, i.e. it extends
54   * Category. In other words, a logger <em>is</em> a category. Thus,
55   * all operations that can be performed on a category can be
56   * performed on a logger. Internally, whenever log4j is asked to
57   * produce a Category object, it will instead produce a Logger
58   * object. Log4j 1.2 will <em>never</em> produce Category objects but
59   * only <code>Logger</code> instances. In order to preserve backward
60   * compatibility, methods that previously accepted category objects
61   * still continue to accept category objects.
62   * 
63   * <p>For example, the following are all legal and will work as
64   * expected.
65   * 
66    <pre>
67     &nbsp;&nbsp;&nbsp;// Deprecated form:
68     &nbsp;&nbsp;&nbsp;Category cat = Category.getInstance("foo.bar")
69    
70     &nbsp;&nbsp;&nbsp;// Preferred form for retrieving loggers:
71     &nbsp;&nbsp;&nbsp;Logger logger = Logger.getLogger("foo.bar")
72    </pre>
73    
74   *  <p>The first form is deprecated and should be avoided.
75   * 
76   *  <p><b>There is absolutely no need for new client code to use or
77   *  refer to the <code>Category</code> class.</b> Whenever possible,
78   *  please avoid referring to it or using it.
79   * 
80   * <p>See the <a href="../../../../manual.html">short manual</a> for an
81   * introduction on this class.
82   * <p>
83   * See the document entitled <a href="http://www.qos.ch/logging/preparingFor13.html">preparing
84   *  for log4j 1.3</a> for a more detailed discussion.
85   *
86   * @author Ceki G&uuml;lc&uuml;
87   * @author Anders Kristensen 
88   */
89 public class Category implements AppenderAttachable {
90
91   /**
92      The hierarchy where categories are attached to by default.
93   */
94   //static
95   //public
96   //final Hierarchy defaultHierarchy = new Hierarchy(new
97   //                                       RootCategory(Level.DEBUG));
98
99   /**
100      The name of this category.
101   */
102   protected String   name;
103
104   /**
105      The assigned level of this category.  The
106      <code>level</code> variable need not be assigned a value in
107      which case it is inherited form the hierarchy.  */
108   volatile protected Level level;
109
110   /**
111      The parent of this category. All categories have at least one
112      ancestor which is the root category. */
113   volatile protected Category parent;
114
115   /**
116      The fully qualified name of the Category class. See also the
117      getFQCN method. */
118   private static final String FQCN = Category.class.getName();
119
120   protected ResourceBundle resourceBundle;
121
122   // Categories need to know what Hierarchy they are in
123   protected LoggerRepository repository;
124
125
126   AppenderAttachableImpl aai;
127
128   /** Additivity is set to true by default, that is children inherit
129       the appenders of their ancestors by default. If this variable is
130       set to <code>false</code> then the appenders found in the
131       ancestors of this category are not used. However, the children
132       of this category will inherit its appenders, unless the children
133       have their additivity flag set to <code>false</code> too. See
134       the user manual for more details. */
135   protected boolean additive = true;
136
137   /**
138      This constructor created a new <code>Category</code> instance and
139      sets its name.
140
141      <p>It is intended to be used by sub-classes only. You should not
142      create categories directly.
143
144      @param name The name of the category.
145   */
146   protected
147   Category(String name) {
148     this.name = name;
149   }
150
151   /**
152      Add <code>newAppender</code> to the list of appenders of this
153      Category instance.
154
155      <p>If <code>newAppender</code> is already in the list of
156      appenders, then it won't be added again.
157   */
158   synchronized
159   public
160   void addAppender(Appender newAppender) {
161     if(aai == null) {
162       aai = new AppenderAttachableImpl();
163     }
164     aai.addAppender(newAppender);
165     repository.fireAddAppenderEvent(this, newAppender);
166   }
167
168   /**
169      If <code>assertion</code> parameter is <code>false</code>, then
170      logs <code>msg</code> as an {@link #error(Object) error} statement.
171
172      <p>The <code>assert</code> method has been renamed to
173      <code>assertLog</code> because <code>assert</code> is a language
174      reserved word in JDK 1.4.
175
176      @param assertion
177      @param msg The message to print if <code>assertion</code> is
178      false.
179
180      @since 1.2 */
181   public
182   void assertLog(boolean assertion, String msg) {
183     if(!assertion) {
184         this.error(msg);
185     }
186   }
187
188
189   /**
190      Call the appenders in the hierrachy starting at
191      <code>this</code>.  If no appenders could be found, emit a
192      warning.
193
194      <p>This method calls all the appenders inherited from the
195      hierarchy circumventing any evaluation of whether to log or not
196      to log the particular log request.
197
198      @param event the event to log.  */
199   public
200   void callAppenders(LoggingEvent event) {
201     int writes = 0;
202
203     for(Category c = this; c != null; c=c.parent) {
204       // Protected against simultaneous call to addAppender, removeAppender,...
205       synchronized(c) {
206         if(c.aai != null) {
207           writes += c.aai.appendLoopOnAppenders(event);
208         }
209         if(!c.additive) {
210           break;
211         }
212       }
213     }
214
215     if(writes == 0) {
216       repository.emitNoAppenderWarning(this);
217     }
218   }
219
220   /**
221      Close all attached appenders implementing the AppenderAttachable
222      interface.
223      @since 1.0
224   */
225   synchronized
226   void closeNestedAppenders() {
227     Enumeration enumeration = this.getAllAppenders();
228     if(enumeration != null) {
229       while(enumeration.hasMoreElements()) {
230         Appender a = (Appender) enumeration.nextElement();
231         if(a instanceof AppenderAttachable) {
232           a.close();
233         }
234       }
235     }
236   }
237
238   /**
239     Log a message object with the {@link Level#DEBUG DEBUG} level.
240
241     <p>This method first checks if this category is <code>DEBUG</code>
242     enabled by comparing the level of this category with the {@link
243     Level#DEBUG DEBUG} level. If this category is
244     <code>DEBUG</code> enabled, then it converts the message object
245     (passed as parameter) to a string by invoking the appropriate
246     {@link org.apache.log4j.or.ObjectRenderer}. It then proceeds to call all the
247     registered appenders in this category and also higher in the
248     hierarchy depending on the value of the additivity flag.
249
250     <p><b>WARNING</b> Note that passing a {@link Throwable} to this
251     method will print the name of the <code>Throwable</code> but no
252     stack trace. To print a stack trace use the {@link #debug(Object,
253     Throwable)} form instead.
254
255     @param message the message object to log. */
256   public
257   void debug(Object message) {
258     if(repository.isDisabled(Level.DEBUG_INT)) {
259         return;
260     }
261     if(Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel())) {
262       forcedLog(FQCN, Level.DEBUG, message, null);
263     }
264   }
265
266
267   /**
268    Log a message object with the <code>DEBUG</code> level including
269    the stack trace of the {@link Throwable} <code>t</code> passed as
270    parameter.
271
272    <p>See {@link #debug(Object)} form for more detailed information.
273
274    @param message the message object to log.
275    @param t the exception to log, including its stack trace.  */
276   public
277   void debug(Object message, Throwable t) {
278     if(repository.isDisabled(Level.DEBUG_INT)) {
279         return;
280     }
281     if(Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel())) {
282         forcedLog(FQCN, Level.DEBUG, message, t);
283     }
284   }
285
286   /**
287     Log a message object with the {@link Level#ERROR ERROR} Level.
288
289     <p>This method first checks if this category is <code>ERROR</code>
290     enabled by comparing the level of this category with {@link
291     Level#ERROR ERROR} Level. If this category is <code>ERROR</code>
292     enabled, then it converts the message object passed as parameter
293     to a string by invoking the appropriate {@link
294     org.apache.log4j.or.ObjectRenderer}. It proceeds to call all the
295     registered appenders in this category and also higher in the
296     hierarchy depending on the value of the additivity flag.
297
298     <p><b>WARNING</b> Note that passing a {@link Throwable} to this
299     method will print the name of the <code>Throwable</code> but no
300     stack trace. To print a stack trace use the {@link #error(Object,
301     Throwable)} form instead.
302
303     @param message the message object to log */
304   public
305   void error(Object message) {
306     if(repository.isDisabled(Level.ERROR_INT)) {
307         return;
308     }
309     if(Level.ERROR.isGreaterOrEqual(this.getEffectiveLevel())) {
310         forcedLog(FQCN, Level.ERROR, message, null);
311     }
312   }
313
314   /**
315    Log a message object with the <code>ERROR</code> level including
316    the stack trace of the {@link Throwable} <code>t</code> passed as
317    parameter.
318
319    <p>See {@link #error(Object)} form for more detailed information.
320
321    @param message the message object to log.
322    @param t the exception to log, including its stack trace.  */
323   public
324   void error(Object message, Throwable t) {
325     if(repository.isDisabled(Level.ERROR_INT)) {
326         return;
327     }
328     if(Level.ERROR.isGreaterOrEqual(this.getEffectiveLevel())) {
329         forcedLog(FQCN, Level.ERROR, message, t);
330     }
331
332   }
333
334
335   /**
336      If the named category exists (in the default hierarchy) then it
337      returns a reference to the category, otherwise it returns
338      <code>null</code>.
339
340      @deprecated Please use {@link LogManager#exists} instead.
341
342      @since 0.8.5 */
343   public
344   static
345   Logger exists(String name) {
346     return LogManager.exists(name);
347   }
348
349   /**
350     Log a message object with the {@link Level#FATAL FATAL} Level.
351
352     <p>This method first checks if this category is <code>FATAL</code>
353     enabled by comparing the level of this category with {@link
354     Level#FATAL FATAL} Level. If the category is <code>FATAL</code>
355     enabled, then it converts the message object passed as parameter
356     to a string by invoking the appropriate
357     {@link org.apache.log4j.or.ObjectRenderer}. It
358     proceeds to call all the registered appenders in this category and
359     also higher in the hierarchy depending on the value of the
360     additivity flag.
361
362     <p><b>WARNING</b> Note that passing a {@link Throwable} to this
363     method will print the name of the Throwable but no stack trace. To
364     print a stack trace use the {@link #fatal(Object, Throwable)} form
365     instead.
366
367     @param message the message object to log */
368   public
369   void fatal(Object message) {
370     if(repository.isDisabled(Level.FATAL_INT)) {
371         return;
372     }
373     if(Level.FATAL.isGreaterOrEqual(this.getEffectiveLevel())) {
374         forcedLog(FQCN, Level.FATAL, message, null);
375     }
376   }
377
378   /**
379    Log a message object with the <code>FATAL</code> level including
380    the stack trace of the {@link Throwable} <code>t</code> passed as
381    parameter.
382
383    <p>See {@link #fatal(Object)} for more detailed information.
384
385    @param message the message object to log.
386    @param t the exception to log, including its stack trace.  */
387   public
388   void fatal(Object message, Throwable t) {
389     if(repository.isDisabled(Level.FATAL_INT)) {
390         return;
391     }
392     if(Level.FATAL.isGreaterOrEqual(this.getEffectiveLevel())) {
393         forcedLog(FQCN, Level.FATAL, message, t);
394     }
395   }
396
397
398   /**
399      This method creates a new logging event and logs the event
400      without further checks.  */
401   protected
402   void forcedLog(String fqcn, Priority level, Object message, Throwable t) {
403     callAppenders(new LoggingEvent(fqcn, this, level, message, t));
404   }
405
406
407   /**
408      Get the additivity flag for this Category instance.
409   */
410   public
411   boolean getAdditivity() {
412     return additive;
413   }
414
415   /**
416      Get the appenders contained in this category as an {@link
417      Enumeration}. If no appenders can be found, then a {@link NullEnumeration}
418      is returned.
419
420      @return Enumeration An enumeration of the appenders in this category.  */
421   synchronized
422   public
423   Enumeration getAllAppenders() {
424     if(aai == null) {
425         return NullEnumeration.getInstance();
426     } else {
427         return aai.getAllAppenders();
428     }
429   }
430
431   /**
432      Look for the appender named as <code>name</code>.
433
434      <p>Return the appender with that name if in the list. Return
435      <code>null</code> otherwise.  */
436   synchronized
437   public
438   Appender getAppender(String name) {
439      if(aai == null || name == null) {
440         return null;
441     }
442
443      return aai.getAppender(name);
444   }
445
446   /**
447      Starting from this category, search the category hierarchy for a
448      non-null level and return it. Otherwise, return the level of the
449      root category.
450
451      <p>The Category class is designed so that this method executes as
452      quickly as possible.
453    */
454   public
455   Level getEffectiveLevel() {
456     for(Category c = this; c != null; c=c.parent) {
457       if(c.level != null) {
458         return c.level;
459     }
460     }
461     return null; // If reached will cause an NullPointerException.
462   }
463
464   /**
465     *
466     * @deprecated Please use the the {@link #getEffectiveLevel} method
467     * instead.  
468     * */
469   public
470   Priority getChainedPriority() {
471     for(Category c = this; c != null; c=c.parent) {
472       if(c.level != null) {
473         return c.level;
474     }
475     }
476     return null; // If reached will cause an NullPointerException.
477   }
478
479
480   /**
481      Returns all the currently defined categories in the default
482      hierarchy as an {@link java.util.Enumeration Enumeration}.
483
484      <p>The root category is <em>not</em> included in the returned
485      {@link Enumeration}.
486
487      @deprecated Please use {@link LogManager#getCurrentLoggers()} instead.
488   */
489   public
490   static
491   Enumeration getCurrentCategories() {
492     return LogManager.getCurrentLoggers();
493   }
494
495
496   /**
497      Return the default Hierarchy instance.
498
499      @deprecated Please use {@link LogManager#getLoggerRepository()} instead.
500
501      @since 1.0
502    */
503   public
504   static
505   LoggerRepository getDefaultHierarchy() {
506     return LogManager.getLoggerRepository();
507   }
508
509   /**
510      Return the the {@link Hierarchy} where this <code>Category</code>
511      instance is attached.
512
513      @deprecated Please use {@link #getLoggerRepository} instead.
514
515      @since 1.1 */
516   public
517   LoggerRepository  getHierarchy() {
518     return repository;
519   }
520
521   /**
522      Return the the {@link LoggerRepository} where this
523      <code>Category</code> is attached.
524
525      @since 1.2 */
526   public
527   LoggerRepository  getLoggerRepository() {
528     return repository;
529   }
530
531
532  /**
533   * @deprecated Make sure to use {@link Logger#getLogger(String)} instead.
534   */
535   public
536   static
537   Category getInstance(String name) {
538     return LogManager.getLogger(name);
539   }
540
541  /**
542   * @deprecated Please make sure to use {@link Logger#getLogger(Class)} instead.
543   */ 
544   public
545   static
546   Category getInstance(Class clazz) {
547     return LogManager.getLogger(clazz);
548   }
549
550
551   /**
552      Return the category name.  */
553   public
554   final
555   String getName() {
556     return name;
557   }
558
559
560   /**
561      Returns the parent of this category. Note that the parent of a
562      given category may change during the lifetime of the category.
563
564      <p>The root category will return <code>null</code>.
565
566      @since 1.2
567   */
568   final
569   public
570   Category getParent() {
571     return this.parent;
572   }
573
574
575   /**
576      Returns the assigned {@link Level}, if any, for this Category.
577
578      @return Level - the assigned Level, can be <code>null</code>.
579   */
580   final
581   public
582   Level getLevel() {
583     return this.level;
584   }
585
586   /**
587      @deprecated Please use {@link #getLevel} instead.
588   */
589   final
590   public
591   Level getPriority() {
592     return this.level;
593   }
594
595
596   /**
597    *  @deprecated Please use {@link Logger#getRootLogger()} instead.
598    */
599   final
600   public
601   static
602   Category getRoot() {
603     return LogManager.getRootLogger();
604   }
605
606   /**
607      Return the <em>inherited</em> {@link ResourceBundle} for this
608      category.
609
610      <p>This method walks the hierarchy to find the appropriate
611      resource bundle. It will return the resource bundle attached to
612      the closest ancestor of this category, much like the way
613      priorities are searched. In case there is no bundle in the
614      hierarchy then <code>null</code> is returned.
615
616      @since 0.9.0 */
617   public
618   ResourceBundle getResourceBundle() {
619     for(Category c = this; c != null; c=c.parent) {
620       if(c.resourceBundle != null) {
621         return c.resourceBundle;
622     }
623     }
624     // It might be the case that there is no resource bundle
625     return null;
626   }
627
628   /**
629      Returns the string resource coresponding to <code>key</code> in
630      this category's inherited resource bundle. See also {@link
631      #getResourceBundle}.
632
633      <p>If the resource cannot be found, then an {@link #error error}
634      message will be logged complaining about the missing resource.
635   */
636   protected
637   String getResourceBundleString(String key) {
638     ResourceBundle rb = getResourceBundle();
639     // This is one of the rare cases where we can use logging in order
640     // to report errors from within log4j.
641     if(rb == null) {
642       //if(!hierarchy.emittedNoResourceBundleWarning) {
643       //error("No resource bundle has been set for category "+name);
644       //hierarchy.emittedNoResourceBundleWarning = true;
645       //}
646       return null;
647     }
648     else {
649       try {
650         return rb.getString(key);
651       }
652       catch(MissingResourceException mre) {
653         error("No resource is associated with key \""+key+"\".");
654         return null;
655       }
656     }
657   }
658
659   /**
660     Log a message object with the {@link Level#INFO INFO} Level.
661
662     <p>This method first checks if this category is <code>INFO</code>
663     enabled by comparing the level of this category with {@link
664     Level#INFO INFO} Level. If the category is <code>INFO</code>
665     enabled, then it converts the message object passed as parameter
666     to a string by invoking the appropriate
667     {@link org.apache.log4j.or.ObjectRenderer}. It
668     proceeds to call all the registered appenders in this category and
669     also higher in the hierarchy depending on the value of the
670     additivity flag.
671
672     <p><b>WARNING</b> Note that passing a {@link Throwable} to this
673     method will print the name of the Throwable but no stack trace. To
674     print a stack trace use the {@link #info(Object, Throwable)} form
675     instead.
676
677     @param message the message object to log */
678   public
679   void info(Object message) {
680     if(repository.isDisabled(Level.INFO_INT)) {
681         return;
682     }
683     if(Level.INFO.isGreaterOrEqual(this.getEffectiveLevel())) {
684         forcedLog(FQCN, Level.INFO, message, null);
685     }
686   }
687
688   /**
689    Log a message object with the <code>INFO</code> level including
690    the stack trace of the {@link Throwable} <code>t</code> passed as
691    parameter.
692
693    <p>See {@link #info(Object)} for more detailed information.
694
695    @param message the message object to log.
696    @param t the exception to log, including its stack trace.  */
697   public
698   void info(Object message, Throwable t) {
699     if(repository.isDisabled(Level.INFO_INT)) {
700         return;
701     }
702     if(Level.INFO.isGreaterOrEqual(this.getEffectiveLevel())) {
703         forcedLog(FQCN, Level.INFO, message, t);
704     }
705   }
706
707   /**
708      Is the appender passed as parameter attached to this category?
709    */
710   public
711   boolean isAttached(Appender appender) {
712     if(appender == null || aai == null) {
713         return false;
714     } else {
715       return aai.isAttached(appender);
716     }
717   }
718
719   /**
720     *  Check whether this category is enabled for the <code>DEBUG</code>
721     *  Level.
722     *
723     *  <p> This function is intended to lessen the computational cost of
724     *  disabled log debug statements.
725     *
726     *  <p> For some <code>cat</code> Category object, when you write,
727     *  <pre>
728     *      cat.debug("This is entry number: " + i );
729     *  </pre>
730     *
731     *  <p>You incur the cost constructing the message, concatenatiion in
732     *  this case, regardless of whether the message is logged or not.
733     *
734     *  <p>If you are worried about speed, then you should write
735     *  <pre>
736     *    if(cat.isDebugEnabled()) {
737     *      cat.debug("This is entry number: " + i );
738     *    }
739     *  </pre>
740     *
741     *  <p>This way you will not incur the cost of parameter
742     *  construction if debugging is disabled for <code>cat</code>. On
743     *  the other hand, if the <code>cat</code> is debug enabled, you
744     *  will incur the cost of evaluating whether the category is debug
745     *  enabled twice. Once in <code>isDebugEnabled</code> and once in
746     *  the <code>debug</code>.  This is an insignificant overhead
747     *  since evaluating a category takes about 1%% of the time it
748     *  takes to actually log.
749     *
750     *  @return boolean - <code>true</code> if this category is debug
751     *  enabled, <code>false</code> otherwise.
752     *   */
753   public
754   boolean isDebugEnabled() {
755     if(repository.isDisabled( Level.DEBUG_INT)) {
756         return false;
757     }
758     return Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel());
759   }
760
761   /**
762      Check whether this category is enabled for a given {@link
763      Level} passed as parameter.
764
765      See also {@link #isDebugEnabled}.
766
767      @return boolean True if this category is enabled for <code>level</code>.
768   */
769   public
770   boolean isEnabledFor(Priority level) {
771     if(repository.isDisabled(level.level)) {
772         return false;
773     }
774     return level.isGreaterOrEqual(this.getEffectiveLevel());
775   }
776
777   /**
778     Check whether this category is enabled for the info Level.
779     See also {@link #isDebugEnabled}.
780
781     @return boolean - <code>true</code> if this category is enabled
782     for level info, <code>false</code> otherwise.
783   */
784   public
785   boolean isInfoEnabled() {
786     if(repository.isDisabled(Level.INFO_INT)) {
787         return false;
788     }
789     return Level.INFO.isGreaterOrEqual(this.getEffectiveLevel());
790   }
791
792
793   /**
794      Log a localized message. The user supplied parameter
795      <code>key</code> is replaced by its localized version from the
796      resource bundle.
797
798      @see #setResourceBundle
799
800      @since 0.8.4 */
801   public
802   void l7dlog(Priority priority, String key, Throwable t) {
803     if(repository.isDisabled(priority.level)) {
804       return;
805     }
806     if(priority.isGreaterOrEqual(this.getEffectiveLevel())) {
807       String msg = getResourceBundleString(key);
808       // if message corresponding to 'key' could not be found in the
809       // resource bundle, then default to 'key'.
810       if(msg == null) {
811         msg = key;
812       }
813       forcedLog(FQCN, priority, msg, t);
814     }
815   }
816   /**
817      Log a localized and parameterized message. First, the user
818      supplied <code>key</code> is searched in the resource
819      bundle. Next, the resulting pattern is formatted using
820      {@link java.text.MessageFormat#format(String,Object[])} method with the
821      user supplied object array <code>params</code>.
822
823      @since 0.8.4
824   */
825   public
826   void l7dlog(Priority priority, String key,  Object[] params, Throwable t) {
827     if(repository.isDisabled(priority.level)) {
828       return;
829     }
830     if(priority.isGreaterOrEqual(this.getEffectiveLevel())) {
831       String pattern = getResourceBundleString(key);
832       String msg;
833       if(pattern == null) {
834         msg = key;
835     } else {
836         msg = java.text.MessageFormat.format(pattern, params);
837     }
838       forcedLog(FQCN, priority, msg, t);
839     }
840   }
841
842   /**
843      This generic form is intended to be used by wrappers.
844    */
845   public
846   void log(Priority priority, Object message, Throwable t) {
847     if(repository.isDisabled(priority.level)) {
848       return;
849     }
850     if(priority.isGreaterOrEqual(this.getEffectiveLevel())) {
851         forcedLog(FQCN, priority, message, t);
852     }
853   }
854
855  /**
856     This generic form is intended to be used by wrappers.
857  */
858   public
859   void log(Priority priority, Object message) {
860     if(repository.isDisabled(priority.level)) {
861       return;
862     }
863     if(priority.isGreaterOrEqual(this.getEffectiveLevel())) {
864         forcedLog(FQCN, priority, message, null);
865     }
866   }
867
868   /**
869
870      This is the most generic printing method. It is intended to be
871      invoked by <b>wrapper</b> classes.
872
873      @param callerFQCN The wrapper class' fully qualified class name.
874      @param level The level of the logging request.
875      @param message The message of the logging request.
876      @param t The throwable of the logging request, may be null.  */
877   public
878   void log(String callerFQCN, Priority level, Object message, Throwable t) {
879     if(repository.isDisabled(level.level)) {
880       return;
881     }
882     if(level.isGreaterOrEqual(this.getEffectiveLevel())) {
883       forcedLog(callerFQCN, level, message, t);
884     }
885   }
886
887     /**
888       *  LoggerRepository forgot the fireRemoveAppenderEvent method,
889       *     if using the stock Hierarchy implementation, then call its fireRemove.
890       *     Custom repositories can implement HierarchyEventListener if they
891       *     want remove notifications.
892      * @param appender appender, may be null.
893      */
894    private void fireRemoveAppenderEvent(final Appender appender) {
895        if (appender != null) {
896          if (repository instanceof Hierarchy) {
897            ((Hierarchy) repository).fireRemoveAppenderEvent(this, appender);
898          } else if (repository instanceof HierarchyEventListener) {
899              ((HierarchyEventListener) repository).removeAppenderEvent(this, appender);
900          }
901        }
902    }
903
904   /**
905      Remove all previously added appenders from this Category
906      instance.
907
908      <p>This is useful when re-reading configuration information.
909   */
910   synchronized
911   public
912   void removeAllAppenders() {
913     if(aai != null) {
914       Vector appenders = new Vector();
915       for (Enumeration iter = aai.getAllAppenders(); iter != null && iter.hasMoreElements();) {
916           appenders.add(iter.nextElement());
917       }
918       aai.removeAllAppenders();
919       for(Enumeration iter = appenders.elements(); iter.hasMoreElements();) {
920           fireRemoveAppenderEvent((Appender) iter.nextElement());
921       }
922       aai = null;
923     }
924   }
925
926
927   /**
928      Remove the appender passed as parameter form the list of appenders.
929
930      @since 0.8.2
931   */
932   synchronized
933   public
934   void removeAppender(Appender appender) {
935     if(appender == null || aai == null) {
936         return;
937     }
938     boolean wasAttached = aai.isAttached(appender);
939     aai.removeAppender(appender);
940     if (wasAttached) {
941         fireRemoveAppenderEvent(appender);
942     }
943   }
944
945   /**
946      Remove the appender with the name passed as parameter form the
947      list of appenders.
948
949      @since 0.8.2 */
950   synchronized
951   public
952   void removeAppender(String name) {
953     if(name == null || aai == null) {
954         return;
955     }
956     Appender appender = aai.getAppender(name);
957     aai.removeAppender(name);
958     if (appender != null) {
959         fireRemoveAppenderEvent(appender);
960     }
961   }
962
963   /**
964      Set the additivity flag for this Category instance.
965      @since 0.8.1
966    */
967   public
968   void setAdditivity(boolean additive) {
969     this.additive = additive;
970   }
971
972   /**
973      Only the Hiearchy class can set the hiearchy of a
974      category. Default package access is MANDATORY here.  */
975   final
976   void setHierarchy(LoggerRepository repository) {
977     this.repository = repository;
978   }
979
980   /**
981      Set the level of this Category. If you are passing any of
982      <code>Level.DEBUG</code>, <code>Level.INFO</code>,
983      <code>Level.WARN</code>, <code>Level.ERROR</code>,
984      <code>Level.FATAL</code> as a parameter, you need to case them as
985      Level.
986
987      <p>As in <pre> &nbsp;&nbsp;&nbsp;logger.setLevel((Level) Level.DEBUG); </pre>
988
989
990      <p>Null values are admitted.  */
991   public
992   void setLevel(Level level) {
993     this.level = level;
994   }
995
996
997   /**
998      Set the level of this Category.
999
1000      <p>Null values are admitted.
1001
1002      @deprecated Please use {@link #setLevel} instead.
1003   */
1004   public
1005   void setPriority(Priority priority) {
1006     this.level = (Level) priority;
1007   }
1008
1009
1010   /**
1011      Set the resource bundle to be used with localized logging
1012      methods {@link #l7dlog(Priority,String,Throwable)} and {@link
1013      #l7dlog(Priority,String,Object[],Throwable)}.
1014
1015      @since 0.8.4
1016    */
1017   public
1018   void setResourceBundle(ResourceBundle bundle) {
1019     resourceBundle = bundle;
1020   }
1021
1022   /**
1023      Calling this method will <em>safely</em> close and remove all
1024      appenders in all the categories including root contained in the
1025      default hierachy.
1026
1027      <p>Some appenders such as {@link org.apache.log4j.net.SocketAppender}
1028      and {@link AsyncAppender} need to be closed before the
1029      application exists. Otherwise, pending logging events might be
1030      lost.
1031
1032      <p>The <code>shutdown</code> method is careful to close nested
1033      appenders before closing regular appenders. This is allows
1034      configurations where a regular appender is attached to a category
1035      and again to a nested appender.
1036
1037      @deprecated Please use {@link LogManager#shutdown()} instead.
1038
1039      @since 1.0
1040   */
1041   public
1042   static
1043   void shutdown() {
1044     LogManager.shutdown();
1045   }
1046
1047
1048   /**
1049     Log a message object with the {@link Level#WARN WARN} Level.
1050
1051     <p>This method first checks if this category is <code>WARN</code>
1052     enabled by comparing the level of this category with {@link
1053     Level#WARN WARN} Level. If the category is <code>WARN</code>
1054     enabled, then it converts the message object passed as parameter
1055     to a string by invoking the appropriate
1056     {@link org.apache.log4j.or.ObjectRenderer}. It
1057     proceeds to call all the registered appenders in this category and
1058     also higher in the hieararchy depending on the value of the
1059     additivity flag.
1060
1061     <p><b>WARNING</b> Note that passing a {@link Throwable} to this
1062     method will print the name of the Throwable but no stack trace. To
1063     print a stack trace use the {@link #warn(Object, Throwable)} form
1064     instead.  <p>
1065
1066     @param message the message object to log.  */
1067   public
1068   void warn(Object message) {
1069     if(repository.isDisabled( Level.WARN_INT)) {
1070         return;
1071     }
1072
1073     if(Level.WARN.isGreaterOrEqual(this.getEffectiveLevel())) {
1074         forcedLog(FQCN, Level.WARN, message, null);
1075     }
1076   }
1077
1078   /**
1079    Log a message with the <code>WARN</code> level including the
1080    stack trace of the {@link Throwable} <code>t</code> passed as
1081    parameter.
1082
1083    <p>See {@link #warn(Object)} for more detailed information.
1084
1085    @param message the message object to log.
1086    @param t the exception to log, including its stack trace.  */
1087   public
1088   void warn(Object message, Throwable t) {
1089     if(repository.isDisabled(Level.WARN_INT)) {
1090         return;
1091     }
1092     if(Level.WARN.isGreaterOrEqual(this.getEffectiveLevel())) {
1093         forcedLog(FQCN, Level.WARN, message, t);
1094     }
1095   }
1096 }