001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 * 
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 * 
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018// Contibutors: Alex Blewitt <Alex.Blewitt@ioshq.com>
019//              Markus Oestreicher <oes@zurich.ibm.com>
020//              Frank Hoering <fhr@zurich.ibm.com>
021//              Nelson Minar <nelson@media.mit.edu>
022//              Jim Cakalic <jim_cakalic@na.biomerieux.com>
023//              Avy Sharell <asharell@club-internet.fr>
024//              Ciaran Treanor <ciaran@xelector.com>
025//              Jeff Turner <jeff@socialchange.net.au>
026//              Michael Horwitz <MHorwitz@siemens.co.za>
027//              Calvin Chan <calvin.chan@hic.gov.au>
028//              Aaron Greenhouse <aarong@cs.cmu.edu>
029//              Beat Meier <bmeier@infovia.com.ar>
030//              Colin Sampaleanu <colinml1@exis.com>
031
032package org.apache.log4j;
033
034import org.apache.log4j.spi.AppenderAttachable;
035import org.apache.log4j.spi.LoggingEvent;
036import org.apache.log4j.spi.LoggerRepository;
037import org.apache.log4j.spi.HierarchyEventListener;
038import org.apache.log4j.helpers.NullEnumeration;
039import org.apache.log4j.helpers.AppenderAttachableImpl;
040
041import java.util.Enumeration;
042import java.util.MissingResourceException;
043import java.util.ResourceBundle;
044import java.util.Vector;
045
046
047/**
048  * <font color="#AA2222"><b>This class has been deprecated and
049  * replaced by the {@link Logger} <em>subclass</em></b></font>. It
050  * will be kept around to preserve backward compatibility until mid
051  * 2003.
052  * 
053  * <p><code>Logger</code> is a subclass of Category, i.e. it extends
054  * Category. In other words, a logger <em>is</em> a category. Thus,
055  * all operations that can be performed on a category can be
056  * performed on a logger. Internally, whenever log4j is asked to
057  * produce a Category object, it will instead produce a Logger
058  * object. Log4j 1.2 will <em>never</em> produce Category objects but
059  * only <code>Logger</code> instances. In order to preserve backward
060  * compatibility, methods that previously accepted category objects
061  * still continue to accept category objects.
062  * 
063  * <p>For example, the following are all legal and will work as
064  * expected.
065  * 
066   <pre>
067    &nbsp;&nbsp;&nbsp;// Deprecated form:
068    &nbsp;&nbsp;&nbsp;Category cat = Category.getInstance("foo.bar")
069   
070    &nbsp;&nbsp;&nbsp;// Preferred form for retrieving loggers:
071    &nbsp;&nbsp;&nbsp;Logger logger = Logger.getLogger("foo.bar")
072   </pre>
073   
074  *  <p>The first form is deprecated and should be avoided.
075  * 
076  *  <p><b>There is absolutely no need for new client code to use or
077  *  refer to the <code>Category</code> class.</b> Whenever possible,
078  *  please avoid referring to it or using it.
079  * 
080  * <p>See the <a href="../../../../manual.html">short manual</a> for an
081  * introduction on this class.
082  * <p>
083  * See the document entitled <a href="http://www.qos.ch/logging/preparingFor13.html">preparing
084  *  for log4j 1.3</a> for a more detailed discussion.
085  *
086  * @author Ceki G&uuml;lc&uuml;
087  * @author Anders Kristensen 
088  */
089public class Category implements AppenderAttachable {
090
091  /**
092     The hierarchy where categories are attached to by default.
093  */
094  //static
095  //public
096  //final Hierarchy defaultHierarchy = new Hierarchy(new
097  //                                       RootCategory(Level.DEBUG));
098
099  /**
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}