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