View Javadoc

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      Call the appenders in the hierrachy starting at
190      <code>this</code>.  If no appenders could be found, emit a
191      warning.
192 
193      <p>This method calls all the appenders inherited from the
194      hierarchy circumventing any evaluation of whether to log or not
195      to log the particular log request.
196 
197      @param event the event to log.  */
198   public
199   void callAppenders(LoggingEvent event) {
200     int writes = 0;
201 
202     for(Category c = this; c != null; c=c.parent) {
203       // Protected against simultaneous call to addAppender, removeAppender,...
204       synchronized(c) {
205 	if(c.aai != null) {
206 	  writes += c.aai.appendLoopOnAppenders(event);
207 	}
208 	if(!c.additive) {
209 	  break;
210 	}
211       }
212     }
213 
214     if(writes == 0) {
215       repository.emitNoAppenderWarning(this);
216     }
217   }
218 
219   /**
220      Close all attached appenders implementing the AppenderAttachable
221      interface.
222      @since 1.0
223   */
224   synchronized
225   void closeNestedAppenders() {
226     Enumeration enumeration = this.getAllAppenders();
227     if(enumeration != null) {
228       while(enumeration.hasMoreElements()) {
229 	Appender a = (Appender) enumeration.nextElement();
230 	if(a instanceof AppenderAttachable) {
231 	  a.close();
232 	}
233       }
234     }
235   }
236 
237   /**
238     Log a message object with the {@link Level#DEBUG DEBUG} level.
239 
240     <p>This method first checks if this category is <code>DEBUG</code>
241     enabled by comparing the level of this category with the {@link
242     Level#DEBUG DEBUG} level. If this category is
243     <code>DEBUG</code> enabled, then it converts the message object
244     (passed as parameter) to a string by invoking the appropriate
245     {@link org.apache.log4j.or.ObjectRenderer}. It then proceeds to call all the
246     registered appenders in this category and also higher in the
247     hierarchy depending on the value of the additivity flag.
248 
249     <p><b>WARNING</b> Note that passing a {@link Throwable} to this
250     method will print the name of the <code>Throwable</code> but no
251     stack trace. To print a stack trace use the {@link #debug(Object,
252     Throwable)} form instead.
253 
254     @param message the message object to log. */
255   public
256   void debug(Object message) {
257     if(repository.isDisabled(Level.DEBUG_INT))
258       return;
259     if(Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel())) {
260       forcedLog(FQCN, Level.DEBUG, message, null);
261     }
262   }
263 
264 
265   /**
266    Log a message object with the <code>DEBUG</code> level including
267    the stack trace of the {@link Throwable} <code>t</code> passed as
268    parameter.
269 
270    <p>See {@link #debug(Object)} form for more detailed information.
271 
272    @param message the message object to log.
273    @param t the exception to log, including its stack trace.  */
274   public
275   void debug(Object message, Throwable t) {
276     if(repository.isDisabled(Level.DEBUG_INT))
277       return;
278     if(Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel()))
279       forcedLog(FQCN, Level.DEBUG, message, t);
280   }
281 
282   /**
283     Log a message object with the {@link Level#ERROR ERROR} Level.
284 
285     <p>This method first checks if this category is <code>ERROR</code>
286     enabled by comparing the level of this category with {@link
287     Level#ERROR ERROR} Level. If this category is <code>ERROR</code>
288     enabled, then it converts the message object passed as parameter
289     to a string by invoking the appropriate {@link
290     org.apache.log4j.or.ObjectRenderer}. It proceeds to call all the
291     registered appenders in this category and also higher in the
292     hierarchy depending on the value of the additivity flag.
293 
294     <p><b>WARNING</b> Note that passing a {@link Throwable} to this
295     method will print the name of the <code>Throwable</code> but no
296     stack trace. To print a stack trace use the {@link #error(Object,
297     Throwable)} form instead.
298 
299     @param message the message object to log */
300   public
301   void error(Object message) {
302     if(repository.isDisabled(Level.ERROR_INT))
303       return;
304     if(Level.ERROR.isGreaterOrEqual(this.getEffectiveLevel()))
305       forcedLog(FQCN, Level.ERROR, message, null);
306   }
307 
308   /**
309    Log a message object with the <code>ERROR</code> level including
310    the stack trace of the {@link Throwable} <code>t</code> passed as
311    parameter.
312 
313    <p>See {@link #error(Object)} form for more detailed information.
314 
315    @param message the message object to log.
316    @param t the exception to log, including its stack trace.  */
317   public
318   void error(Object message, Throwable t) {
319     if(repository.isDisabled(Level.ERROR_INT))
320       return;
321     if(Level.ERROR.isGreaterOrEqual(this.getEffectiveLevel()))
322       forcedLog(FQCN, Level.ERROR, message, t);
323 
324   }
325 
326 
327   /**
328      If the named category exists (in the default hierarchy) then it
329      returns a reference to the category, otherwise it returns
330      <code>null</code>.
331 
332      @deprecated Please use {@link LogManager#exists} instead.
333 
334      @since 0.8.5 */
335   public
336   static
337   Logger exists(String name) {
338     return LogManager.exists(name);
339   }
340 
341   /**
342     Log a message object with the {@link Level#FATAL FATAL} Level.
343 
344     <p>This method first checks if this category is <code>FATAL</code>
345     enabled by comparing the level of this category with {@link
346     Level#FATAL FATAL} Level. If the category is <code>FATAL</code>
347     enabled, then it converts the message object passed as parameter
348     to a string by invoking the appropriate
349     {@link org.apache.log4j.or.ObjectRenderer}. It
350     proceeds to call all the registered appenders in this category and
351     also higher in the hierarchy depending on the value of the
352     additivity flag.
353 
354     <p><b>WARNING</b> Note that passing a {@link Throwable} to this
355     method will print the name of the Throwable but no stack trace. To
356     print a stack trace use the {@link #fatal(Object, Throwable)} form
357     instead.
358 
359     @param message the message object to log */
360   public
361   void fatal(Object message) {
362     if(repository.isDisabled(Level.FATAL_INT))
363       return;
364     if(Level.FATAL.isGreaterOrEqual(this.getEffectiveLevel()))
365       forcedLog(FQCN, Level.FATAL, message, null);
366   }
367 
368   /**
369    Log a message object with the <code>FATAL</code> level including
370    the stack trace of the {@link Throwable} <code>t</code> passed as
371    parameter.
372 
373    <p>See {@link #fatal(Object)} for more detailed information.
374 
375    @param message the message object to log.
376    @param t the exception to log, including its stack trace.  */
377   public
378   void fatal(Object message, Throwable t) {
379     if(repository.isDisabled(Level.FATAL_INT))
380       return;
381     if(Level.FATAL.isGreaterOrEqual(this.getEffectiveLevel()))
382       forcedLog(FQCN, Level.FATAL, message, t);
383   }
384 
385 
386   /**
387      This method creates a new logging event and logs the event
388      without further checks.  */
389   protected
390   void forcedLog(String fqcn, Priority level, Object message, Throwable t) {
391     callAppenders(new LoggingEvent(fqcn, this, level, message, t));
392   }
393 
394 
395   /**
396      Get the additivity flag for this Category instance.
397   */
398   public
399   boolean getAdditivity() {
400     return additive;
401   }
402 
403   /**
404      Get the appenders contained in this category as an {@link
405      Enumeration}. If no appenders can be found, then a {@link NullEnumeration}
406      is returned.
407 
408      @return Enumeration An enumeration of the appenders in this category.  */
409   synchronized
410   public
411   Enumeration getAllAppenders() {
412     if(aai == null)
413       return NullEnumeration.getInstance();
414     else
415       return aai.getAllAppenders();
416   }
417 
418   /**
419      Look for the appender named as <code>name</code>.
420 
421      <p>Return the appender with that name if in the list. Return
422      <code>null</code> otherwise.  */
423   synchronized
424   public
425   Appender getAppender(String name) {
426      if(aai == null || name == null)
427       return null;
428 
429      return aai.getAppender(name);
430   }
431 
432   /**
433      Starting from this category, search the category hierarchy for a
434      non-null level and return it. Otherwise, return the level of the
435      root category.
436 
437      <p>The Category class is designed so that this method executes as
438      quickly as possible.
439    */
440   public
441   Level getEffectiveLevel() {
442     for(Category c = this; c != null; c=c.parent) {
443       if(c.level != null)
444 	return c.level;
445     }
446     return null; // If reached will cause an NullPointerException.
447   }
448 
449   /**
450     *
451     * @deprecated Please use the the {@link #getEffectiveLevel} method
452     * instead.  
453     * */
454   public
455   Priority getChainedPriority() {
456     for(Category c = this; c != null; c=c.parent) {
457       if(c.level != null)
458 	return c.level;
459     }
460     return null; // If reached will cause an NullPointerException.
461   }
462 
463 
464   /**
465      Returns all the currently defined categories in the default
466      hierarchy as an {@link java.util.Enumeration Enumeration}.
467 
468      <p>The root category is <em>not</em> included in the returned
469      {@link Enumeration}.
470 
471      @deprecated Please use {@link LogManager#getCurrentLoggers()} instead.
472   */
473   public
474   static
475   Enumeration getCurrentCategories() {
476     return LogManager.getCurrentLoggers();
477   }
478 
479 
480   /**
481      Return the default Hierarchy instance.
482 
483      @deprecated Please use {@link LogManager#getLoggerRepository()} instead.
484 
485      @since 1.0
486    */
487   public
488   static
489   LoggerRepository getDefaultHierarchy() {
490     return LogManager.getLoggerRepository();
491   }
492 
493   /**
494      Return the the {@link Hierarchy} where this <code>Category</code>
495      instance is attached.
496 
497      @deprecated Please use {@link #getLoggerRepository} instead.
498 
499      @since 1.1 */
500   public
501   LoggerRepository  getHierarchy() {
502     return repository;
503   }
504 
505   /**
506      Return the the {@link LoggerRepository} where this
507      <code>Category</code> is attached.
508 
509      @since 1.2 */
510   public
511   LoggerRepository  getLoggerRepository() {
512     return repository;
513   }
514 
515 
516  /**
517   * @deprecated Make sure to use {@link Logger#getLogger(String)} instead.
518   */
519   public
520   static
521   Category getInstance(String name) {
522     return LogManager.getLogger(name);
523   }
524 
525  /**
526   * @deprecated Please make sure to use {@link Logger#getLogger(Class)} instead.
527   */ 
528   public
529   static
530   Category getInstance(Class clazz) {
531     return LogManager.getLogger(clazz);
532   }
533 
534 
535   /**
536      Return the category name.  */
537   public
538   final
539   String getName() {
540     return name;
541   }
542 
543 
544   /**
545      Returns the parent of this category. Note that the parent of a
546      given category may change during the lifetime of the category.
547 
548      <p>The root category will return <code>null</code>.
549 
550      @since 1.2
551   */
552   final
553   public
554   Category getParent() {
555     return this.parent;
556   }
557 
558 
559   /**
560      Returns the assigned {@link Level}, if any, for this Category.
561 
562      @return Level - the assigned Level, can be <code>null</code>.
563   */
564   final
565   public
566   Level getLevel() {
567     return this.level;
568   }
569 
570   /**
571      @deprecated Please use {@link #getLevel} instead.
572   */
573   final
574   public
575   Level getPriority() {
576     return this.level;
577   }
578 
579 
580   /**
581    *  @deprecated Please use {@link Logger#getRootLogger()} instead.
582    */
583   final
584   public
585   static
586   Category getRoot() {
587     return LogManager.getRootLogger();
588   }
589 
590   /**
591      Return the <em>inherited</em> {@link ResourceBundle} for this
592      category.
593 
594      <p>This method walks the hierarchy to find the appropriate
595      resource bundle. It will return the resource bundle attached to
596      the closest ancestor of this category, much like the way
597      priorities are searched. In case there is no bundle in the
598      hierarchy then <code>null</code> is returned.
599 
600      @since 0.9.0 */
601   public
602   ResourceBundle getResourceBundle() {
603     for(Category c = this; c != null; c=c.parent) {
604       if(c.resourceBundle != null)
605 	return c.resourceBundle;
606     }
607     // It might be the case that there is no resource bundle
608     return null;
609   }
610 
611   /**
612      Returns the string resource coresponding to <code>key</code> in
613      this category's inherited resource bundle. See also {@link
614      #getResourceBundle}.
615 
616      <p>If the resource cannot be found, then an {@link #error error}
617      message will be logged complaining about the missing resource.
618   */
619   protected
620   String getResourceBundleString(String key) {
621     ResourceBundle rb = getResourceBundle();
622     // This is one of the rare cases where we can use logging in order
623     // to report errors from within log4j.
624     if(rb == null) {
625       //if(!hierarchy.emittedNoResourceBundleWarning) {
626       //error("No resource bundle has been set for category "+name);
627       //hierarchy.emittedNoResourceBundleWarning = true;
628       //}
629       return null;
630     }
631     else {
632       try {
633 	return rb.getString(key);
634       }
635       catch(MissingResourceException mre) {
636 	error("No resource is associated with key \""+key+"\".");
637 	return null;
638       }
639     }
640   }
641 
642   /**
643     Log a message object with the {@link Level#INFO INFO} Level.
644 
645     <p>This method first checks if this category is <code>INFO</code>
646     enabled by comparing the level of this category with {@link
647     Level#INFO INFO} Level. If the category is <code>INFO</code>
648     enabled, then it converts the message object passed as parameter
649     to a string by invoking the appropriate
650     {@link org.apache.log4j.or.ObjectRenderer}. It
651     proceeds to call all the registered appenders in this category and
652     also higher in the hierarchy depending on the value of the
653     additivity flag.
654 
655     <p><b>WARNING</b> Note that passing a {@link Throwable} to this
656     method will print the name of the Throwable but no stack trace. To
657     print a stack trace use the {@link #info(Object, Throwable)} form
658     instead.
659 
660     @param message the message object to log */
661   public
662   void info(Object message) {
663     if(repository.isDisabled(Level.INFO_INT))
664       return;
665     if(Level.INFO.isGreaterOrEqual(this.getEffectiveLevel()))
666       forcedLog(FQCN, Level.INFO, message, null);
667   }
668 
669   /**
670    Log a message object with the <code>INFO</code> level including
671    the stack trace of the {@link Throwable} <code>t</code> passed as
672    parameter.
673 
674    <p>See {@link #info(Object)} for more detailed information.
675 
676    @param message the message object to log.
677    @param t the exception to log, including its stack trace.  */
678   public
679   void info(Object message, Throwable t) {
680     if(repository.isDisabled(Level.INFO_INT))
681       return;
682     if(Level.INFO.isGreaterOrEqual(this.getEffectiveLevel()))
683       forcedLog(FQCN, Level.INFO, message, t);
684   }
685 
686   /**
687      Is the appender passed as parameter attached to this category?
688    */
689   public
690   boolean isAttached(Appender appender) {
691     if(appender == null || aai == null)
692       return false;
693     else {
694       return aai.isAttached(appender);
695     }
696   }
697 
698   /**
699     *  Check whether this category is enabled for the <code>DEBUG</code>
700     *  Level.
701     *
702     *  <p> This function is intended to lessen the computational cost of
703     *  disabled log debug statements.
704     *
705     *  <p> For some <code>cat</code> Category object, when you write,
706     *  <pre>
707     *      cat.debug("This is entry number: " + i );
708     *  </pre>
709     *
710     *  <p>You incur the cost constructing the message, concatenatiion in
711     *  this case, regardless of whether the message is logged or not.
712     *
713     *  <p>If you are worried about speed, then you should write
714     *  <pre>
715     * 	 if(cat.isDebugEnabled()) {
716     * 	   cat.debug("This is entry number: " + i );
717     * 	 }
718     *  </pre>
719     *
720     *  <p>This way you will not incur the cost of parameter
721     *  construction if debugging is disabled for <code>cat</code>. On
722     *  the other hand, if the <code>cat</code> is debug enabled, you
723     *  will incur the cost of evaluating whether the category is debug
724     *  enabled twice. Once in <code>isDebugEnabled</code> and once in
725     *  the <code>debug</code>.  This is an insignificant overhead
726     *  since evaluating a category takes about 1%% of the time it
727     *  takes to actually log.
728     *
729     *  @return boolean - <code>true</code> if this category is debug
730     *  enabled, <code>false</code> otherwise.
731     *   */
732   public
733   boolean isDebugEnabled() {
734     if(repository.isDisabled( Level.DEBUG_INT))
735       return false;
736     return Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel());
737   }
738 
739   /**
740      Check whether this category is enabled for a given {@link
741      Level} passed as parameter.
742 
743      See also {@link #isDebugEnabled}.
744 
745      @return boolean True if this category is enabled for <code>level</code>.
746   */
747   public
748   boolean isEnabledFor(Priority level) {
749     if(repository.isDisabled(level.level))
750       return false;
751     return level.isGreaterOrEqual(this.getEffectiveLevel());
752   }
753 
754   /**
755     Check whether this category is enabled for the info Level.
756     See also {@link #isDebugEnabled}.
757 
758     @return boolean - <code>true</code> if this category is enabled
759     for level info, <code>false</code> otherwise.
760   */
761   public
762   boolean isInfoEnabled() {
763     if(repository.isDisabled(Level.INFO_INT))
764       return false;
765     return Level.INFO.isGreaterOrEqual(this.getEffectiveLevel());
766   }
767 
768 
769   /**
770      Log a localized message. The user supplied parameter
771      <code>key</code> is replaced by its localized version from the
772      resource bundle.
773 
774      @see #setResourceBundle
775 
776      @since 0.8.4 */
777   public
778   void l7dlog(Priority priority, String key, Throwable t) {
779     if(repository.isDisabled(priority.level)) {
780       return;
781     }
782     if(priority.isGreaterOrEqual(this.getEffectiveLevel())) {
783       String msg = getResourceBundleString(key);
784       // if message corresponding to 'key' could not be found in the
785       // resource bundle, then default to 'key'.
786       if(msg == null) {
787 	msg = key;
788       }
789       forcedLog(FQCN, priority, msg, t);
790     }
791   }
792   /**
793      Log a localized and parameterized message. First, the user
794      supplied <code>key</code> is searched in the resource
795      bundle. Next, the resulting pattern is formatted using
796      {@link java.text.MessageFormat#format(String,Object[])} method with the
797      user supplied object array <code>params</code>.
798 
799      @since 0.8.4
800   */
801   public
802   void l7dlog(Priority priority, String key,  Object[] params, Throwable t) {
803     if(repository.isDisabled(priority.level)) {
804       return;
805     }
806     if(priority.isGreaterOrEqual(this.getEffectiveLevel())) {
807       String pattern = getResourceBundleString(key);
808       String msg;
809       if(pattern == null)
810 	msg = key;
811       else
812 	msg = java.text.MessageFormat.format(pattern, params);
813       forcedLog(FQCN, priority, msg, t);
814     }
815   }
816 
817   /**
818      This generic form is intended to be used by wrappers.
819    */
820   public
821   void log(Priority priority, Object message, Throwable t) {
822     if(repository.isDisabled(priority.level)) {
823       return;
824     }
825     if(priority.isGreaterOrEqual(this.getEffectiveLevel()))
826       forcedLog(FQCN, priority, message, t);
827   }
828 
829  /**
830     This generic form is intended to be used by wrappers.
831  */
832   public
833   void log(Priority priority, Object message) {
834     if(repository.isDisabled(priority.level)) {
835       return;
836     }
837     if(priority.isGreaterOrEqual(this.getEffectiveLevel()))
838       forcedLog(FQCN, priority, message, null);
839   }
840 
841   /**
842 
843      This is the most generic printing method. It is intended to be
844      invoked by <b>wrapper</b> classes.
845 
846      @param callerFQCN The wrapper class' fully qualified class name.
847      @param level The level of the logging request.
848      @param message The message of the logging request.
849      @param t The throwable of the logging request, may be null.  */
850   public
851   void log(String callerFQCN, Priority level, Object message, Throwable t) {
852     if(repository.isDisabled(level.level)) {
853       return;
854     }
855     if(level.isGreaterOrEqual(this.getEffectiveLevel())) {
856       forcedLog(callerFQCN, level, message, t);
857     }
858   }
859 
860     /**
861       *  LoggerRepository forgot the fireRemoveAppenderEvent method,
862       *     if using the stock Hierarchy implementation, then call its fireRemove.
863       *     Custom repositories can implement HierarchyEventListener if they
864       *     want remove notifications.
865      * @param appender appender, may be null.
866      */
867    private void fireRemoveAppenderEvent(final Appender appender) {
868        if (appender != null) {
869          if (repository instanceof Hierarchy) {
870            ((Hierarchy) repository).fireRemoveAppenderEvent(this, appender);
871          } else if (repository instanceof HierarchyEventListener) {
872              ((HierarchyEventListener) repository).removeAppenderEvent(this, appender);
873          }
874        }
875    }
876 
877   /**
878      Remove all previously added appenders from this Category
879      instance.
880 
881      <p>This is useful when re-reading configuration information.
882   */
883   synchronized
884   public
885   void removeAllAppenders() {
886     if(aai != null) {
887       Vector appenders = new Vector();
888       for (Enumeration iter = aai.getAllAppenders(); iter != null && iter.hasMoreElements();) {
889           appenders.add(iter.nextElement());
890       }
891       aai.removeAllAppenders();
892       for(Enumeration iter = appenders.elements(); iter.hasMoreElements();) {
893           fireRemoveAppenderEvent((Appender) iter.nextElement());
894       }
895       aai = null;
896     }
897   }
898 
899 
900   /**
901      Remove the appender passed as parameter form the list of appenders.
902 
903      @since 0.8.2
904   */
905   synchronized
906   public
907   void removeAppender(Appender appender) {
908     if(appender == null || aai == null)
909       return;
910     boolean wasAttached = aai.isAttached(appender);
911     aai.removeAppender(appender);
912     if (wasAttached) {
913         fireRemoveAppenderEvent(appender);
914     }
915   }
916 
917   /**
918      Remove the appender with the name passed as parameter form the
919      list of appenders.
920 
921      @since 0.8.2 */
922   synchronized
923   public
924   void removeAppender(String name) {
925     if(name == null || aai == null) return;
926     Appender appender = aai.getAppender(name);
927     aai.removeAppender(name);
928     if (appender != null) {
929         fireRemoveAppenderEvent(appender);
930     }
931   }
932 
933   /**
934      Set the additivity flag for this Category instance.
935      @since 0.8.1
936    */
937   public
938   void setAdditivity(boolean additive) {
939     this.additive = additive;
940   }
941 
942   /**
943      Only the Hiearchy class can set the hiearchy of a
944      category. Default package access is MANDATORY here.  */
945   final
946   void setHierarchy(LoggerRepository repository) {
947     this.repository = repository;
948   }
949 
950   /**
951      Set the level of this Category. If you are passing any of
952      <code>Level.DEBUG</code>, <code>Level.INFO</code>,
953      <code>Level.WARN</code>, <code>Level.ERROR</code>,
954      <code>Level.FATAL</code> as a parameter, you need to case them as
955      Level.
956 
957      <p>As in <pre> &nbsp;&nbsp;&nbsp;logger.setLevel((Level) Level.DEBUG); </pre>
958 
959 
960      <p>Null values are admitted.  */
961   public
962   void setLevel(Level level) {
963     this.level = level;
964   }
965 
966 
967   /**
968      Set the level of this Category.
969 
970      <p>Null values are admitted.
971 
972      @deprecated Please use {@link #setLevel} instead.
973   */
974   public
975   void setPriority(Priority priority) {
976     this.level = (Level) priority;
977   }
978 
979 
980   /**
981      Set the resource bundle to be used with localized logging
982      methods {@link #l7dlog(Priority,String,Throwable)} and {@link
983      #l7dlog(Priority,String,Object[],Throwable)}.
984 
985      @since 0.8.4
986    */
987   public
988   void setResourceBundle(ResourceBundle bundle) {
989     resourceBundle = bundle;
990   }
991 
992   /**
993      Calling this method will <em>safely</em> close and remove all
994      appenders in all the categories including root contained in the
995      default hierachy.
996 
997      <p>Some appenders such as {@link org.apache.log4j.net.SocketAppender}
998      and {@link AsyncAppender} need to be closed before the
999      application exists. Otherwise, pending logging events might be
1000      lost.
1001 
1002      <p>The <code>shutdown</code> method is careful to close nested
1003      appenders before closing regular appenders. This is allows
1004      configurations where a regular appender is attached to a category
1005      and again to a nested appender.
1006 
1007      @deprecated Please use {@link LogManager#shutdown()} instead.
1008 
1009      @since 1.0
1010   */
1011   public
1012   static
1013   void shutdown() {
1014     LogManager.shutdown();
1015   }
1016 
1017 
1018   /**
1019     Log a message object with the {@link Level#WARN WARN} Level.
1020 
1021     <p>This method first checks if this category is <code>WARN</code>
1022     enabled by comparing the level of this category with {@link
1023     Level#WARN WARN} Level. If the category is <code>WARN</code>
1024     enabled, then it converts the message object passed as parameter
1025     to a string by invoking the appropriate
1026     {@link org.apache.log4j.or.ObjectRenderer}. It
1027     proceeds to call all the registered appenders in this category and
1028     also higher in the hieararchy depending on the value of the
1029     additivity flag.
1030 
1031     <p><b>WARNING</b> Note that passing a {@link Throwable} to this
1032     method will print the name of the Throwable but no stack trace. To
1033     print a stack trace use the {@link #warn(Object, Throwable)} form
1034     instead.  <p>
1035 
1036     @param message the message object to log.  */
1037   public
1038   void warn(Object message) {
1039     if(repository.isDisabled( Level.WARN_INT))
1040       return;
1041 
1042     if(Level.WARN.isGreaterOrEqual(this.getEffectiveLevel()))
1043       forcedLog(FQCN, Level.WARN, message, null);
1044   }
1045 
1046   /**
1047    Log a message with the <code>WARN</code> level including the
1048    stack trace of the {@link Throwable} <code>t</code> passed as
1049    parameter.
1050 
1051    <p>See {@link #warn(Object)} for more detailed information.
1052 
1053    @param message the message object to log.
1054    @param t the exception to log, including its stack trace.  */
1055   public
1056   void warn(Object message, Throwable t) {
1057     if(repository.isDisabled(Level.WARN_INT))
1058       return;
1059     if(Level.WARN.isGreaterOrEqual(this.getEffectiveLevel()))
1060       forcedLog(FQCN, Level.WARN, message, t);
1061   }
1062 }