| /* Logger.java -- a class for logging messages |
| Copyright (C) 2002, 2004, 2006, 2007 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package java.util.logging; |
| |
| import gnu.java.lang.CPStringBuilder; |
| |
| import java.util.List; |
| import java.util.MissingResourceException; |
| import java.util.ResourceBundle; |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| |
| /** |
| * A Logger is used for logging information about events. Usually, there is a |
| * seprate logger for each subsystem or component, although there is a shared |
| * instance for components that make only occasional use of the logging |
| * framework. |
| * <p> |
| * It is common to name a logger after the name of a corresponding Java package. |
| * Loggers are organized into a hierarchical namespace; for example, the logger |
| * <code>"org.gnu.foo"</code> is the <em>parent</em> of logger |
| * <code>"org.gnu.foo.bar"</code>. |
| * <p> |
| * A logger for a named subsystem can be obtained through {@link |
| * java.util.logging.Logger#getLogger(java.lang.String)}. However, only code |
| * which has been granted the permission to control the logging infrastructure |
| * will be allowed to customize that logger. Untrusted code can obtain a |
| * private, anonymous logger through {@link #getAnonymousLogger()} if it wants |
| * to perform any modifications to the logger. |
| * <p> |
| * FIXME: Write more documentation. |
| * |
| * @author Sascha Brawer (brawer@acm.org) |
| */ |
| public class Logger |
| { |
| static final Logger root = new Logger("", null); |
| |
| /** |
| * A logger provided to applications that make only occasional use of the |
| * logging framework, typically early prototypes. Serious products are |
| * supposed to create and use their own Loggers, so they can be controlled |
| * individually. |
| */ |
| public static final Logger global; |
| |
| /** |
| * Use to lock methods on this class instead of calling synchronize on methods |
| * to avoid deadlocks. Yeah, no kidding, we got them :) |
| */ |
| private static final Object[] lock = new Object[0]; |
| |
| static |
| { |
| // Our class might be initialized from an unprivileged context |
| global = (Logger) AccessController.doPrivileged(new PrivilegedAction() |
| { |
| public Object run() |
| { |
| return getLogger("global"); |
| } |
| }); |
| } |
| |
| /** |
| * The name of the Logger, or <code>null</code> if the logger is anonymous. |
| * <p> |
| * A previous version of the GNU Classpath implementation granted untrusted |
| * code the permission to control any logger whose name was null. However, |
| * test code revealed that the Sun J2SE 1.4 reference implementation enforces |
| * the security control for any logger that was not created through |
| * getAnonymousLogger, even if it has a null name. Therefore, a separate flag |
| * {@link Logger#anonymous} was introduced. |
| */ |
| private final String name; |
| |
| /** |
| * The name of the resource bundle used for localization. |
| * <p> |
| * This variable cannot be declared as <code>final</code> because its value |
| * can change as a result of calling getLogger(String,String). |
| */ |
| private String resourceBundleName; |
| |
| /** |
| * The resource bundle used for localization. |
| * <p> |
| * This variable cannot be declared as <code>final</code> because its value |
| * can change as a result of calling getLogger(String,String). |
| */ |
| private ResourceBundle resourceBundle; |
| |
| private Filter filter; |
| |
| private final List handlerList = new java.util.ArrayList(4); |
| |
| private Handler[] handlers = new Handler[0]; |
| |
| /** |
| * Indicates whether or not this logger is anonymous. While a |
| * LoggingPermission is required for any modifications to a normal logger, |
| * untrusted code can obtain an anonymous logger and modify it according to |
| * its needs. |
| * <p> |
| * A previous version of the GNU Classpath implementation granted access to |
| * every logger whose name was null. However, test code revealed that the Sun |
| * J2SE 1.4 reference implementation enforces the security control for any |
| * logger that was not created through getAnonymousLogger, even if it has a |
| * null name. |
| */ |
| private boolean anonymous; |
| |
| private boolean useParentHandlers; |
| |
| private Level level; |
| |
| private Logger parent; |
| |
| /** |
| * Constructs a Logger for a subsystem. Most applications do not need to |
| * create new Loggers explicitly; instead, they should call the static factory |
| * methods {@link #getLogger(java.lang.String,java.lang.String) getLogger} |
| * (with ResourceBundle for localization) or |
| * {@link #getLogger(java.lang.String) getLogger} (without ResourceBundle), |
| * respectively. |
| * |
| * @param name the name for the logger, for example "java.awt" or |
| * "com.foo.bar". The name should be based on the name of the |
| * package issuing log records and consist of dot-separated Java |
| * identifiers. |
| * @param resourceBundleName the name of a resource bundle for localizing |
| * messages, or <code>null</code> to indicate that messages do |
| * not need to be localized. |
| * @throws java.util.MissingResourceException if |
| * <code>resourceBundleName</code> is not <code>null</code> |
| * and no such bundle could be located. |
| */ |
| protected Logger(String name, String resourceBundleName) |
| throws MissingResourceException |
| { |
| this.name = name; |
| this.resourceBundleName = resourceBundleName; |
| |
| if (resourceBundleName == null) |
| resourceBundle = null; |
| else |
| resourceBundle = ResourceBundle.getBundle(resourceBundleName); |
| |
| level = null; |
| |
| /* |
| * This is null when the root logger is being constructed, and the root |
| * logger afterwards. |
| */ |
| parent = root; |
| |
| useParentHandlers = (parent != null); |
| } |
| |
| /** |
| * Finds a registered logger for a subsystem, or creates one in case no logger |
| * has been registered yet. |
| * |
| * @param name the name for the logger, for example "java.awt" or |
| * "com.foo.bar". The name should be based on the name of the |
| * package issuing log records and consist of dot-separated Java |
| * identifiers. |
| * @throws IllegalArgumentException if a logger for the subsystem identified |
| * by <code>name</code> has already been created, but uses a a |
| * resource bundle for localizing messages. |
| * @throws NullPointerException if <code>name</code> is <code>null</code>. |
| * @return a logger for the subsystem specified by <code>name</code> that |
| * does not localize messages. |
| */ |
| public static Logger getLogger(String name) |
| { |
| return getLogger(name, null); |
| } |
| |
| /** |
| * Finds a registered logger for a subsystem, or creates one in case no logger |
| * has been registered yet. |
| * <p> |
| * If a logger with the specified name has already been registered, the |
| * behavior depends on the resource bundle that is currently associated with |
| * the existing logger. |
| * <ul> |
| * <li>If the existing logger uses the same resource bundle as specified by |
| * <code>resourceBundleName</code>, the existing logger is returned.</li> |
| * <li>If the existing logger currently does not localize messages, the |
| * existing logger is modified to use the bundle specified by |
| * <code>resourceBundleName</code>. The existing logger is then returned. |
| * Therefore, all subsystems currently using this logger will produce |
| * localized messages from now on.</li> |
| * <li>If the existing logger already has an associated resource bundle, but |
| * a different one than specified by <code>resourceBundleName</code>, an |
| * <code>IllegalArgumentException</code> is thrown.</li> |
| * </ul> |
| * |
| * @param name the name for the logger, for example "java.awt" or |
| * "org.gnu.foo". The name should be based on the name of the |
| * package issuing log records and consist of dot-separated Java |
| * identifiers. |
| * @param resourceBundleName the name of a resource bundle for localizing |
| * messages, or <code>null</code> to indicate that messages do |
| * not need to be localized. |
| * @return a logger for the subsystem specified by <code>name</code>. |
| * @throws java.util.MissingResourceException if |
| * <code>resourceBundleName</code> is not <code>null</code> |
| * and no such bundle could be located. |
| * @throws IllegalArgumentException if a logger for the subsystem identified |
| * by <code>name</code> has already been created, but uses a |
| * different resource bundle for localizing messages. |
| * @throws NullPointerException if <code>name</code> is <code>null</code>. |
| */ |
| public static Logger getLogger(String name, String resourceBundleName) |
| { |
| LogManager lm = LogManager.getLogManager(); |
| Logger result; |
| |
| if (name == null) |
| throw new NullPointerException(); |
| |
| /* |
| * Without synchronized(lm), it could happen that another thread would |
| * create a logger between our calls to getLogger and addLogger. While |
| * addLogger would indicate this by returning false, we could not be sure |
| * that this other logger was still existing when we called getLogger a |
| * second time in order to retrieve it -- note that LogManager is only |
| * allowed to keep weak references to registered loggers, so Loggers can be |
| * garbage collected at any time in general, and between our call to |
| * addLogger and our second call go getLogger in particular. Of course, we |
| * assume here that LogManager.addLogger etc. are synchronizing on the |
| * global LogManager object. There is a comment in the implementation of |
| * LogManager.addLogger referring to this comment here, so that any change |
| * in the synchronization of LogManager will be reflected here. |
| */ |
| synchronized (lock) |
| { |
| synchronized (lm) |
| { |
| result = lm.getLogger(name); |
| if (result == null) |
| { |
| boolean couldBeAdded; |
| |
| result = new Logger(name, resourceBundleName); |
| couldBeAdded = lm.addLogger(result); |
| if (! couldBeAdded) |
| throw new IllegalStateException("cannot register new logger"); |
| } |
| else |
| { |
| /* |
| * The logger already exists. Make sure it uses the same |
| * resource bundle for localizing messages. |
| */ |
| String existingBundleName = result.getResourceBundleName(); |
| |
| /* |
| * The Sun J2SE 1.4 reference implementation will return the |
| * registered logger object, even if it does not have a resource |
| * bundle associated with it. However, it seems to change the |
| * resourceBundle of the registered logger to the bundle whose |
| * name was passed to getLogger. |
| */ |
| if ((existingBundleName == null) && |
| (resourceBundleName != null)) |
| { |
| /* |
| * If ResourceBundle.getBundle throws an exception, the |
| * existing logger will be unchanged. This would be |
| * different if the assignment to resourceBundleName came |
| * first. |
| */ |
| result.resourceBundle = |
| ResourceBundle.getBundle(resourceBundleName); |
| |
| result.resourceBundleName = resourceBundleName; |
| return result; |
| } |
| |
| if ((existingBundleName != resourceBundleName) |
| && ((existingBundleName == null) |
| || !existingBundleName.equals(resourceBundleName))) |
| { |
| throw new IllegalArgumentException(); |
| } |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Creates a new, unnamed logger. Unnamed loggers are not registered in the |
| * namespace of the LogManager, and no special security permission is required |
| * for changing their state. Therefore, untrusted applets are able to modify |
| * their private logger instance obtained through this method. |
| * <p> |
| * The parent of the newly created logger will the the root logger, from which |
| * the level threshold and the handlers are inherited. |
| */ |
| public static Logger getAnonymousLogger() |
| { |
| return getAnonymousLogger(null); |
| } |
| |
| /** |
| * Creates a new, unnamed logger. Unnamed loggers are not registered in the |
| * namespace of the LogManager, and no special security permission is required |
| * for changing their state. Therefore, untrusted applets are able to modify |
| * their private logger instance obtained through this method. |
| * <p> |
| * The parent of the newly created logger will the the root logger, from which |
| * the level threshold and the handlers are inherited. |
| * |
| * @param resourceBundleName the name of a resource bundle for localizing |
| * messages, or <code>null</code> to indicate that messages do |
| * not need to be localized. |
| * @throws java.util.MissingResourceException if |
| * <code>resourceBundleName</code> is not <code>null</code> |
| * and no such bundle could be located. |
| */ |
| public static Logger getAnonymousLogger(String resourceBundleName) |
| throws MissingResourceException |
| { |
| Logger result; |
| |
| result = new Logger(null, resourceBundleName); |
| result.anonymous = true; |
| return result; |
| } |
| |
| /** |
| * Returns the name of the resource bundle that is being used for localizing |
| * messages. |
| * |
| * @return the name of the resource bundle used for localizing messages, or |
| * <code>null</code> if the parent's resource bundle is used for |
| * this purpose. |
| */ |
| public String getResourceBundleName() |
| { |
| synchronized (lock) |
| { |
| return resourceBundleName; |
| } |
| } |
| |
| /** |
| * Returns the resource bundle that is being used for localizing messages. |
| * |
| * @return the resource bundle used for localizing messages, or |
| * <code>null</code> if the parent's resource bundle is used for |
| * this purpose. |
| */ |
| public ResourceBundle getResourceBundle() |
| { |
| synchronized (lock) |
| { |
| return resourceBundle; |
| } |
| } |
| |
| /** |
| * Returns the severity level threshold for this <code>Handler</code>. All |
| * log records with a lower severity level will be discarded; a log record of |
| * the same or a higher level will be published unless an installed |
| * <code>Filter</code> decides to discard it. |
| * |
| * @return the severity level below which all log messages will be discarded, |
| * or <code>null</code> if the logger inherits the threshold from |
| * its parent. |
| */ |
| public Level getLevel() |
| { |
| synchronized (lock) |
| { |
| return level; |
| } |
| } |
| |
| /** |
| * Returns whether or not a message of the specified level would be logged by |
| * this logger. |
| * |
| * @throws NullPointerException if <code>level</code> is <code>null</code>. |
| */ |
| public boolean isLoggable(Level level) |
| { |
| synchronized (lock) |
| { |
| if (this.level != null) |
| return this.level.intValue() <= level.intValue(); |
| |
| if (parent != null) |
| return parent.isLoggable(level); |
| else |
| return false; |
| } |
| } |
| |
| /** |
| * Sets the severity level threshold for this <code>Handler</code>. All log |
| * records with a lower severity level will be discarded immediately. A log |
| * record of the same or a higher level will be published unless an installed |
| * <code>Filter</code> decides to discard it. |
| * |
| * @param level the severity level below which all log messages will be |
| * discarded, or <code>null</code> to indicate that the logger |
| * should inherit the threshold from its parent. |
| * @throws SecurityException if this logger is not anonymous, a security |
| * manager exists, and the caller is not granted the permission to |
| * control the logging infrastructure by having |
| * LoggingPermission("control"). Untrusted code can obtain an |
| * anonymous logger through the static factory method |
| * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. |
| */ |
| public void setLevel(Level level) |
| { |
| synchronized (lock) |
| { |
| /* |
| * An application is allowed to control an anonymous logger without |
| * having the permission to control the logging infrastructure. |
| */ |
| if (! anonymous) |
| LogManager.getLogManager().checkAccess(); |
| |
| this.level = level; |
| } |
| } |
| |
| public Filter getFilter() |
| { |
| synchronized (lock) |
| { |
| return filter; |
| } |
| } |
| |
| /** |
| * @throws SecurityException if this logger is not anonymous, a security |
| * manager exists, and the caller is not granted the permission to |
| * control the logging infrastructure by having |
| * LoggingPermission("control"). Untrusted code can obtain an |
| * anonymous logger through the static factory method |
| * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. |
| */ |
| public void setFilter(Filter filter) throws SecurityException |
| { |
| synchronized (lock) |
| { |
| /* |
| * An application is allowed to control an anonymous logger without |
| * having the permission to control the logging infrastructure. |
| */ |
| if (! anonymous) |
| LogManager.getLogManager().checkAccess(); |
| |
| this.filter = filter; |
| } |
| } |
| |
| /** |
| * Returns the name of this logger. |
| * |
| * @return the name of this logger, or <code>null</code> if the logger is |
| * anonymous. |
| */ |
| public String getName() |
| { |
| /* |
| * Note that the name of a logger cannot be changed during its lifetime, so |
| * no synchronization is needed. |
| */ |
| return name; |
| } |
| |
| /** |
| * Passes a record to registered handlers, provided the record is considered |
| * as loggable both by {@link #isLoggable(Level)} and a possibly installed |
| * custom {@link #setFilter(Filter) filter}. |
| * <p> |
| * If the logger has been configured to use parent handlers, the record will |
| * be forwarded to the parent of this logger in addition to being processed by |
| * the handlers registered with this logger. |
| * <p> |
| * The other logging methods in this class are convenience methods that merely |
| * create a new LogRecord and pass it to this method. Therefore, subclasses |
| * usually just need to override this single method for customizing the |
| * logging behavior. |
| * |
| * @param record the log record to be inspected and possibly forwarded. |
| */ |
| public void log(LogRecord record) |
| { |
| synchronized (lock) |
| { |
| if (!isLoggable(record.getLevel())) |
| return; |
| |
| if ((filter != null) && ! filter.isLoggable(record)) |
| return; |
| |
| /* |
| * If no logger name has been set for the log record, use the name of |
| * this logger. |
| */ |
| if (record.getLoggerName() == null) |
| record.setLoggerName(name); |
| |
| /* |
| * Avoid that some other thread is changing the logger hierarchy while |
| * we are traversing it. |
| */ |
| synchronized (LogManager.getLogManager()) |
| { |
| Logger curLogger = this; |
| |
| do |
| { |
| /* |
| * The Sun J2SE 1.4 reference implementation seems to call the |
| * filter only for the logger whose log method is called, never |
| * for any of its parents. Also, parent loggers publish log |
| * record whatever their level might be. This is pretty weird, |
| * but GNU Classpath tries to be as compatible as possible to |
| * the reference implementation. |
| */ |
| for (int i = 0; i < curLogger.handlers.length; i++) |
| curLogger.handlers[i].publish(record); |
| |
| if (curLogger.getUseParentHandlers() == false) |
| break; |
| |
| curLogger = curLogger.getParent(); |
| } |
| while (parent != null); |
| } |
| } |
| } |
| |
| public void log(Level level, String message) |
| { |
| if (isLoggable(level)) |
| log(level, message, (Object[]) null); |
| } |
| |
| public void log(Level level, String message, Object param) |
| { |
| synchronized (lock) |
| { |
| if (isLoggable(level)) |
| { |
| StackTraceElement caller = getCallerStackFrame(); |
| logp(level, caller != null ? caller.getClassName() : "<unknown>", |
| caller != null ? caller.getMethodName() : "<unknown>", |
| message, param); |
| } |
| } |
| } |
| |
| public void log(Level level, String message, Object[] params) |
| { |
| synchronized (lock) |
| { |
| if (isLoggable(level)) |
| { |
| StackTraceElement caller = getCallerStackFrame(); |
| logp(level, caller != null ? caller.getClassName() : "<unknown>", |
| caller != null ? caller.getMethodName() : "<unknown>", |
| message, params); |
| |
| } |
| } |
| } |
| |
| public void log(Level level, String message, Throwable thrown) |
| { |
| synchronized (lock) |
| { |
| if (isLoggable(level)) |
| { |
| StackTraceElement caller = getCallerStackFrame(); |
| logp(level, caller != null ? caller.getClassName() : "<unknown>", |
| caller != null ? caller.getMethodName() : "<unknown>", |
| message, thrown); |
| } |
| } |
| } |
| |
| public void logp(Level level, String sourceClass, String sourceMethod, |
| String message) |
| { |
| synchronized (lock) |
| { |
| logp(level, sourceClass, sourceMethod, message, (Object[]) null); |
| } |
| } |
| |
| public void logp(Level level, String sourceClass, String sourceMethod, |
| String message, Object param) |
| { |
| synchronized (lock) |
| { |
| logp(level, sourceClass, sourceMethod, message, new Object[] { param }); |
| } |
| |
| } |
| |
| private ResourceBundle findResourceBundle() |
| { |
| synchronized (lock) |
| { |
| if (resourceBundle != null) |
| return resourceBundle; |
| |
| if (parent != null) |
| return parent.findResourceBundle(); |
| |
| return null; |
| } |
| } |
| |
| private void logImpl(Level level, String sourceClass, String sourceMethod, |
| String message, Object[] params) |
| { |
| synchronized (lock) |
| { |
| LogRecord rec = new LogRecord(level, message); |
| |
| rec.setResourceBundle(findResourceBundle()); |
| rec.setSourceClassName(sourceClass); |
| rec.setSourceMethodName(sourceMethod); |
| rec.setParameters(params); |
| |
| log(rec); |
| } |
| } |
| |
| public void logp(Level level, String sourceClass, String sourceMethod, |
| String message, Object[] params) |
| { |
| synchronized (lock) |
| { |
| logImpl(level, sourceClass, sourceMethod, message, params); |
| } |
| } |
| |
| public void logp(Level level, String sourceClass, String sourceMethod, |
| String message, Throwable thrown) |
| { |
| synchronized (lock) |
| { |
| LogRecord rec = new LogRecord(level, message); |
| |
| rec.setResourceBundle(resourceBundle); |
| rec.setSourceClassName(sourceClass); |
| rec.setSourceMethodName(sourceMethod); |
| rec.setThrown(thrown); |
| |
| log(rec); |
| } |
| } |
| |
| public void logrb(Level level, String sourceClass, String sourceMethod, |
| String bundleName, String message) |
| { |
| synchronized (lock) |
| { |
| logrb(level, sourceClass, sourceMethod, bundleName, message, |
| (Object[]) null); |
| } |
| } |
| |
| public void logrb(Level level, String sourceClass, String sourceMethod, |
| String bundleName, String message, Object param) |
| { |
| synchronized (lock) |
| { |
| logrb(level, sourceClass, sourceMethod, bundleName, message, |
| new Object[] { param }); |
| } |
| } |
| |
| public void logrb(Level level, String sourceClass, String sourceMethod, |
| String bundleName, String message, Object[] params) |
| { |
| synchronized (lock) |
| { |
| LogRecord rec = new LogRecord(level, message); |
| |
| rec.setResourceBundleName(bundleName); |
| rec.setSourceClassName(sourceClass); |
| rec.setSourceMethodName(sourceMethod); |
| rec.setParameters(params); |
| |
| log(rec); |
| } |
| } |
| |
| public void logrb(Level level, String sourceClass, String sourceMethod, |
| String bundleName, String message, Throwable thrown) |
| { |
| synchronized (lock) |
| { |
| LogRecord rec = new LogRecord(level, message); |
| |
| rec.setResourceBundleName(bundleName); |
| rec.setSourceClassName(sourceClass); |
| rec.setSourceMethodName(sourceMethod); |
| rec.setThrown(thrown); |
| |
| log(rec); |
| } |
| } |
| |
| public void entering(String sourceClass, String sourceMethod) |
| { |
| synchronized (lock) |
| { |
| if (isLoggable(Level.FINER)) |
| logp(Level.FINER, sourceClass, sourceMethod, "ENTRY"); |
| } |
| } |
| |
| public void entering(String sourceClass, String sourceMethod, Object param) |
| { |
| synchronized (lock) |
| { |
| if (isLoggable(Level.FINER)) |
| logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param); |
| } |
| } |
| |
| public void entering(String sourceClass, String sourceMethod, Object[] params) |
| { |
| synchronized (lock) |
| { |
| if (isLoggable(Level.FINER)) |
| { |
| CPStringBuilder buf = new CPStringBuilder(80); |
| buf.append("ENTRY"); |
| for (int i = 0; i < params.length; i++) |
| { |
| buf.append(" {"); |
| buf.append(i); |
| buf.append('}'); |
| } |
| |
| logp(Level.FINER, sourceClass, sourceMethod, buf.toString(), params); |
| } |
| } |
| } |
| |
| public void exiting(String sourceClass, String sourceMethod) |
| { |
| synchronized (lock) |
| { |
| if (isLoggable(Level.FINER)) |
| logp(Level.FINER, sourceClass, sourceMethod, "RETURN"); |
| } |
| } |
| |
| public void exiting(String sourceClass, String sourceMethod, Object result) |
| { |
| synchronized (lock) |
| { |
| if (isLoggable(Level.FINER)) |
| logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result); |
| } |
| } |
| |
| public void throwing(String sourceClass, String sourceMethod, Throwable thrown) |
| { |
| synchronized (lock) |
| { |
| if (isLoggable(Level.FINER)) |
| logp(Level.FINER, sourceClass, sourceMethod, "THROW", thrown); |
| } |
| } |
| |
| /** |
| * Logs a message with severity level SEVERE, indicating a serious failure |
| * that prevents normal program execution. Messages at this level should be |
| * understandable to an inexperienced, non-technical end user. Ideally, they |
| * explain in simple words what actions the user can take in order to resolve |
| * the problem. |
| * |
| * @see Level#SEVERE |
| * @param message the message text, also used as look-up key if the logger is |
| * localizing messages with a resource bundle. While it is possible |
| * to pass <code>null</code>, this is not recommended, since a |
| * logging message without text is unlikely to be helpful. |
| */ |
| public void severe(String message) |
| { |
| synchronized (lock) |
| { |
| if (isLoggable(Level.SEVERE)) |
| log(Level.SEVERE, message); |
| } |
| } |
| |
| /** |
| * Logs a message with severity level WARNING, indicating a potential problem |
| * that does not prevent normal program execution. Messages at this level |
| * should be understandable to an inexperienced, non-technical end user. |
| * Ideally, they explain in simple words what actions the user can take in |
| * order to resolve the problem. |
| * |
| * @see Level#WARNING |
| * @param message the message text, also used as look-up key if the logger is |
| * localizing messages with a resource bundle. While it is possible |
| * to pass <code>null</code>, this is not recommended, since a |
| * logging message without text is unlikely to be helpful. |
| */ |
| public void warning(String message) |
| { |
| synchronized (lock) |
| { |
| if (isLoggable(Level.WARNING)) |
| log(Level.WARNING, message); |
| } |
| } |
| |
| /** |
| * Logs a message with severity level INFO. {@link Level#INFO} is intended for |
| * purely informational messages that do not indicate error or warning |
| * situations. In the default logging configuration, INFO messages will be |
| * written to the system console. For this reason, the INFO level should be |
| * used only for messages that are important to end users and system |
| * administrators. Messages at this level should be understandable to an |
| * inexperienced, non-technical user. |
| * |
| * @param message the message text, also used as look-up key if the logger is |
| * localizing messages with a resource bundle. While it is possible |
| * to pass <code>null</code>, this is not recommended, since a |
| * logging message without text is unlikely to be helpful. |
| */ |
| public void info(String message) |
| { |
| synchronized (lock) |
| { |
| if (isLoggable(Level.INFO)) |
| log(Level.INFO, message); |
| } |
| } |
| |
| /** |
| * Logs a message with severity level CONFIG. {@link Level#CONFIG} is intended |
| * for static configuration messages, for example about the windowing |
| * environment, the operating system version, etc. |
| * |
| * @param message the message text, also used as look-up key if the logger is |
| * localizing messages with a resource bundle. While it is possible |
| * to pass <code>null</code>, this is not recommended, since a |
| * logging message without text is unlikely to be helpful. |
| */ |
| public void config(String message) |
| { |
| synchronized (lock) |
| { |
| if (isLoggable(Level.CONFIG)) |
| log(Level.CONFIG, message); |
| } |
| } |
| |
| /** |
| * Logs a message with severity level FINE. {@link Level#FINE} is intended for |
| * messages that are relevant for developers using the component generating |
| * log messages. Examples include minor, recoverable failures, or possible |
| * inefficiencies. |
| * |
| * @param message the message text, also used as look-up key if the logger is |
| * localizing messages with a resource bundle. While it is possible |
| * to pass <code>null</code>, this is not recommended, since a |
| * logging message without text is unlikely to be helpful. |
| */ |
| public void fine(String message) |
| { |
| synchronized (lock) |
| { |
| if (isLoggable(Level.FINE)) |
| log(Level.FINE, message); |
| } |
| } |
| |
| /** |
| * Logs a message with severity level FINER. {@link Level#FINER} is intended |
| * for rather detailed tracing, for example entering a method, returning from |
| * a method, or throwing an exception. |
| * |
| * @param message the message text, also used as look-up key if the logger is |
| * localizing messages with a resource bundle. While it is possible |
| * to pass <code>null</code>, this is not recommended, since a |
| * logging message without text is unlikely to be helpful. |
| */ |
| public void finer(String message) |
| { |
| synchronized (lock) |
| { |
| if (isLoggable(Level.FINER)) |
| log(Level.FINER, message); |
| } |
| } |
| |
| /** |
| * Logs a message with severity level FINEST. {@link Level#FINEST} is intended |
| * for highly detailed tracing, for example reaching a certain point inside |
| * the body of a method. |
| * |
| * @param message the message text, also used as look-up key if the logger is |
| * localizing messages with a resource bundle. While it is possible |
| * to pass <code>null</code>, this is not recommended, since a |
| * logging message without text is unlikely to be helpful. |
| */ |
| public void finest(String message) |
| { |
| synchronized (lock) |
| { |
| if (isLoggable(Level.FINEST)) |
| log(Level.FINEST, message); |
| } |
| } |
| |
| /** |
| * Adds a handler to the set of handlers that get notified when a log record |
| * is to be published. |
| * |
| * @param handler the handler to be added. |
| * @throws NullPointerException if <code>handler</code> is <code>null</code>. |
| * @throws SecurityException if this logger is not anonymous, a security |
| * manager exists, and the caller is not granted the permission to |
| * control the logging infrastructure by having |
| * LoggingPermission("control"). Untrusted code can obtain an |
| * anonymous logger through the static factory method |
| * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. |
| */ |
| public void addHandler(Handler handler) throws SecurityException |
| { |
| synchronized (lock) |
| { |
| if (handler == null) |
| throw new NullPointerException(); |
| |
| /* |
| * An application is allowed to control an anonymous logger without |
| * having the permission to control the logging infrastructure. |
| */ |
| if (! anonymous) |
| LogManager.getLogManager().checkAccess(); |
| |
| if (! handlerList.contains(handler)) |
| { |
| handlerList.add(handler); |
| handlers = getHandlers(); |
| } |
| } |
| } |
| |
| /** |
| * Removes a handler from the set of handlers that get notified when a log |
| * record is to be published. |
| * |
| * @param handler the handler to be removed. |
| * @throws SecurityException if this logger is not anonymous, a security |
| * manager exists, and the caller is not granted the permission to |
| * control the logging infrastructure by having |
| * LoggingPermission("control"). Untrusted code can obtain an |
| * anonymous logger through the static factory method {@link |
| * #getAnonymousLogger(java.lang.String) getAnonymousLogger}. |
| * @throws NullPointerException if <code>handler</code> is <code>null</code>. |
| */ |
| public void removeHandler(Handler handler) throws SecurityException |
| { |
| synchronized (lock) |
| { |
| /* |
| * An application is allowed to control an anonymous logger without |
| * having the permission to control the logging infrastructure. |
| */ |
| if (! anonymous) |
| LogManager.getLogManager().checkAccess(); |
| |
| if (handler == null) |
| throw new NullPointerException(); |
| |
| handlerList.remove(handler); |
| handlers = getHandlers(); |
| } |
| } |
| |
| /** |
| * Returns the handlers currently registered for this Logger. When a log |
| * record has been deemed as being loggable, it will be passed to all |
| * registered handlers for publication. In addition, if the logger uses parent |
| * handlers (see {@link #getUseParentHandlers() getUseParentHandlers} and |
| * {@link #setUseParentHandlers(boolean) setUseParentHandlers}, the log |
| * record will be passed to the parent's handlers. |
| */ |
| public Handler[] getHandlers() |
| { |
| synchronized (lock) |
| { |
| /* |
| * We cannot return our internal handlers array because we do not have |
| * any guarantee that the caller would not change the array entries. |
| */ |
| return (Handler[]) handlerList.toArray(new Handler[handlerList.size()]); |
| } |
| } |
| |
| /** |
| * Returns whether or not this Logger forwards log records to handlers |
| * registered for its parent loggers. |
| * |
| * @return <code>false</code> if this Logger sends log records merely to |
| * Handlers registered with itself; <code>true</code> if this Logger |
| * sends log records not only to Handlers registered with itself, but |
| * also to those Handlers registered with parent loggers. |
| */ |
| public boolean getUseParentHandlers() |
| { |
| synchronized (lock) |
| { |
| return useParentHandlers; |
| } |
| } |
| |
| /** |
| * Sets whether or not this Logger forwards log records to handlers registered |
| * for its parent loggers. |
| * |
| * @param useParentHandlers <code>false</code> to let this Logger send log |
| * records merely to Handlers registered with itself; |
| * <code>true</code> to let this Logger send log records not only |
| * to Handlers registered with itself, but also to those Handlers |
| * registered with parent loggers. |
| * @throws SecurityException if this logger is not anonymous, a security |
| * manager exists, and the caller is not granted the permission to |
| * control the logging infrastructure by having |
| * LoggingPermission("control"). Untrusted code can obtain an |
| * anonymous logger through the static factory method |
| * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. |
| */ |
| public void setUseParentHandlers(boolean useParentHandlers) |
| { |
| synchronized (lock) |
| { |
| /* |
| * An application is allowed to control an anonymous logger without |
| * having the permission to control the logging infrastructure. |
| */ |
| if (! anonymous) |
| LogManager.getLogManager().checkAccess(); |
| |
| this.useParentHandlers = useParentHandlers; |
| } |
| } |
| |
| /** |
| * Returns the parent of this logger. By default, the parent is assigned by |
| * the LogManager by inspecting the logger's name. |
| * |
| * @return the parent of this logger (as detemined by the LogManager by |
| * inspecting logger names), the root logger if no other logger has a |
| * name which is a prefix of this logger's name, or <code>null</code> |
| * for the root logger. |
| */ |
| public Logger getParent() |
| { |
| synchronized (lock) |
| { |
| return parent; |
| } |
| } |
| |
| /** |
| * Sets the parent of this logger. Usually, applications do not call this |
| * method directly. Instead, the LogManager will ensure that the tree of |
| * loggers reflects the hierarchical logger namespace. Basically, this method |
| * should not be public at all, but the GNU implementation follows the API |
| * specification. |
| * |
| * @throws NullPointerException if <code>parent</code> is <code>null</code>. |
| * @throws SecurityException if this logger is not anonymous, a security |
| * manager exists, and the caller is not granted the permission to |
| * control the logging infrastructure by having |
| * LoggingPermission("control"). Untrusted code can obtain an |
| * anonymous logger through the static factory method |
| * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. |
| */ |
| public void setParent(Logger parent) |
| { |
| synchronized (lock) |
| { |
| if (parent == null) |
| throw new NullPointerException(); |
| |
| if (this == root) |
| throw new IllegalArgumentException( |
| "the root logger can only have a null parent"); |
| |
| /* |
| * An application is allowed to control an anonymous logger without |
| * having the permission to control the logging infrastructure. |
| */ |
| if (! anonymous) |
| LogManager.getLogManager().checkAccess(); |
| |
| this.parent = parent; |
| } |
| } |
| |
| /** |
| * Gets the StackTraceElement of the first class that is not this class. That |
| * should be the initial caller of a logging method. |
| * |
| * @return caller of the initial logging method or null if unknown. |
| */ |
| private StackTraceElement getCallerStackFrame() |
| { |
| Throwable t = new Throwable(); |
| StackTraceElement[] stackTrace = t.getStackTrace(); |
| int index = 0; |
| |
| // skip to stackentries until this class |
| while (index < stackTrace.length |
| && ! stackTrace[index].getClassName().equals(getClass().getName())) |
| index++; |
| |
| // skip the stackentries of this class |
| while (index < stackTrace.length |
| && stackTrace[index].getClassName().equals(getClass().getName())) |
| index++; |
| |
| return index < stackTrace.length ? stackTrace[index] : null; |
| } |
| |
| /** |
| * Reset and close handlers attached to this logger. This function is package |
| * private because it must only be available to the LogManager. |
| */ |
| void resetLogger() |
| { |
| for (int i = 0; i < handlers.length; i++) |
| { |
| handlers[i].close(); |
| handlerList.remove(handlers[i]); |
| } |
| handlers = getHandlers(); |
| } |
| } |