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