Source for java.util.logging.Logger

   1: /* Logger.java -- a class for logging messages
   2:    Copyright (C) 2002, 2004 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package java.util.logging;
  40: 
  41: import java.util.List;
  42: import java.util.MissingResourceException;
  43: import java.util.ResourceBundle;
  44: 
  45: /**
  46:  * A Logger is used for logging information about events. Usually, there
  47:  * is a seprate logger for each subsystem or component, although there
  48:  * is a shared instance for components that make only occasional use of
  49:  * the logging framework.
  50:  *
  51:  * <p>It is common to name a logger after the name of a corresponding
  52:  * Java package.  Loggers are organized into a hierarchical namespace;
  53:  * for example, the logger <code>"org.gnu.foo"</code> is the
  54:  * <em>parent</em> of logger <code>"org.gnu.foo.bar"</code>.
  55:  *
  56:  * <p>A logger for a named subsystem can be obtained through {@link
  57:  * java.util.logging.Logger#getLogger(java.lang.String)}.  However,
  58:  * only code which has been granted the permission to control the
  59:  * logging infrastructure will be allowed to customize that logger.
  60:  * Untrusted code can obtain a private, anonymous logger through
  61:  * {@link #getAnonymousLogger()} if it wants to perform any
  62:  * modifications to the logger.
  63:  *
  64:  * <p>FIXME: Write more documentation.
  65:  *
  66:  * @author Sascha Brawer (brawer@acm.org)
  67:  */
  68: public class Logger
  69: {
  70:   /**
  71:    * A logger provided to applications that make only occasional use
  72:    * of the logging framework, typically early prototypes.  Serious
  73:    * products are supposed to create and use their own Loggers, so
  74:    * they can be controlled individually.
  75:    */
  76:   public static final Logger global = getLogger("global");
  77: 
  78: 
  79:   /**
  80:    * The name of the Logger, or <code>null</code> if the logger is
  81:    * anonymous.
  82:    *
  83:    * <p>A previous version of the GNU Classpath implementation granted
  84:    * untrusted code the permission to control any logger whose name
  85:    * was null.  However, test code revealed that the Sun J2SE 1.4
  86:    * reference implementation enforces the security control for any
  87:    * logger that was not created through getAnonymousLogger, even if
  88:    * it has a null name.  Therefore, a separate flag {@link
  89:    * Logger#anonymous} was introduced.
  90:    */
  91:   private final String name;
  92: 
  93: 
  94:   /**
  95:    * The name of the resource bundle used for localization.
  96:    *
  97:    * <p>This variable cannot be declared as <code>final</code>
  98:    * because its value can change as a result of calling
  99:    * getLogger(String,String).
 100:    */
 101:   private String resourceBundleName;
 102: 
 103: 
 104:   /**
 105:    * The resource bundle used for localization.
 106:    *
 107:    * <p>This variable cannot be declared as <code>final</code>
 108:    * because its value can change as a result of calling
 109:    * getLogger(String,String).
 110:    */
 111:   private ResourceBundle resourceBundle;
 112: 
 113:   private Filter filter;
 114: 
 115:   private final List handlerList = new java.util.ArrayList(4);
 116:   private Handler[] handlers = new Handler[0];
 117: 
 118:   /**
 119:    * Indicates whether or not this logger is anonymous.  While
 120:    * a LoggingPermission is required for any modifications to
 121:    * a normal logger, untrusted code can obtain an anonymous logger
 122:    * and modify it according to its needs.
 123:    *
 124:    * <p>A previous version of the GNU Classpath implementation
 125:    * granted access to every logger whose name was null.
 126:    * However, test code revealed that the Sun J2SE 1.4 reference
 127:    * implementation enforces the security control for any logger
 128:    * that was not created through getAnonymousLogger, even
 129:    * if it has a null name.
 130:    */
 131:   private boolean anonymous;
 132: 
 133: 
 134:   private boolean useParentHandlers;
 135: 
 136:   private Level level;
 137: 
 138:   private Logger parent;
 139: 
 140:   /**
 141:    * Constructs a Logger for a subsystem.  Most applications do not
 142:    * need to create new Loggers explicitly; instead, they should call
 143:    * the static factory methods
 144:    * {@link #getLogger(java.lang.String,java.lang.String) getLogger}
 145:    * (with ResourceBundle for localization) or
 146:    * {@link #getLogger(java.lang.String) getLogger} (without
 147:    * ResourceBundle), respectively.
 148:    *
 149:    * @param name the name for the logger, for example "java.awt"
 150:    *             or "com.foo.bar". The name should be based on
 151:    *             the name of the package issuing log records
 152:    *             and consist of dot-separated Java identifiers.
 153:    *
 154:    * @param resourceBundleName the name of a resource bundle
 155:    *        for localizing messages, or <code>null</code>
 156:    *        to indicate that messages do not need to be localized.
 157:    *
 158:    * @throws java.util.MissingResourceException if
 159:    *         <code>resourceBundleName</code> is not <code>null</code>
 160:    *         and no such bundle could be located.
 161:    */
 162:   protected Logger(String name, String resourceBundleName)
 163:     throws MissingResourceException
 164:   {
 165:     this.name = name;
 166:     this.resourceBundleName = resourceBundleName;
 167: 
 168:     if (resourceBundleName == null)
 169:       resourceBundle = null;
 170:     else
 171:       resourceBundle = ResourceBundle.getBundle(resourceBundleName);
 172: 
 173:     level = null;
 174: 
 175:     /* This is null when the root logger is being constructed,
 176:      * and the root logger afterwards.
 177:      */
 178:     parent = LogManager.getLogManager().rootLogger;
 179: 
 180:     useParentHandlers = (parent != null);
 181:   }
 182: 
 183: 
 184: 
 185:   /**
 186:    * Finds a registered logger for a subsystem, or creates one in
 187:    * case no logger has been registered yet.
 188:    *
 189:    * @param name the name for the logger, for example "java.awt"
 190:    *             or "com.foo.bar". The name should be based on
 191:    *             the name of the package issuing log records
 192:    *             and consist of dot-separated Java identifiers.
 193:    *
 194:    * @throws IllegalArgumentException if a logger for the subsystem
 195:    *         identified by <code>name</code> has already been created,
 196:    *         but uses a a resource bundle for localizing messages.
 197:    *
 198:    * @throws NullPointerException if <code>name</code> is
 199:    *         <code>null</code>.
 200:    *
 201:    * @return a logger for the subsystem specified by <code>name</code>
 202:    *         that does not localize messages.
 203:    */
 204:   public static Logger getLogger(String name)
 205:   {
 206:     return getLogger(name, null);
 207:   }
 208: 
 209:     
 210:   /**
 211:    * Finds a registered logger for a subsystem, or creates one in case
 212:    * no logger has been registered yet.
 213:    *
 214:    * <p>If a logger with the specified name has already been
 215:    * registered, the behavior depends on the resource bundle that is
 216:    * currently associated with the existing logger.
 217:    *
 218:    * <ul><li>If the existing logger uses the same resource bundle as
 219:    * specified by <code>resourceBundleName</code>, the existing logger
 220:    * is returned.</li>
 221:    *
 222:    * <li>If the existing logger currently does not localize messages,
 223:    * the existing logger is modified to use the bundle specified by
 224:    * <code>resourceBundleName</code>.  The existing logger is then
 225:    * returned.  Therefore, all subsystems currently using this logger
 226:    * will produce localized messages from now on.</li>
 227:    *
 228:    * <li>If the existing logger already has an associated resource
 229:    * bundle, but a different one than specified by
 230:    * <code>resourceBundleName</code>, an
 231:    * <code>IllegalArgumentException</code> is thrown.</li></ul>
 232:    *
 233:    * @param name the name for the logger, for example "java.awt"
 234:    *             or "org.gnu.foo". The name should be based on
 235:    *             the name of the package issuing log records
 236:    *             and consist of dot-separated Java identifiers.
 237:    *
 238:    * @param resourceBundleName the name of a resource bundle
 239:    *        for localizing messages, or <code>null</code>
 240:    *        to indicate that messages do not need to be localized.
 241:    *
 242:    * @return a logger for the subsystem specified by <code>name</code>.
 243:    *
 244:    * @throws java.util.MissingResourceException if
 245:    *         <code>resourceBundleName</code> is not <code>null</code>
 246:    *         and no such bundle could be located.   
 247:    *
 248:    * @throws IllegalArgumentException if a logger for the subsystem
 249:    *         identified by <code>name</code> has already been created,
 250:    *         but uses a different resource bundle for localizing
 251:    *         messages.
 252:    *
 253:    * @throws NullPointerException if <code>name</code> is
 254:    *         <code>null</code>.
 255:    */
 256:   public static Logger getLogger(String name, String resourceBundleName)
 257:   {
 258:     LogManager lm = LogManager.getLogManager();
 259:     Logger     result;
 260: 
 261:     /* Throw NullPointerException if name is null. */
 262:     name.getClass();
 263: 
 264:     /* Without synchronized(lm), it could happen that another thread
 265:      * would create a logger between our calls to getLogger and
 266:      * addLogger.  While addLogger would indicate this by returning
 267:      * false, we could not be sure that this other logger was still
 268:      * existing when we called getLogger a second time in order
 269:      * to retrieve it -- note that LogManager is only allowed to
 270:      * keep weak references to registered loggers, so Loggers
 271:      * can be garbage collected at any time in general, and between
 272:      * our call to addLogger and our second call go getLogger
 273:      * in particular.
 274:      *
 275:      * Of course, we assume here that LogManager.addLogger etc.
 276:      * are synchronizing on the global LogManager object. There
 277:      * is a comment in the implementation of LogManager.addLogger
 278:      * referring to this comment here, so that any change in
 279:      * the synchronization of LogManager will be reflected here.
 280:      */
 281:     synchronized (lm)
 282:     {
 283:       result = lm.getLogger(name);
 284:       if (result == null)
 285:       {
 286:     boolean couldBeAdded;
 287: 
 288:     result = new Logger(name, resourceBundleName);
 289:     couldBeAdded = lm.addLogger(result);
 290:     if (!couldBeAdded)
 291:       throw new IllegalStateException("cannot register new logger");
 292:       }
 293:       else
 294:       {
 295:     /* The logger already exists. Make sure it uses
 296:      * the same resource bundle for localizing messages.
 297:      */
 298:     String existingBundleName = result.getResourceBundleName();
 299: 
 300:     /* The Sun J2SE 1.4 reference implementation will return the
 301:      * registered logger object, even if it does not have a resource
 302:      * bundle associated with it. However, it seems to change the
 303:      * resourceBundle of the registered logger to the bundle
 304:      * whose name was passed to getLogger.
 305:      */
 306:     if ((existingBundleName == null) && (resourceBundleName != null))
 307:     {
 308:       /* If ResourceBundle.getBundle throws an exception, the
 309:        * existing logger will be unchanged.  This would be
 310:        * different if the assignment to resourceBundleName
 311:        * came first.
 312:        */
 313:       result.resourceBundle = ResourceBundle.getBundle(resourceBundleName);
 314:       result.resourceBundleName = resourceBundleName;
 315:       return result;
 316:     }
 317: 
 318:     if ((existingBundleName != resourceBundleName)
 319:         && ((existingBundleName == null)
 320:         || !existingBundleName.equals(resourceBundleName)))
 321:     {
 322:       throw new IllegalArgumentException();
 323:     }
 324:       }
 325:     }
 326: 
 327:     return result;
 328:   }
 329: 
 330:   
 331:   /**
 332:    * Creates a new, unnamed logger.  Unnamed loggers are not
 333:    * registered in the namespace of the LogManager, and no special
 334:    * security permission is required for changing their state.
 335:    * Therefore, untrusted applets are able to modify their private
 336:    * logger instance obtained through this method.
 337:    *
 338:    * <p>The parent of the newly created logger will the the root
 339:    * logger, from which the level threshold and the handlers are
 340:    * inherited.
 341:    */
 342:   public static Logger getAnonymousLogger()
 343:   {
 344:     return getAnonymousLogger(null);
 345:   }
 346: 
 347: 
 348:   /**
 349:    * Creates a new, unnamed logger.  Unnamed loggers are not
 350:    * registered in the namespace of the LogManager, and no special
 351:    * security permission is required for changing their state.
 352:    * Therefore, untrusted applets are able to modify their private
 353:    * logger instance obtained through this method.
 354:    *
 355:    * <p>The parent of the newly created logger will the the root
 356:    * logger, from which the level threshold and the handlers are
 357:    * inherited.
 358:    *
 359:    * @param resourceBundleName the name of a resource bundle
 360:    *        for localizing messages, or <code>null</code>
 361:    *        to indicate that messages do not need to be localized.
 362:    *
 363:    * @throws java.util.MissingResourceException if
 364:    *         <code>resourceBundleName</code> is not <code>null</code>
 365:    *         and no such bundle could be located.
 366:    */
 367:   public static Logger getAnonymousLogger(String resourceBundleName)
 368:     throws MissingResourceException
 369:   {
 370:     Logger  result;
 371: 
 372:     result = new Logger(null, resourceBundleName);
 373:     result.anonymous = true;
 374:     return result;
 375:   }
 376: 
 377: 
 378:   /**
 379:    * Returns the name of the resource bundle that is being used for
 380:    * localizing messages.
 381:    *
 382:    * @return the name of the resource bundle used for localizing messages,
 383:    *         or <code>null</code> if the parent's resource bundle
 384:    *         is used for this purpose.
 385:    */
 386:   public synchronized String getResourceBundleName()
 387:   {
 388:     return resourceBundleName;
 389:   }
 390: 
 391: 
 392:   /**
 393:    * Returns the resource bundle that is being used for localizing
 394:    * messages.
 395:    *
 396:    * @return the resource bundle used for localizing messages,
 397:    *         or <code>null</code> if the parent's resource bundle
 398:    *         is used for this purpose.
 399:    */
 400:   public synchronized ResourceBundle getResourceBundle()
 401:   {
 402:     return resourceBundle;
 403:   }
 404: 
 405: 
 406:   /**
 407:    * Returns the severity level threshold for this <code>Handler</code>.
 408:    * All log records with a lower severity level will be discarded;
 409:    * a log record of the same or a higher level will be published
 410:    * unless an installed <code>Filter</code> decides to discard it.
 411:    *
 412:    * @return the severity level below which all log messages will be
 413:    *         discarded, or <code>null</code> if the logger inherits
 414:    *         the threshold from its parent.
 415:    */
 416:   public synchronized Level getLevel()
 417:   {
 418:     return level;
 419:   }
 420: 
 421: 
 422:   /**
 423:    * Returns whether or not a message of the specified level
 424:    * would be logged by this logger.
 425:    *
 426:    * @throws NullPointerException if <code>level</code>
 427:    *         is <code>null</code>.
 428:    */
 429:   public synchronized boolean isLoggable(Level level)
 430:   {
 431:     if (this.level != null)
 432:       return this.level.intValue() <= level.intValue();
 433: 
 434:     if (parent != null)
 435:       return parent.isLoggable(level);
 436:     else
 437:       return false;
 438:   }
 439: 
 440: 
 441:   /**
 442:    * Sets the severity level threshold for this <code>Handler</code>.
 443:    * All log records with a lower severity level will be discarded
 444:    * immediately.  A log record of the same or a higher level will be
 445:    * published unless an installed <code>Filter</code> decides to
 446:    * discard it.
 447:    *
 448:    * @param level the severity level below which all log messages
 449:    *              will be discarded, or <code>null</code> to
 450:    *              indicate that the logger should inherit the
 451:    *              threshold from its parent.
 452:    *
 453:    * @throws SecurityException if this logger is not anonymous, a
 454:    *     security manager exists, and the caller is not granted
 455:    *     the permission to control the logging infrastructure by
 456:    *     having LoggingPermission("control").  Untrusted code can
 457:    *     obtain an anonymous logger through the static factory method
 458:    *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
 459:    */
 460:   public synchronized void setLevel(Level level)
 461:   {
 462:     /* An application is allowed to control an anonymous logger
 463:      * without having the permission to control the logging
 464:      * infrastructure.
 465:      */
 466:     if (!anonymous)
 467:       LogManager.getLogManager().checkAccess();
 468: 
 469:     this.level = level;
 470:   }
 471: 
 472: 
 473:   public synchronized Filter getFilter()
 474:   {
 475:     return filter;
 476:   }
 477: 
 478: 
 479:   /**
 480:    * @throws SecurityException if this logger is not anonymous, a
 481:    *     security manager exists, and the caller is not granted
 482:    *     the permission to control the logging infrastructure by
 483:    *     having LoggingPermission("control").  Untrusted code can
 484:    *     obtain an anonymous logger through the static factory method
 485:    *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
 486:    */
 487:   public synchronized void setFilter(Filter filter)
 488:     throws SecurityException
 489:   {
 490:     /* An application is allowed to control an anonymous logger
 491:      * without having the permission to control the logging
 492:      * infrastructure.
 493:      */
 494:     if (!anonymous)
 495:       LogManager.getLogManager().checkAccess();
 496: 
 497:     this.filter = filter;
 498:   }
 499: 
 500: 
 501: 
 502: 
 503:   /**
 504:    * Returns the name of this logger.
 505:    *
 506:    * @return the name of this logger, or <code>null</code> if
 507:    *         the logger is anonymous.
 508:    */
 509:   public String getName()
 510:   {
 511:     /* Note that the name of a logger cannot be changed during
 512:      * its lifetime, so no synchronization is needed.
 513:      */
 514:     return name;
 515:   }
 516: 
 517: 
 518:   /**
 519:    * Passes a record to registered handlers, provided the record
 520:    * is considered as loggable both by {@link #isLoggable(Level)}
 521:    * and a possibly installed custom {@link #setFilter(Filter) filter}.
 522:    *
 523:    * <p>If the logger has been configured to use parent handlers,
 524:    * the record will be forwarded to the parent of this logger
 525:    * in addition to being processed by the handlers registered with
 526:    * this logger.
 527:    *
 528:    * <p>The other logging methods in this class are convenience methods
 529:    * that merely create a new LogRecord and pass it to this method.
 530:    * Therefore, subclasses usually just need to override this single
 531:    * method for customizing the logging behavior.
 532:    *
 533:    * @param record the log record to be inspected and possibly forwarded.
 534:    */
 535:   public synchronized void log(LogRecord record)
 536:   {
 537:     if (!isLoggable(record.getLevel()))
 538:       return;
 539: 
 540:     if ((filter != null) && !filter.isLoggable(record))
 541:       return;
 542: 
 543:     /* If no logger name has been set for the log record,
 544:      * use the name of this logger.
 545:      */
 546:     if (record.getLoggerName() == null)
 547:       record.setLoggerName(name);
 548: 
 549:     /* Avoid that some other thread is changing the logger hierarchy
 550:      * while we are traversing it.
 551:      */
 552:     synchronized (LogManager.getLogManager())
 553:     {
 554:       Logger curLogger = this;
 555: 
 556:       do
 557:       {
 558:         /* The Sun J2SE 1.4 reference implementation seems to call the
 559:      * filter only for the logger whose log method is called,
 560:      * never for any of its parents.  Also, parent loggers publish
 561:      * log record whatever their level might be.  This is pretty
 562:      * weird, but GNU Classpath tries to be as compatible as
 563:      * possible to the reference implementation.
 564:      */
 565:         for (int i = 0; i < curLogger.handlers.length; i++)
 566:           curLogger.handlers[i].publish(record);
 567: 
 568:     if (curLogger.getUseParentHandlers() == false)
 569:       break;
 570:     
 571:     curLogger = curLogger.getParent();
 572:       }
 573:       while (parent != null);
 574:     }
 575:   }
 576: 
 577: 
 578:   public void log(Level level, String message)
 579:   {
 580:     if (isLoggable(level))
 581:       log(level, message, (Object[]) null);
 582:   }
 583: 
 584: 
 585:   public synchronized void log(Level level,
 586:                    String message,
 587:                    Object param)
 588:   {
 589:     if (isLoggable(level))
 590:       {
 591:         StackTraceElement caller = getCallerStackFrame();
 592:         logp(level,
 593:              caller != null ? caller.getClassName() : "<unknown>",
 594:              caller != null ? caller.getMethodName() : "<unknown>",
 595:              message,
 596:              param);
 597:       }
 598:   }
 599: 
 600: 
 601:   public synchronized void log(Level level,
 602:                    String message,
 603:                    Object[] params)
 604:   {
 605:     if (isLoggable(level))
 606:       {
 607:         StackTraceElement caller = getCallerStackFrame();
 608:         logp(level,
 609:              caller != null ? caller.getClassName() : "<unknown>",
 610:              caller != null ? caller.getMethodName() : "<unknown>",
 611:              message,
 612:              params);
 613:       }
 614:   }
 615: 
 616: 
 617:   public synchronized void log(Level level,
 618:                    String message,
 619:                    Throwable thrown)
 620:   {
 621:     if (isLoggable(level))
 622:       {
 623:         StackTraceElement caller = getCallerStackFrame();    
 624:         logp(level,
 625:              caller != null ? caller.getClassName() : "<unknown>",
 626:              caller != null ? caller.getMethodName() : "<unknown>",
 627:              message,
 628:              thrown);
 629:       }
 630:   }
 631: 
 632: 
 633:   public synchronized void logp(Level level,
 634:                 String sourceClass,
 635:                 String sourceMethod,
 636:                 String message)
 637:   {
 638:     logp(level, sourceClass, sourceMethod, message,
 639:      (Object[]) null);
 640:   }
 641: 
 642: 
 643:   public synchronized void logp(Level level,
 644:                 String sourceClass,
 645:                 String sourceMethod,
 646:                 String message,
 647:                 Object param)
 648:   {
 649:     logp(level, sourceClass, sourceMethod, message,
 650:      new Object[] { param });
 651:   }
 652: 
 653: 
 654:   private synchronized ResourceBundle findResourceBundle()
 655:   {
 656:     if (resourceBundle != null)
 657:       return resourceBundle;
 658: 
 659:     if (parent != null)
 660:       return parent.findResourceBundle();
 661: 
 662:     return null;
 663:   }
 664: 
 665: 
 666:   private synchronized void logImpl(Level level,
 667:                     String sourceClass,
 668:                     String sourceMethod,
 669:                     String message,
 670:                     Object[] params)
 671:   {
 672:     LogRecord rec = new LogRecord(level, message);
 673: 
 674:     rec.setResourceBundle(findResourceBundle());
 675:     rec.setSourceClassName(sourceClass);
 676:     rec.setSourceMethodName(sourceMethod);
 677:     rec.setParameters(params);
 678: 
 679:     log(rec);
 680:   }
 681: 
 682: 
 683:   public synchronized void logp(Level level,
 684:                 String sourceClass,
 685:                 String sourceMethod,
 686:                 String message,
 687:                 Object[] params)
 688:   {
 689:     logImpl(level, sourceClass, sourceMethod, message, params);
 690:   }
 691: 
 692: 
 693:   public synchronized void logp(Level level,
 694:                 String sourceClass,
 695:                 String sourceMethod,
 696:                 String message,
 697:                 Throwable thrown)
 698:   {
 699:     LogRecord rec = new LogRecord(level, message);
 700: 
 701:     rec.setResourceBundle(resourceBundle);
 702:     rec.setSourceClassName(sourceClass);
 703:     rec.setSourceMethodName(sourceMethod);
 704:     rec.setThrown(thrown);
 705: 
 706:     log(rec);
 707:   }
 708: 
 709: 
 710:   public synchronized void logrb(Level level,
 711:                  String sourceClass,
 712:                  String sourceMethod,
 713:                  String bundleName,
 714:                  String message)
 715:   {
 716:     logrb(level, sourceClass, sourceMethod, bundleName,
 717:       message, (Object[]) null);
 718:   }
 719: 
 720: 
 721:   public synchronized void logrb(Level level,
 722:                  String sourceClass,
 723:                  String sourceMethod,
 724:                  String bundleName,
 725:                  String message,
 726:                  Object param)
 727:   {
 728:     logrb(level, sourceClass, sourceMethod, bundleName,
 729:       message, new Object[] { param });
 730:   }
 731: 
 732: 
 733:   public synchronized void logrb(Level level,
 734:                  String sourceClass,
 735:                  String sourceMethod,
 736:                  String bundleName,
 737:                  String message,
 738:                  Object[] params)
 739:   {
 740:     LogRecord rec = new LogRecord(level, message);
 741: 
 742:     rec.setResourceBundleName(bundleName);
 743:     rec.setSourceClassName(sourceClass);
 744:     rec.setSourceMethodName(sourceMethod);
 745:     rec.setParameters(params);
 746: 
 747:     log(rec);
 748:   }
 749: 
 750: 
 751:   public synchronized void logrb(Level level,
 752:                  String sourceClass,
 753:                  String sourceMethod,
 754:                  String bundleName,
 755:                  String message,
 756:                  Throwable thrown)
 757:   {
 758:     LogRecord rec = new LogRecord(level, message);
 759: 
 760:     rec.setResourceBundleName(bundleName);
 761:     rec.setSourceClassName(sourceClass);
 762:     rec.setSourceMethodName(sourceMethod);
 763:     rec.setThrown(thrown);
 764: 
 765:     log(rec);
 766:   }
 767: 
 768: 
 769:   public synchronized void entering(String sourceClass,
 770:                     String sourceMethod)
 771:   {
 772:     if (isLoggable(Level.FINER))
 773:       logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
 774:   }
 775: 
 776: 
 777:   public synchronized void entering(String sourceClass,
 778:                     String sourceMethod,
 779:                     Object param)
 780:   {
 781:     if (isLoggable(Level.FINER))
 782:       logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param);
 783:   }
 784: 
 785: 
 786:   public synchronized void entering(String sourceClass,
 787:                     String sourceMethod,
 788:                     Object[] params)
 789:   {
 790:     if (isLoggable(Level.FINER))
 791:     {
 792:       StringBuffer buf = new StringBuffer(80);
 793:       buf.append("ENTRY");
 794:       for (int i = 0; i < params.length; i++)
 795:       {
 796:     buf.append(" {");
 797:     buf.append(i);
 798:     buf.append('}');
 799:       }
 800:       
 801:       logp(Level.FINER, sourceClass, sourceMethod, buf.toString(), params);
 802:     }
 803:   }
 804: 
 805: 
 806:   public synchronized void exiting(String sourceClass,
 807:                    String sourceMethod)
 808:   {
 809:     if (isLoggable(Level.FINER))
 810:       logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
 811:   }
 812: 
 813:    
 814:   public synchronized void exiting(String sourceClass,
 815:                    String sourceMethod,
 816:                    Object result)
 817:   {
 818:     if (isLoggable(Level.FINER))
 819:       logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
 820:   }
 821: 
 822:  
 823:   public synchronized void throwing(String sourceClass,
 824:                     String sourceMethod,
 825:                     Throwable thrown)
 826:   {
 827:     if (isLoggable(Level.FINER))
 828:       logp(Level.FINER, sourceClass, sourceMethod, "THROW", thrown);
 829:   }
 830: 
 831: 
 832:   /**
 833:    * Logs a message with severity level SEVERE, indicating a serious
 834:    * failure that prevents normal program execution.  Messages at this
 835:    * level should be understandable to an inexperienced, non-technical
 836:    * end user.  Ideally, they explain in simple words what actions the
 837:    * user can take in order to resolve the problem.
 838:    *
 839:    * @see Level#SEVERE
 840:    *
 841:    * @param message the message text, also used as look-up key if the
 842:    *                logger is localizing messages with a resource
 843:    *                bundle.  While it is possible to pass
 844:    *                <code>null</code>, this is not recommended, since
 845:    *                a logging message without text is unlikely to be
 846:    *                helpful.
 847:    */
 848:   public synchronized void severe(String message)
 849:   {
 850:     if (isLoggable(Level.SEVERE))
 851:       log(Level.SEVERE, message);
 852:   }
 853: 
 854: 
 855:   /**
 856:    * Logs a message with severity level WARNING, indicating a
 857:    * potential problem that does not prevent normal program execution.
 858:    * Messages at this level should be understandable to an
 859:    * inexperienced, non-technical end user.  Ideally, they explain in
 860:    * simple words what actions the user can take in order to resolve
 861:    * the problem.
 862:    *
 863:    * @see Level#WARNING
 864:    *
 865:    * @param message the message text, also used as look-up key if the
 866:    *                logger is localizing messages with a resource
 867:    *                bundle.  While it is possible to pass
 868:    *                <code>null</code>, this is not recommended, since
 869:    *                a logging message without text is unlikely to be
 870:    *                helpful.
 871:    */
 872:   public synchronized void warning(String message)
 873:   {
 874:     if (isLoggable(Level.WARNING))
 875:       log(Level.WARNING, message);
 876:   }
 877: 
 878: 
 879:   /**
 880:    * Logs a message with severity level INFO.  {@link Level#INFO} is
 881:    * intended for purely informational messages that do not indicate
 882:    * error or warning situations. In the default logging
 883:    * configuration, INFO messages will be written to the system
 884:    * console.  For this reason, the INFO level should be used only for
 885:    * messages that are important to end users and system
 886:    * administrators.  Messages at this level should be understandable
 887:    * to an inexperienced, non-technical user.
 888:    *
 889:    * @param message the message text, also used as look-up key if the
 890:    *                logger is localizing messages with a resource
 891:    *                bundle.  While it is possible to pass
 892:    *                <code>null</code>, this is not recommended, since
 893:    *                a logging message without text is unlikely to be
 894:    *                helpful.
 895:    */
 896:   public synchronized void info(String message)
 897:   {
 898:     if (isLoggable(Level.INFO))
 899:       log(Level.INFO, message);
 900:   }
 901: 
 902: 
 903:   /**
 904:    * Logs a message with severity level CONFIG.  {@link Level#CONFIG} is
 905:    * intended for static configuration messages, for example about the
 906:    * windowing environment, the operating system version, etc.
 907:    *
 908:    * @param message the message text, also used as look-up key if the
 909:    *     logger is localizing messages with a resource bundle.  While
 910:    *     it is possible to pass <code>null</code>, this is not
 911:    *     recommended, since a logging message without text is unlikely
 912:    *     to be helpful.
 913:    */
 914:   public synchronized void config(String message)
 915:   {
 916:     if (isLoggable(Level.CONFIG))
 917:       log(Level.CONFIG, message);
 918:   }
 919: 
 920: 
 921:   /**
 922:    * Logs a message with severity level FINE.  {@link Level#FINE} is
 923:    * intended for messages that are relevant for developers using
 924:    * the component generating log messages. Examples include minor,
 925:    * recoverable failures, or possible inefficiencies.
 926:    *
 927:    * @param message the message text, also used as look-up key if the
 928:    *                logger is localizing messages with a resource
 929:    *                bundle.  While it is possible to pass
 930:    *                <code>null</code>, this is not recommended, since
 931:    *                a logging message without text is unlikely to be
 932:    *                helpful.
 933:    */
 934:   public synchronized void fine(String message)
 935:   {
 936:     if (isLoggable(Level.FINE))
 937:       log(Level.FINE, message);
 938:   }
 939: 
 940: 
 941:   /**
 942:    * Logs a message with severity level FINER.  {@link Level#FINER} is
 943:    * intended for rather detailed tracing, for example entering a
 944:    * method, returning from a method, or throwing an exception.
 945:    *
 946:    * @param message the message text, also used as look-up key if the
 947:    *                logger is localizing messages with a resource
 948:    *                bundle.  While it is possible to pass
 949:    *                <code>null</code>, this is not recommended, since
 950:    *                a logging message without text is unlikely to be
 951:    *                helpful.
 952:    */
 953:   public synchronized void finer(String message)
 954:   {
 955:     if (isLoggable(Level.FINER))
 956:       log(Level.FINER, message);
 957:   }
 958: 
 959: 
 960:   /**
 961:    * Logs a message with severity level FINEST.  {@link Level#FINEST}
 962:    * is intended for highly detailed tracing, for example reaching a
 963:    * certain point inside the body of a method.
 964:    *
 965:    * @param message the message text, also used as look-up key if the
 966:    *                logger is localizing messages with a resource
 967:    *                bundle.  While it is possible to pass
 968:    *                <code>null</code>, this is not recommended, since
 969:    *                a logging message without text is unlikely to be
 970:    *                helpful.
 971:    */
 972:   public synchronized void finest(String message)
 973:   {
 974:     if (isLoggable(Level.FINEST))
 975:       log(Level.FINEST, message);
 976:   }
 977: 
 978: 
 979:   /**
 980:    * Adds a handler to the set of handlers that get notified
 981:    * when a log record is to be published.
 982:    *
 983:    * @param handler the handler to be added.
 984:    *
 985:    * @throws NullPointerException if <code>handler</code>
 986:    *     is <code>null</code>.
 987:    *
 988:    * @throws SecurityException if this logger is not anonymous, a
 989:    *     security manager exists, and the caller is not granted
 990:    *     the permission to control the logging infrastructure by
 991:    *     having LoggingPermission("control").  Untrusted code can
 992:    *     obtain an anonymous logger through the static factory method
 993:    *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
 994:    */
 995:   public synchronized void addHandler(Handler handler)
 996:     throws SecurityException
 997:   {
 998:     /* Throw a new NullPointerException if handler is null. */
 999:     handler.getClass();
1000: 
1001:     /* An application is allowed to control an anonymous logger
1002:      * without having the permission to control the logging
1003:      * infrastructure.
1004:      */
1005:     if (!anonymous)
1006:       LogManager.getLogManager().checkAccess();
1007: 
1008:     if (!handlerList.contains(handler))
1009:     {
1010:       handlerList.add(handler);
1011:       handlers = getHandlers();
1012:     }
1013:   }
1014: 
1015: 
1016:   /**
1017:    * Removes a handler from the set of handlers that get notified
1018:    * when a log record is to be published.
1019:    *
1020:    * @param handler the handler to be removed.
1021:    *
1022:    * @throws SecurityException if this logger is not anonymous, a
1023:    *     security manager exists, and the caller is not granted the
1024:    *     permission to control the logging infrastructure by having
1025:    *     LoggingPermission("control").  Untrusted code can obtain an
1026:    *     anonymous logger through the static factory method {@link
1027:    *     #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
1028:    *
1029:    * @throws NullPointerException if <code>handler</code>
1030:    *     is <code>null</code>.
1031:    */
1032:   public synchronized void removeHandler(Handler handler)
1033:     throws SecurityException
1034:   {
1035:     /* An application is allowed to control an anonymous logger
1036:      * without having the permission to control the logging
1037:      * infrastructure.
1038:      */
1039:     if (!anonymous)
1040:       LogManager.getLogManager().checkAccess();
1041: 
1042:     /* Throw a new NullPointerException if handler is null. */
1043:     handler.getClass();
1044: 
1045:     handlerList.remove(handler);
1046:     handlers = getHandlers();
1047:   }
1048: 
1049: 
1050:   /**
1051:    * Returns the handlers currently registered for this Logger.
1052:    * When a log record has been deemed as being loggable,
1053:    * it will be passed to all registered handlers for
1054:    * publication.  In addition, if the logger uses parent handlers
1055:    * (see {@link #getUseParentHandlers() getUseParentHandlers}
1056:    * and {@link #setUseParentHandlers(boolean) setUseParentHandlers},
1057:    * the log record will be passed to the parent's handlers.
1058:    */
1059:   public synchronized Handler[] getHandlers()
1060:   {
1061:     /* We cannot return our internal handlers array
1062:      * because we do not have any guarantee that the
1063:      * caller would not change the array entries.
1064:      */
1065:     return (Handler[]) handlerList.toArray(new Handler[handlerList.size()]);
1066:   }
1067: 
1068: 
1069:   /**
1070:    * Returns whether or not this Logger forwards log records to
1071:    * handlers registered for its parent loggers.
1072:    *
1073:    * @return <code>false</code> if this Logger sends log records
1074:    *         merely to Handlers registered with itself;
1075:    *         <code>true</code> if this Logger sends log records
1076:    *         not only to Handlers registered with itself, but also
1077:    *         to those Handlers registered with parent loggers.
1078:    */
1079:   public synchronized boolean getUseParentHandlers()
1080:   {
1081:     return useParentHandlers;
1082:   }
1083: 
1084: 
1085:   /**
1086:    * Sets whether or not this Logger forwards log records to
1087:    * handlers registered for its parent loggers.
1088:    *
1089:    * @param useParentHandlers <code>false</code> to let this
1090:    *         Logger send log records merely to Handlers registered
1091:    *         with itself; <code>true</code> to let this Logger
1092:    *         send log records not only to Handlers registered
1093:    *         with itself, but also to those Handlers registered with
1094:    *         parent loggers.
1095:    *
1096:    * @throws SecurityException if this logger is not anonymous, a
1097:    *     security manager exists, and the caller is not granted
1098:    *     the permission to control the logging infrastructure by
1099:    *     having LoggingPermission("control").  Untrusted code can
1100:    *     obtain an anonymous logger through the static factory method
1101:    *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
1102:    *
1103:    */
1104:   public synchronized void setUseParentHandlers(boolean useParentHandlers)
1105:   {
1106:     /* An application is allowed to control an anonymous logger
1107:      * without having the permission to control the logging
1108:      * infrastructure.
1109:      */
1110:     if (!anonymous)
1111:       LogManager.getLogManager().checkAccess();
1112: 
1113:     this.useParentHandlers = useParentHandlers;
1114:   }
1115: 
1116: 
1117:   /**
1118:    * Returns the parent of this logger.  By default, the parent is
1119:    * assigned by the LogManager by inspecting the logger's name.
1120:    *
1121:    * @return the parent of this logger (as detemined by the LogManager
1122:    *     by inspecting logger names), the root logger if no other
1123:    *     logger has a name which is a prefix of this logger's name, or
1124:    *     <code>null</code> for the root logger.
1125:    */
1126:   public synchronized Logger getParent()
1127:   {
1128:     return parent;
1129:   }
1130: 
1131: 
1132:   /**
1133:    * Sets the parent of this logger.  Usually, applications do not
1134:    * call this method directly.  Instead, the LogManager will ensure
1135:    * that the tree of loggers reflects the hierarchical logger
1136:    * namespace.  Basically, this method should not be public at all,
1137:    * but the GNU implementation follows the API specification.
1138:    *
1139:    * @throws NullPointerException if <code>parent</code> is
1140:    *     <code>null</code>.
1141:    *
1142:    * @throws SecurityException if this logger is not anonymous, a
1143:    *     security manager exists, and the caller is not granted
1144:    *     the permission to control the logging infrastructure by
1145:    *     having LoggingPermission("control").  Untrusted code can
1146:    *     obtain an anonymous logger through the static factory method
1147:    *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
1148:    */
1149:   public synchronized void setParent(Logger parent)
1150:   {
1151:     LogManager lm;
1152: 
1153:     /* Throw a new NullPointerException if parent is null. */
1154:     parent.getClass();
1155: 
1156:     lm = LogManager.getLogManager();
1157: 
1158:     if (this == lm.rootLogger)
1159:         throw new IllegalArgumentException(
1160:           "only the root logger can have a null parent");
1161: 
1162:     /* An application is allowed to control an anonymous logger
1163:      * without having the permission to control the logging
1164:      * infrastructure.
1165:      */
1166:     if (!anonymous)
1167:       LogManager.getLogManager().checkAccess();
1168: 
1169:     this.parent = parent;
1170:   }
1171:   
1172:   /**
1173:    * Gets the StackTraceElement of the first class that is not this class.
1174:    * That should be the initial caller of a logging method.
1175:    * @return caller of the initial logging method or null if unknown.
1176:    */
1177:   private StackTraceElement getCallerStackFrame()
1178:   {
1179:     Throwable t = new Throwable();
1180:     StackTraceElement[] stackTrace = t.getStackTrace();
1181:     int index = 0;
1182: 
1183:     // skip to stackentries until this class
1184:     while(index < stackTrace.length
1185:       && !stackTrace[index].getClassName().equals(getClass().getName()))
1186:       index++;
1187: 
1188:     // skip the stackentries of this class
1189:     while(index < stackTrace.length
1190:       && stackTrace[index].getClassName().equals(getClass().getName()))
1191:       index++;
1192: 
1193:     return index < stackTrace.length ? stackTrace[index] : null;
1194:   }
1195:   
1196:   /**
1197:    * Reset and close handlers attached to this logger. This function is package
1198:    * private because it must only be avaiable to the LogManager.
1199:    */
1200:   void resetLogger()
1201:   {
1202:     for (int i = 0; i < handlers.length; i++)
1203:       {
1204:         handlers[i].close();
1205:         handlerList.remove(handlers[i]);
1206:       }
1207:     handlers = getHandlers();
1208:   }
1209: }