Source for java.util.logging.LogRecord

   1: /* LogRecord.java --
   2:    A class for the state associated with individual logging events
   3:    Copyright (C) 2002, 2003, 2004  Free Software Foundation, Inc.
   4: 
   5: This file is part of GNU Classpath.
   6: 
   7: GNU Classpath is free software; you can redistribute it and/or modify
   8: it under the terms of the GNU General Public License as published by
   9: the Free Software Foundation; either version 2, or (at your option)
  10: any later version.
  11: 
  12: GNU Classpath is distributed in the hope that it will be useful, but
  13: WITHOUT ANY WARRANTY; without even the implied warranty of
  14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15: General Public License for more details.
  16: 
  17: You should have received a copy of the GNU General Public License
  18: along with GNU Classpath; see the file COPYING.  If not, write to the
  19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  20: 02110-1301 USA.
  21: 
  22: Linking this library statically or dynamically with other modules is
  23: making a combined work based on this library.  Thus, the terms and
  24: conditions of the GNU General Public License cover the whole
  25: combination.
  26: 
  27: As a special exception, the copyright holders of this library give you
  28: permission to link this library with independent modules to produce an
  29: executable, regardless of the license terms of these independent
  30: modules, and to copy and distribute the resulting executable under
  31: terms of your choice, provided that you also meet, for each linked
  32: independent module, the terms and conditions of the license of that
  33: module.  An independent module is a module which is not derived from
  34: or based on this library.  If you modify this library, you may extend
  35: this exception to your version of the library, but you are not
  36: obligated to do so.  If you do not wish to do so, delete this
  37: exception statement from your version. */
  38: 
  39: 
  40: package java.util.logging;
  41: 
  42: import java.util.ResourceBundle;
  43: 
  44: 
  45: /**
  46:  * A <code>LogRecord</code> contains the state for an individual
  47:  * event to be logged.
  48:  *
  49:  * <p>As soon as a LogRecord instance has been handed over to the
  50:  * logging framework, applications should not manipulate it anymore.
  51:  *
  52:  * @author Sascha Brawer (brawer@acm.org)
  53:  */
  54: public class LogRecord
  55:   implements java.io.Serializable
  56: {
  57:   /**
  58:    * The severity level of this <code>LogRecord</code>.
  59:    */
  60:   private Level      level;
  61: 
  62: 
  63:   /**
  64:    * The sequence number of this <code>LogRecord</code>.
  65:    */
  66:   private long       sequenceNumber;
  67: 
  68: 
  69:   /**
  70:    * The name of the class that issued the logging request, or
  71:    * <code>null</code> if this information could not be obtained.
  72:    */
  73:   private String     sourceClassName;
  74: 
  75: 
  76:   /**
  77:    * The name of the method that issued the logging request, or
  78:    * <code>null</code> if this information could not be obtained.
  79:    */
  80:   private String sourceMethodName;
  81: 
  82: 
  83:   /**
  84:    * The message for this <code>LogRecord</code> before
  85:    * any localization or formatting.
  86:    */
  87:   private String message;
  88: 
  89: 
  90:   /**
  91:    * An identifier for the thread in which this <code>LogRecord</code>
  92:    * was created.  The identifier is not necessarily related to any
  93:    * thread identifiers used by the operating system.
  94:    */
  95:   private int threadID;
  96: 
  97: 
  98:   /**
  99:    * The time when this <code>LogRecord</code> was created,
 100:    * in milliseconds since the beginning of January 1, 1970.
 101:    */
 102:   private long millis;
 103: 
 104: 
 105:   /**
 106:    * The Throwable associated with this <code>LogRecord</code>, or
 107:    * <code>null</code> if the logged event is not related to an
 108:    * exception or error.
 109:    */
 110:   private Throwable thrown;
 111: 
 112: 
 113:   /**
 114:    * The name of the logger where this <code>LogRecord</code> has
 115:    * originated, or <code>null</code> if this <code>LogRecord</code>
 116:    * does not originate from a <code>Logger</code>.
 117:    */
 118:   private String  loggerName;
 119: 
 120: 
 121:   /**
 122:    * The name of the resource bundle used for localizing log messages,
 123:    * or <code>null</code> if no bundle has been specified.
 124:    */
 125:   private String resourceBundleName;
 126: 
 127:   private transient Object[] parameters;
 128: 
 129:   private transient ResourceBundle bundle;
 130: 
 131: 
 132:   /**
 133:    * Constructs a <code>LogRecord</code> given a severity level and
 134:    * an unlocalized message text.  In addition, the sequence number,
 135:    * creation time (as returned by <code>getMillis()</code>) and
 136:    * thread ID are assigned. All other properties are set to
 137:    * <code>null</code>.
 138:    *
 139:    * @param level the severity level, for example <code>Level.WARNING</code>.
 140:    *
 141:    * @param message the message text (which will be used as key
 142:    *                for looking up the localized message text
 143:    *                if a resource bundle has been associated).
 144:    */
 145:   public LogRecord(Level level, String message)
 146:   {
 147:     this.level = level;
 148:     this.message = message;
 149:     this.millis = System.currentTimeMillis();
 150: 
 151:     /* A subclass of java.lang.Thread could override hashCode(),
 152:      * in which case the result would not be guaranteed anymore
 153:      * to be unique among all threads.  While System.identityHashCode
 154:      * is not necessarily unique either, it at least cannot be
 155:      * overridden by user code.  However, is might be a good idea
 156:      * to use something better for generating thread IDs.
 157:      */
 158:     this.threadID = System.identityHashCode(Thread.currentThread());
 159: 
 160:     sequenceNumber = allocateSeqNum();
 161:   }
 162: 
 163: 
 164:   /**
 165:    * Determined with the serialver tool of the Sun J2SE 1.4.
 166:    */
 167:   static final long serialVersionUID = 5372048053134512534L;
 168: 
 169:   private void readObject(java.io.ObjectInputStream in)
 170:     throws java.io.IOException, java.lang.ClassNotFoundException
 171:   {
 172:     in.defaultReadObject();
 173: 
 174:     /* We assume that future versions will be downwards compatible,
 175:      * so we can ignore the versions.
 176:      */
 177:     byte majorVersion = in.readByte();
 178:     byte minorVersion = in.readByte();
 179: 
 180:     int numParams = in.readInt();
 181:     if (numParams >= 0)
 182:     {
 183:       parameters = new Object[numParams];
 184:       for (int i = 0; i < numParams; i++)
 185:         parameters[i] = in.readObject();
 186:     }
 187:   }
 188: 
 189: 
 190:   /**
 191:    * @serialData The default fields, followed by a major byte version
 192:    * number, followed by a minor byte version number, followed by
 193:    * information about the log record parameters.  If
 194:    * <code>parameters</code> is <code>null</code>, the integer -1 is
 195:    * written, otherwise the length of the <code>parameters</code>
 196:    * array (which can be zero), followed by the result of calling
 197:    * {@link Object#toString() toString()} on the parameter (or
 198:    * <code>null</code> if the parameter is <code>null</code>).
 199:    *
 200:    * <p><strong>Specification Note:</strong> The Javadoc for the
 201:    * Sun reference implementation does not specify the version
 202:    * number. FIXME: Reverse-engineer the JDK and file a bug
 203:    * report with Sun, asking for amendment of the specification.
 204:    */
 205:   private void writeObject(java.io.ObjectOutputStream out)
 206:     throws java.io.IOException
 207:   {
 208:     out.defaultWriteObject();
 209: 
 210:     /* Major, minor version number: The Javadoc for J2SE1.4 does not
 211:      * specify the values.
 212:      */
 213:     out.writeByte(0);
 214:     out.writeByte(0);
 215: 
 216:     if (parameters == null)
 217:       out.writeInt(-1);
 218:     else
 219:     {
 220:       out.writeInt(parameters.length);
 221:       for (int i = 0; i < parameters.length; i++)
 222:       {
 223:         if (parameters[i] == null)
 224:           out.writeObject(null);
 225:         else
 226:           out.writeObject(parameters[i].toString());
 227:       }
 228:     }
 229:   }
 230: 
 231: 
 232:   /**
 233:    * Returns the name of the logger where this <code>LogRecord</code>
 234:    * has originated.
 235:    *
 236:    * @return the name of the source {@link Logger}, or
 237:    *         <code>null</code> if this <code>LogRecord</code>
 238:    *         does not originate from a <code>Logger</code>.
 239:    */
 240:   public String getLoggerName()
 241:   {
 242:     return loggerName;
 243:   }
 244: 
 245: 
 246:   /**
 247:    * Sets the name of the logger where this <code>LogRecord</code>
 248:    * has originated.
 249:    *
 250:    * <p>As soon as a <code>LogRecord</code> has been handed over
 251:    * to the logging framework, applications should not modify it
 252:    * anymore.  Therefore, this method should only be called on
 253:    * freshly constructed LogRecords.
 254:    *
 255:    * @param name the name of the source logger, or <code>null</code> to
 256:    *             indicate that this <code>LogRecord</code> does not
 257:    *             originate from a <code>Logger</code>.
 258:    */
 259:   public void setLoggerName(String name)
 260:   {
 261:     loggerName = name;
 262:   }
 263: 
 264: 
 265:   /**
 266:    * Returns the resource bundle that is used when the message
 267:    * of this <code>LogRecord</code> needs to be localized.
 268:    *
 269:    * @return the resource bundle used for localization,
 270:    *         or <code>null</code> if this message does not need
 271:    *         to be localized.
 272:    */
 273:   public ResourceBundle getResourceBundle()
 274:   {
 275:     return bundle;
 276:   }
 277: 
 278: 
 279:   /**
 280:    * Sets the resource bundle that is used when the message
 281:    * of this <code>LogRecord</code> needs to be localized.
 282:    *
 283:    * <p>As soon as a <code>LogRecord</code> has been handed over
 284:    * to the logging framework, applications should not modify it
 285:    * anymore.  Therefore, this method should only be called on
 286:    * freshly constructed LogRecords.
 287:    *
 288:    * @param bundle  the resource bundle to be used, or
 289:    *                <code>null</code> to indicate that this
 290:    *                message does not need to be localized.
 291:    */
 292:   public void setResourceBundle(ResourceBundle bundle)
 293:   {
 294:     this.bundle = bundle;
 295: 
 296:     /* FIXME: Is there a way to infer the name
 297:      * of a resource bundle from a ResourceBundle object?
 298:      */
 299:     this.resourceBundleName = null;
 300:   }
 301: 
 302: 
 303:   /**
 304:    * Returns the name of the resource bundle that is used when the
 305:    * message of this <code>LogRecord</code> needs to be localized.
 306:    *
 307:    * @return the name of the resource bundle used for localization,
 308:    *         or <code>null</code> if this message does not need
 309:    *         to be localized.
 310:    */
 311:   public String getResourceBundleName()
 312:   {
 313:     return resourceBundleName;
 314:   }
 315: 
 316: 
 317:   /**
 318:    * Sets the name of the resource bundle that is used when the
 319:    * message of this <code>LogRecord</code> needs to be localized.
 320:    *
 321:    * <p>As soon as a <code>LogRecord</code> has been handed over
 322:    * to the logging framework, applications should not modify it
 323:    * anymore.  Therefore, this method should only be called on
 324:    * freshly constructed LogRecords.
 325:    *
 326:    * @param name the name of the resource bundle to be used, or
 327:    *             <code>null</code> to indicate that this message
 328:    *             does not need to be localized.
 329:    */
 330:   public void setResourceBundleName(String name)
 331:   {
 332:     resourceBundleName = name;
 333:     bundle = null;
 334: 
 335:     try
 336:     {
 337:       if (resourceBundleName != null)
 338:         bundle = ResourceBundle.getBundle(resourceBundleName);
 339:     }
 340:     catch (java.util.MissingResourceException _)
 341:     {
 342:     }
 343:   }
 344: 
 345: 
 346:   /**
 347:    * Returns the level of the LogRecord.
 348:    *
 349:    * <p>Applications should be aware of the possibility that the
 350:    *  result is not necessarily one of the standard logging levels,
 351:    *  since the logging framework allows to create custom subclasses
 352:    *  of <code>java.util.logging.Level</code>.  Therefore, filters
 353:    *  should perform checks like <code>theRecord.getLevel().intValue()
 354:    *  == Level.INFO.intValue()</code> instead of <code>theRecord.getLevel()
 355:    *  == Level.INFO</code>.
 356:    */
 357:   public Level getLevel()
 358:   {
 359:     return level;
 360:   }
 361: 
 362: 
 363:   /**
 364:    * Sets the severity level of this <code>LogRecord</code> to a new
 365:    * value.
 366:    *
 367:    * <p>As soon as a <code>LogRecord</code> has been handed over
 368:    * to the logging framework, applications should not modify it
 369:    * anymore.  Therefore, this method should only be called on
 370:    * freshly constructed LogRecords.
 371:    *
 372:    * @param level the new severity level, for example
 373:    *              <code>Level.WARNING</code>.
 374:    */
 375:   public void setLevel(Level level)
 376:   {
 377:     this.level = level;
 378:   }
 379: 
 380: 
 381:   /**
 382:    * The last used sequence number for any LogRecord.
 383:    */
 384:   private static long lastSeqNum;
 385: 
 386: 
 387:   /**
 388:    * Allocates a sequence number for a new LogRecord.  This class
 389:    * method is only called by the LogRecord constructor.
 390:    */
 391:   private static synchronized long allocateSeqNum()
 392:   {
 393:     lastSeqNum += 1;
 394:     return lastSeqNum;
 395:   }
 396: 
 397: 
 398:   /**
 399:    * Returns the sequence number of this <code>LogRecord</code>.
 400:    */
 401:   public long getSequenceNumber()
 402:   {
 403:     return sequenceNumber;
 404:   }
 405: 
 406: 
 407:   /**
 408:    * Sets the sequence number of this <code>LogRecord</code> to a new
 409:    * value.
 410:    *
 411:    * <p>As soon as a <code>LogRecord</code> has been handed over
 412:    * to the logging framework, applications should not modify it
 413:    * anymore.  Therefore, this method should only be called on
 414:    * freshly constructed LogRecords.
 415:    *
 416:    * @param seqNum the new sequence number.
 417:    */
 418:   public void setSequenceNumber(long seqNum)
 419:   {
 420:     this.sequenceNumber = seqNum;
 421:   }
 422: 
 423: 
 424:   /**
 425:    * Returns the name of the class where the event being logged
 426:    * has had its origin.  This information can be passed as
 427:    * parameter to some logging calls, and in certain cases, the
 428:    * logging framework tries to determine an approximation
 429:    * (which may or may not be accurate).
 430:    *
 431:    * @return the name of the class that issued the logging request,
 432:    *         or <code>null</code> if this information could not
 433:    *         be obtained.
 434:    */
 435:   public String getSourceClassName()
 436:   {
 437:     if (sourceClassName != null)
 438:       return sourceClassName;
 439: 
 440:     /*  FIXME: Should infer this information from the call stack. */
 441:     return null;
 442:   }
 443: 
 444: 
 445:   /**
 446:    * Sets the name of the class where the event being logged
 447:    * has had its origin.
 448:    *
 449:    * <p>As soon as a <code>LogRecord</code> has been handed over
 450:    * to the logging framework, applications should not modify it
 451:    * anymore.  Therefore, this method should only be called on
 452:    * freshly constructed LogRecords.
 453:    *
 454:    * @param sourceClassName the name of the class that issued the
 455:    *          logging request, or <code>null</code> to indicate that
 456:    *          this information could not be obtained.
 457:    */
 458:   public void setSourceClassName(String sourceClassName)
 459:   {
 460:     this.sourceClassName = sourceClassName;
 461:   }
 462: 
 463: 
 464:   /**
 465:    * Returns the name of the method where the event being logged
 466:    * has had its origin.  This information can be passed as
 467:    * parameter to some logging calls, and in certain cases, the
 468:    * logging framework tries to determine an approximation
 469:    * (which may or may not be accurate).
 470:    *
 471:    * @return the name of the method that issued the logging request,
 472:    *         or <code>null</code> if this information could not
 473:    *         be obtained.
 474:    */
 475:   public String getSourceMethodName()
 476:   {
 477:     if (sourceMethodName != null)
 478:       return sourceMethodName;
 479: 
 480:     /* FIXME: Should infer this information from the call stack. */
 481:     return null;
 482:   }
 483: 
 484: 
 485:   /**
 486:    * Sets the name of the method where the event being logged
 487:    * has had its origin.
 488:    *
 489:    * <p>As soon as a <code>LogRecord</code> has been handed over
 490:    * to the logging framework, applications should not modify it
 491:    * anymore.  Therefore, this method should only be called on
 492:    * freshly constructed LogRecords.
 493:    *
 494:    * @param sourceMethodName the name of the method that issued the
 495:    *          logging request, or <code>null</code> to indicate that
 496:    *          this information could not be obtained.
 497:    */
 498:   public void setSourceMethodName(String sourceMethodName)
 499:   {
 500:     this.sourceMethodName = sourceMethodName;
 501:   }
 502: 
 503: 
 504:   /**
 505:    * Returns the message for this <code>LogRecord</code> before
 506:    * any localization or parameter substitution.
 507:    *
 508:    * <p>A {@link Logger} will try to localize the message
 509:    * if a resource bundle has been associated with this
 510:    * <code>LogRecord</code>.  In this case, the logger will call
 511:    * <code>getMessage()</code> and use the result as the key
 512:    * for looking up the localized message in the bundle.
 513:    * If no bundle has been associated, or if the result of
 514:    * <code>getMessage()</code> is not a valid key in the
 515:    * bundle, the logger will use the raw message text as
 516:    * returned by this method.
 517:    *
 518:    * @return the message text, or <code>null</code> if there
 519:    *         is no message text.
 520:    */
 521:   public String getMessage()
 522:   {
 523:     return message;
 524:   }
 525: 
 526: 
 527:   /**
 528:    * Sets the message for this <code>LogRecord</code>.
 529:    *
 530:    * <p>A <code>Logger</code> will try to localize the message
 531:    * if a resource bundle has been associated with this
 532:    * <code>LogRecord</code>.  In this case, the logger will call
 533:    * <code>getMessage()</code> and use the result as the key
 534:    * for looking up the localized message in the bundle.
 535:    * If no bundle has been associated, or if the result of
 536:    * <code>getMessage()</code> is not a valid key in the
 537:    * bundle, the logger will use the raw message text as
 538:    * returned by this method.
 539:    *
 540:    * <p>It is possible to set the message to either an empty String or
 541:    * <code>null</code>, although this does not make the the message
 542:    * very helpful to human users.
 543:    *
 544:    * @param message the message text (which will be used as key
 545:    *                for looking up the localized message text
 546:    *                if a resource bundle has been associated).
 547:    */
 548:   public void setMessage(String message)
 549:   {
 550:     this.message = message;
 551:   }
 552: 
 553: 
 554:   /**
 555:    * Returns the parameters to the log message.
 556:    *
 557:    * @return the parameters to the message, or <code>null</code> if
 558:    *         the message has no parameters.
 559:    */
 560:   public Object[] getParameters()
 561:   {
 562:     return parameters;
 563:   }
 564: 
 565: 
 566:   /**
 567:    * Sets the parameters to the log message.
 568:    *
 569:    * <p>As soon as a <code>LogRecord</code> has been handed over
 570:    * to the logging framework, applications should not modify it
 571:    * anymore.  Therefore, this method should only be called on
 572:    * freshly constructed LogRecords.
 573:    *
 574:    * @param parameters the parameters to the message, or <code>null</code>
 575:    *                   to indicate that the message has no parameters.
 576:    */
 577:   public void setParameters(Object[] parameters)
 578:   {
 579:     this.parameters = parameters;
 580:   }
 581: 
 582: 
 583:   /**
 584:    * Returns an identifier for the thread in which this
 585:    * <code>LogRecord</code> was created.  The identifier is not
 586:    * necessarily related to any thread identifiers used by the
 587:    * operating system.
 588:    *
 589:    * @return an identifier for the source thread.
 590:    */
 591:   public int getThreadID()
 592:   {
 593:     return threadID;
 594:   }
 595: 
 596: 
 597:   /**
 598:    * Sets the identifier indicating in which thread this
 599:    * <code>LogRecord</code> was created.  The identifier is not
 600:    * necessarily related to any thread identifiers used by the
 601:    * operating system.
 602:    *
 603:    * <p>As soon as a <code>LogRecord</code> has been handed over
 604:    * to the logging framework, applications should not modify it
 605:    * anymore.  Therefore, this method should only be called on
 606:    * freshly constructed LogRecords.
 607:    *
 608:    * @param threadID the identifier for the source thread.
 609:    */
 610:   public void setThreadID(int threadID)
 611:   {
 612:     this.threadID = threadID;
 613:   }
 614: 
 615: 
 616:   /**
 617:    * Returns the time when this <code>LogRecord</code> was created.
 618:    *
 619:    * @return the time of creation in milliseconds since the beginning
 620:    *         of January 1, 1970.
 621:    */
 622:   public long getMillis()
 623:   {
 624:     return millis;
 625:   }
 626: 
 627: 
 628:   /**
 629:    * Sets the time when this <code>LogRecord</code> was created.
 630:    *
 631:    * <p>As soon as a <code>LogRecord</code> has been handed over
 632:    * to the logging framework, applications should not modify it
 633:    * anymore.  Therefore, this method should only be called on
 634:    * freshly constructed LogRecords.
 635:    *
 636:    * @param millis the time of creation in milliseconds since the
 637:    *               beginning of January 1, 1970.
 638:    */
 639:   public void setMillis(long millis)
 640:   {
 641:     this.millis = millis;
 642:   }
 643: 
 644: 
 645:   /**
 646:    * Returns the Throwable associated with this <code>LogRecord</code>,
 647:    * or <code>null</code> if the logged event is not related to an exception
 648:    * or error.
 649:    */
 650:   public Throwable getThrown()
 651:   {
 652:     return thrown;
 653:   }
 654: 
 655: 
 656:   /**
 657:    * Associates this <code>LogRecord</code> with an exception or error.
 658:    *
 659:    * <p>As soon as a <code>LogRecord</code> has been handed over
 660:    * to the logging framework, applications should not modify it
 661:    * anymore.  Therefore, this method should only be called on
 662:    * freshly constructed LogRecords.
 663:    *
 664:    * @param thrown the exception or error to associate with, or
 665:    *               <code>null</code> if this <code>LogRecord</code>
 666:    *               should be made unrelated to an exception or error.
 667:    */
 668:   public void setThrown(Throwable thrown)
 669:   {
 670:     this.thrown = thrown;
 671:   }
 672: }