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