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