Frames | No Frames |
1: /* Logger.java -- a class for logging messages 2: Copyright (C) 2002, 2004, 2005 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.getClassName(), 591: caller.getMethodName(), 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.getClassName(), 604: caller.getMethodName(), 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.getClassName(), 617: caller.getMethodName(), 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: { 1150: if (parent != null) 1151: throw new IllegalArgumentException( 1152: "only the root logger can have a null parent"); 1153: this.parent = null; 1154: return; 1155: } 1156: 1157: /* An application is allowed to control an anonymous logger 1158: * without having the permission to control the logging 1159: * infrastructure. 1160: */ 1161: if (!anonymous) 1162: LogManager.getLogManager().checkAccess(); 1163: 1164: this.parent = parent; 1165: } 1166: 1167: /** 1168: * Gets the StackTraceElement of the first class that is not this class. 1169: * That should be the initial caller of a logging method. 1170: * @return caller of the initial looging method 1171: */ 1172: private native StackTraceElement getCallerStackFrame(); 1173: }