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:     log(level, message, (Object[]) null);
 581:   }
 582: 
 583: 
 584:   public synchronized void log(Level level,
 585:                    String message,
 586:                    Object param)
 587:   {
 588:     StackTraceElement caller = getCallerStackFrame();
 589:     logp(level,
 590:      caller != null ? caller.getClassName() : "<unknown>",
 591:      caller != null ? caller.getMethodName() : "<unknown>",
 592:      message,
 593:      param);
 594:   }
 595: 
 596: 
 597:   public synchronized void log(Level level,
 598:                    String message,
 599:                    Object[] params)
 600:   {
 601:     StackTraceElement caller = getCallerStackFrame();
 602:     logp(level,
 603:      caller != null ? caller.getClassName() : "<unknown>",
 604:      caller != null ? caller.getMethodName() : "<unknown>",
 605:      message,
 606:      params);
 607:   }
 608: 
 609: 
 610:   public synchronized void log(Level level,
 611:                    String message,
 612:                    Throwable thrown)
 613:   {
 614:     StackTraceElement caller = getCallerStackFrame();    
 615:     logp(level,
 616:      caller != null ? caller.getClassName() : "<unknown>",
 617:      caller != null ? caller.getMethodName() : "<unknown>",
 618:      message,
 619:      thrown);
 620:   }
 621: 
 622: 
 623:   public synchronized void logp(Level level,
 624:                 String sourceClass,
 625:                 String sourceMethod,
 626:                 String message)
 627:   {
 628:     logp(level, sourceClass, sourceMethod, message,
 629:      (Object[]) null);
 630:   }
 631: 
 632: 
 633:   public synchronized void logp(Level level,
 634:                 String sourceClass,
 635:                 String sourceMethod,
 636:                 String message,
 637:                 Object param)
 638:   {
 639:     logp(level, sourceClass, sourceMethod, message,
 640:      new Object[] { param });
 641:   }
 642: 
 643: 
 644:   private synchronized ResourceBundle findResourceBundle()
 645:   {
 646:     if (resourceBundle != null)
 647:       return resourceBundle;
 648: 
 649:     if (parent != null)
 650:       return parent.findResourceBundle();
 651: 
 652:     return null;
 653:   }
 654: 
 655: 
 656:   private synchronized void logImpl(Level level,
 657:                     String sourceClass,
 658:                     String sourceMethod,
 659:                     String message,
 660:                     Object[] params)
 661:   {
 662:     LogRecord rec = new LogRecord(level, message);
 663: 
 664:     rec.setResourceBundle(findResourceBundle());
 665:     rec.setSourceClassName(sourceClass);
 666:     rec.setSourceMethodName(sourceMethod);
 667:     rec.setParameters(params);
 668: 
 669:     log(rec);
 670:   }
 671: 
 672: 
 673:   public synchronized void logp(Level level,
 674:                 String sourceClass,
 675:                 String sourceMethod,
 676:                 String message,
 677:                 Object[] params)
 678:   {
 679:     logImpl(level, sourceClass, sourceMethod, message, params);
 680:   }
 681: 
 682: 
 683:   public synchronized void logp(Level level,
 684:                 String sourceClass,
 685:                 String sourceMethod,
 686:                 String message,
 687:                 Throwable thrown)
 688:   {
 689:     LogRecord rec = new LogRecord(level, message);
 690: 
 691:     rec.setResourceBundle(resourceBundle);
 692:     rec.setSourceClassName(sourceClass);
 693:     rec.setSourceMethodName(sourceMethod);
 694:     rec.setThrown(thrown);
 695: 
 696:     log(rec);
 697:   }
 698: 
 699: 
 700:   public synchronized void logrb(Level level,
 701:                  String sourceClass,
 702:                  String sourceMethod,
 703:                  String bundleName,
 704:                  String message)
 705:   {
 706:     logrb(level, sourceClass, sourceMethod, bundleName,
 707:       message, (Object[]) null);
 708:   }
 709: 
 710: 
 711:   public synchronized void logrb(Level level,
 712:                  String sourceClass,
 713:                  String sourceMethod,
 714:                  String bundleName,
 715:                  String message,
 716:                  Object param)
 717:   {
 718:     logrb(level, sourceClass, sourceMethod, bundleName,
 719:       message, new Object[] { param });
 720:   }
 721: 
 722: 
 723:   public synchronized void logrb(Level level,
 724:                  String sourceClass,
 725:                  String sourceMethod,
 726:                  String bundleName,
 727:                  String message,
 728:                  Object[] params)
 729:   {
 730:     LogRecord rec = new LogRecord(level, message);
 731: 
 732:     rec.setResourceBundleName(bundleName);
 733:     rec.setSourceClassName(sourceClass);
 734:     rec.setSourceMethodName(sourceMethod);
 735:     rec.setParameters(params);
 736: 
 737:     log(rec);
 738:   }
 739: 
 740: 
 741:   public synchronized void logrb(Level level,
 742:                  String sourceClass,
 743:                  String sourceMethod,
 744:                  String bundleName,
 745:                  String message,
 746:                  Throwable thrown)
 747:   {
 748:     LogRecord rec = new LogRecord(level, message);
 749: 
 750:     rec.setResourceBundleName(bundleName);
 751:     rec.setSourceClassName(sourceClass);
 752:     rec.setSourceMethodName(sourceMethod);
 753:     rec.setThrown(thrown);
 754: 
 755:     log(rec);
 756:   }
 757: 
 758: 
 759:   public synchronized void entering(String sourceClass,
 760:                     String sourceMethod)
 761:   {
 762:     if (isLoggable(Level.FINER))
 763:       logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
 764:   }
 765: 
 766: 
 767:   public synchronized void entering(String sourceClass,
 768:                     String sourceMethod,
 769:                     Object param)
 770:   {
 771:     if (isLoggable(Level.FINER))
 772:       logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param);
 773:   }
 774: 
 775: 
 776:   public synchronized void entering(String sourceClass,
 777:                     String sourceMethod,
 778:                     Object[] params)
 779:   {
 780:     if (isLoggable(Level.FINER))
 781:     {
 782:       StringBuffer buf = new StringBuffer(80);
 783:       buf.append("ENTRY");
 784:       for (int i = 0; i < params.length; i++)
 785:       {
 786:     buf.append(" {");
 787:     buf.append(i);
 788:     buf.append('}');
 789:       }
 790:       
 791:       logp(Level.FINER, sourceClass, sourceMethod, buf.toString(), params);
 792:     }
 793:   }
 794: 
 795: 
 796:   public synchronized void exiting(String sourceClass,
 797:                    String sourceMethod)
 798:   {
 799:     if (isLoggable(Level.FINER))
 800:       logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
 801:   }
 802: 
 803:    
 804:   public synchronized void exiting(String sourceClass,
 805:                    String sourceMethod,
 806:                    Object result)
 807:   {
 808:     if (isLoggable(Level.FINER))
 809:       logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
 810:   }
 811: 
 812:  
 813:   public synchronized void throwing(String sourceClass,
 814:                     String sourceMethod,
 815:                     Throwable thrown)
 816:   {
 817:     if (isLoggable(Level.FINER))
 818:       logp(Level.FINER, sourceClass, sourceMethod, "THROW", thrown);
 819:   }
 820: 
 821: 
 822:   /**
 823:    * Logs a message with severity level SEVERE, indicating a serious
 824:    * failure that prevents normal program execution.  Messages at this
 825:    * level should be understandable to an inexperienced, non-technical
 826:    * end user.  Ideally, they explain in simple words what actions the
 827:    * user can take in order to resolve the problem.
 828:    *
 829:    * @see Level#SEVERE
 830:    *
 831:    * @param message the message text, also used as look-up key if the
 832:    *                logger is localizing messages with a resource
 833:    *                bundle.  While it is possible to pass
 834:    *                <code>null</code>, this is not recommended, since
 835:    *                a logging message without text is unlikely to be
 836:    *                helpful.
 837:    */
 838:   public synchronized void severe(String message)
 839:   {
 840:     if (isLoggable(Level.SEVERE))
 841:       log(Level.SEVERE, message);
 842:   }
 843: 
 844: 
 845:   /**
 846:    * Logs a message with severity level WARNING, indicating a
 847:    * potential problem that does not prevent normal program execution.
 848:    * Messages at this level should be understandable to an
 849:    * inexperienced, non-technical end user.  Ideally, they explain in
 850:    * simple words what actions the user can take in order to resolve
 851:    * the problem.
 852:    *
 853:    * @see Level#WARNING
 854:    *
 855:    * @param message the message text, also used as look-up key if the
 856:    *                logger is localizing messages with a resource
 857:    *                bundle.  While it is possible to pass
 858:    *                <code>null</code>, this is not recommended, since
 859:    *                a logging message without text is unlikely to be
 860:    *                helpful.
 861:    */
 862:   public synchronized void warning(String message)
 863:   {
 864:     if (isLoggable(Level.WARNING))
 865:       log(Level.WARNING, message);
 866:   }
 867: 
 868: 
 869:   /**
 870:    * Logs a message with severity level INFO.  {@link Level#INFO} is
 871:    * intended for purely informational messages that do not indicate
 872:    * error or warning situations. In the default logging
 873:    * configuration, INFO messages will be written to the system
 874:    * console.  For this reason, the INFO level should be used only for
 875:    * messages that are important to end users and system
 876:    * administrators.  Messages at this level should be understandable
 877:    * to an inexperienced, non-technical user.
 878:    *
 879:    * @param message the message text, also used as look-up key if the
 880:    *                logger is localizing messages with a resource
 881:    *                bundle.  While it is possible to pass
 882:    *                <code>null</code>, this is not recommended, since
 883:    *                a logging message without text is unlikely to be
 884:    *                helpful.
 885:    */
 886:   public synchronized void info(String message)
 887:   {
 888:     if (isLoggable(Level.INFO))
 889:       log(Level.INFO, message);
 890:   }
 891: 
 892: 
 893:   /**
 894:    * Logs a message with severity level CONFIG.  {@link Level#CONFIG} is
 895:    * intended for static configuration messages, for example about the
 896:    * windowing environment, the operating system version, etc.
 897:    *
 898:    * @param message the message text, also used as look-up key if the
 899:    *     logger is localizing messages with a resource bundle.  While
 900:    *     it is possible to pass <code>null</code>, this is not
 901:    *     recommended, since a logging message without text is unlikely
 902:    *     to be helpful.
 903:    */
 904:   public synchronized void config(String message)
 905:   {
 906:     if (isLoggable(Level.CONFIG))
 907:       log(Level.CONFIG, message);
 908:   }
 909: 
 910: 
 911:   /**
 912:    * Logs a message with severity level FINE.  {@link Level#FINE} is
 913:    * intended for messages that are relevant for developers using
 914:    * the component generating log messages. Examples include minor,
 915:    * recoverable failures, or possible inefficiencies.
 916:    *
 917:    * @param message the message text, also used as look-up key if the
 918:    *                logger is localizing messages with a resource
 919:    *                bundle.  While it is possible to pass
 920:    *                <code>null</code>, this is not recommended, since
 921:    *                a logging message without text is unlikely to be
 922:    *                helpful.
 923:    */
 924:   public synchronized void fine(String message)
 925:   {
 926:     if (isLoggable(Level.FINE))
 927:       log(Level.FINE, message);
 928:   }
 929: 
 930: 
 931:   /**
 932:    * Logs a message with severity level FINER.  {@link Level#FINER} is
 933:    * intended for rather detailed tracing, for example entering a
 934:    * method, returning from a method, or throwing an exception.
 935:    *
 936:    * @param message the message text, also used as look-up key if the
 937:    *                logger is localizing messages with a resource
 938:    *                bundle.  While it is possible to pass
 939:    *                <code>null</code>, this is not recommended, since
 940:    *                a logging message without text is unlikely to be
 941:    *                helpful.
 942:    */
 943:   public synchronized void finer(String message)
 944:   {
 945:     if (isLoggable(Level.FINER))
 946:       log(Level.FINER, message);
 947:   }
 948: 
 949: 
 950:   /**
 951:    * Logs a message with severity level FINEST.  {@link Level#FINEST}
 952:    * is intended for highly detailed tracing, for example reaching a
 953:    * certain point inside the body of a method.
 954:    *
 955:    * @param message the message text, also used as look-up key if the
 956:    *                logger is localizing messages with a resource
 957:    *                bundle.  While it is possible to pass
 958:    *                <code>null</code>, this is not recommended, since
 959:    *                a logging message without text is unlikely to be
 960:    *                helpful.
 961:    */
 962:   public synchronized void finest(String message)
 963:   {
 964:     if (isLoggable(Level.FINEST))
 965:       log(Level.FINEST, message);
 966:   }
 967: 
 968: 
 969:   /**
 970:    * Adds a handler to the set of handlers that get notified
 971:    * when a log record is to be published.
 972:    *
 973:    * @param handler the handler to be added.
 974:    *
 975:    * @throws NullPointerException if <code>handler</code>
 976:    *     is <code>null</code>.
 977:    *
 978:    * @throws SecurityException if this logger is not anonymous, a
 979:    *     security manager exists, and the caller is not granted
 980:    *     the permission to control the logging infrastructure by
 981:    *     having LoggingPermission("control").  Untrusted code can
 982:    *     obtain an anonymous logger through the static factory method
 983:    *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
 984:    */
 985:   public synchronized void addHandler(Handler handler)
 986:     throws SecurityException
 987:   {
 988:     /* Throw a new NullPointerException if handler is null. */
 989:     handler.getClass();
 990: 
 991:     /* An application is allowed to control an anonymous logger
 992:      * without having the permission to control the logging
 993:      * infrastructure.
 994:      */
 995:     if (!anonymous)
 996:       LogManager.getLogManager().checkAccess();
 997: 
 998:     if (!handlerList.contains(handler))
 999:     {
1000:       handlerList.add(handler);
1001:       handlers = getHandlers();
1002:     }
1003:   }
1004: 
1005: 
1006:   /**
1007:    * Removes a handler from the set of handlers that get notified
1008:    * when a log record is to be published.
1009:    *
1010:    * @param handler the handler to be removed.
1011:    *
1012:    * @throws SecurityException if this logger is not anonymous, a
1013:    *     security manager exists, and the caller is not granted the
1014:    *     permission to control the logging infrastructure by having
1015:    *     LoggingPermission("control").  Untrusted code can obtain an
1016:    *     anonymous logger through the static factory method {@link
1017:    *     #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
1018:    *
1019:    * @throws NullPointerException if <code>handler</code>
1020:    *     is <code>null</code>.
1021:    */
1022:   public synchronized void removeHandler(Handler handler)
1023:     throws SecurityException
1024:   {
1025:     /* An application is allowed to control an anonymous logger
1026:      * without having the permission to control the logging
1027:      * infrastructure.
1028:      */
1029:     if (!anonymous)
1030:       LogManager.getLogManager().checkAccess();
1031: 
1032:     /* Throw a new NullPointerException if handler is null. */
1033:     handler.getClass();
1034: 
1035:     handlerList.remove(handler);
1036:     handlers = getHandlers();
1037:   }
1038: 
1039: 
1040:   /**
1041:    * Returns the handlers currently registered for this Logger.
1042:    * When a log record has been deemed as being loggable,
1043:    * it will be passed to all registered handlers for
1044:    * publication.  In addition, if the logger uses parent handlers
1045:    * (see {@link #getUseParentHandlers() getUseParentHandlers}
1046:    * and {@link #setUseParentHandlers(boolean) setUseParentHandlers},
1047:    * the log record will be passed to the parent's handlers.
1048:    */
1049:   public synchronized Handler[] getHandlers()
1050:   {
1051:     /* We cannot return our internal handlers array
1052:      * because we do not have any guarantee that the
1053:      * caller would not change the array entries.
1054:      */
1055:     return (Handler[]) handlerList.toArray(new Handler[handlerList.size()]);
1056:   }
1057: 
1058: 
1059:   /**
1060:    * Returns whether or not this Logger forwards log records to
1061:    * handlers registered for its parent loggers.
1062:    *
1063:    * @return <code>false</code> if this Logger sends log records
1064:    *         merely to Handlers registered with itself;
1065:    *         <code>true</code> if this Logger sends log records
1066:    *         not only to Handlers registered with itself, but also
1067:    *         to those Handlers registered with parent loggers.
1068:    */
1069:   public synchronized boolean getUseParentHandlers()
1070:   {
1071:     return useParentHandlers;
1072:   }
1073: 
1074: 
1075:   /**
1076:    * Sets whether or not this Logger forwards log records to
1077:    * handlers registered for its parent loggers.
1078:    *
1079:    * @param useParentHandlers <code>false</code> to let this
1080:    *         Logger send log records merely to Handlers registered
1081:    *         with itself; <code>true</code> to let this Logger
1082:    *         send log records not only to Handlers registered
1083:    *         with itself, but also to those Handlers registered with
1084:    *         parent loggers.
1085:    *
1086:    * @throws SecurityException if this logger is not anonymous, a
1087:    *     security manager exists, and the caller is not granted
1088:    *     the permission to control the logging infrastructure by
1089:    *     having LoggingPermission("control").  Untrusted code can
1090:    *     obtain an anonymous logger through the static factory method
1091:    *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
1092:    *
1093:    */
1094:   public synchronized void setUseParentHandlers(boolean useParentHandlers)
1095:   {
1096:     /* An application is allowed to control an anonymous logger
1097:      * without having the permission to control the logging
1098:      * infrastructure.
1099:      */
1100:     if (!anonymous)
1101:       LogManager.getLogManager().checkAccess();
1102: 
1103:     this.useParentHandlers = useParentHandlers;
1104:   }
1105: 
1106: 
1107:   /**
1108:    * Returns the parent of this logger.  By default, the parent is
1109:    * assigned by the LogManager by inspecting the logger's name.
1110:    *
1111:    * @return the parent of this logger (as detemined by the LogManager
1112:    *     by inspecting logger names), the root logger if no other
1113:    *     logger has a name which is a prefix of this logger's name, or
1114:    *     <code>null</code> for the root logger.
1115:    */
1116:   public synchronized Logger getParent()
1117:   {
1118:     return parent;
1119:   }
1120: 
1121: 
1122:   /**
1123:    * Sets the parent of this logger.  Usually, applications do not
1124:    * call this method directly.  Instead, the LogManager will ensure
1125:    * that the tree of loggers reflects the hierarchical logger
1126:    * namespace.  Basically, this method should not be public at all,
1127:    * but the GNU implementation follows the API specification.
1128:    *
1129:    * @throws NullPointerException if <code>parent</code> is
1130:    *     <code>null</code>.
1131:    *
1132:    * @throws SecurityException if this logger is not anonymous, a
1133:    *     security manager exists, and the caller is not granted
1134:    *     the permission to control the logging infrastructure by
1135:    *     having LoggingPermission("control").  Untrusted code can
1136:    *     obtain an anonymous logger through the static factory method
1137:    *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
1138:    */
1139:   public synchronized void setParent(Logger parent)
1140:   {
1141:     LogManager lm;
1142: 
1143:     /* Throw a new NullPointerException if parent is null. */
1144:     parent.getClass();
1145: 
1146:     lm = LogManager.getLogManager();
1147: 
1148:     if (this == lm.rootLogger)
1149:         throw new IllegalArgumentException(
1150:           "only the root logger can have a null parent");
1151: 
1152:     /* An application is allowed to control an anonymous logger
1153:      * without having the permission to control the logging
1154:      * infrastructure.
1155:      */
1156:     if (!anonymous)
1157:       LogManager.getLogManager().checkAccess();
1158: 
1159:     this.parent = parent;
1160:   }
1161:   
1162:   /**
1163:    * Gets the StackTraceElement of the first class that is not this class.
1164:    * That should be the initial caller of a logging method.
1165:    * @return caller of the initial logging method or null if unknown.
1166:    */
1167:   private StackTraceElement getCallerStackFrame()
1168:   {
1169:     Throwable t = new Throwable();
1170:     StackTraceElement[] stackTrace = t.getStackTrace();
1171:     int index = 0;
1172: 
1173:     // skip to stackentries until this class
1174:     while(index < stackTrace.length
1175:       && !stackTrace[index].getClassName().equals(getClass().getName()))
1176:       index++;
1177: 
1178:     // skip the stackentries of this class
1179:     while(index < stackTrace.length
1180:       && stackTrace[index].getClassName().equals(getClass().getName()))
1181:       index++;
1182: 
1183:     return index < stackTrace.length ? stackTrace[index] : null;
1184:   }
1185:   
1186:   /**
1187:    * Reset and close handlers attached to this logger. This function is package
1188:    * private because it must only be avaiable to the LogManager.
1189:    */
1190:   void resetLogger()
1191:   {
1192:     for (int i = 0; i < handlers.length; i++)
1193:       {
1194:         handlers[i].close();
1195:         handlerList.remove(handlers[i]);
1196:       }
1197:     handlers = getHandlers();
1198:   }
1199: }