diff options
Diffstat (limited to 'libjava/java/util/logging/Logger.java')
-rw-r--r-- | libjava/java/util/logging/Logger.java | 1167 |
1 files changed, 1167 insertions, 0 deletions
diff --git a/libjava/java/util/logging/Logger.java b/libjava/java/util/logging/Logger.java new file mode 100644 index 0000000..e142e20 --- /dev/null +++ b/libjava/java/util/logging/Logger.java @@ -0,0 +1,1167 @@ +/* Logger.java + -- a class for logging messages + +Copyright (C) 2002 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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 java.util.ResourceBundle; +import java.util.MissingResourceException; +import java.util.List; + +/** + * 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 +{ + /** + * 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 = 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 = LogManager.getLogManager().rootLogger; + + 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; + + /* Throw NullPointerException if name is null. */ + name.getClass(); + + /* 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 (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 synchronized String getResourceBundleName() + { + 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 synchronized ResourceBundle getResourceBundle() + { + 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 synchronized Level getLevel() + { + 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 synchronized boolean isLoggable(Level level) + { + 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 synchronized void setLevel(Level level) + { + /* 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 synchronized Filter getFilter() + { + 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 synchronized void setFilter(Filter filter) + throws SecurityException + { + /* 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 synchronized void log(LogRecord record) + { + 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) + { + log(level, message, (Object[]) null); + } + + + public synchronized void log(Level level, + String message, + Object param) + { + logp(level, + /* sourceClass*/ null, + /* sourceMethod */ null, + message, + param); + } + + + public synchronized void log(Level level, + String message, + Object[] params) + { + logp(level, + /* sourceClass*/ null, + /* sourceMethod */ null, + message, + params); + } + + + public synchronized void log(Level level, + String message, + Throwable thrown) + { + logp(level, + /* sourceClass*/ null, + /* sourceMethod */ null, + message, + thrown); + } + + + public synchronized void logp(Level level, + String sourceClass, + String sourceMethod, + String message) + { + logp(level, sourceClass, sourceMethod, message, + (Object[]) null); + } + + + public synchronized void logp(Level level, + String sourceClass, + String sourceMethod, + String message, + Object param) + { + logp(level, sourceClass, sourceMethod, message, + new Object[] { param }); + } + + + private synchronized ResourceBundle findResourceBundle() + { + if (resourceBundle != null) + return resourceBundle; + + if (parent != null) + return parent.findResourceBundle(); + + return null; + } + + + private synchronized void logImpl(Level level, + String sourceClass, + String sourceMethod, + String message, + Object[] params) + { + LogRecord rec = new LogRecord(level, message); + + rec.setResourceBundle(findResourceBundle()); + rec.setSourceClassName(sourceClass); + rec.setSourceMethodName(sourceMethod); + rec.setParameters(params); + + log(rec); + } + + + public synchronized void logp(Level level, + String sourceClass, + String sourceMethod, + String message, + Object[] params) + { + logImpl(level, sourceClass, sourceMethod, message, params); + } + + + public synchronized void logp(Level level, + String sourceClass, + String sourceMethod, + String message, + Throwable thrown) + { + LogRecord rec = new LogRecord(level, message); + + rec.setResourceBundle(resourceBundle); + rec.setSourceClassName(sourceClass); + rec.setSourceMethodName(sourceMethod); + rec.setThrown(thrown); + + log(rec); + } + + + public synchronized void logrb(Level level, + String sourceClass, + String sourceMethod, + String bundleName, + String message) + { + logrb(level, sourceClass, sourceMethod, bundleName, + message, (Object[]) null); + } + + + public synchronized void logrb(Level level, + String sourceClass, + String sourceMethod, + String bundleName, + String message, + Object param) + { + logrb(level, sourceClass, sourceMethod, bundleName, + message, new Object[] { param }); + } + + + public synchronized void logrb(Level level, + String sourceClass, + String sourceMethod, + String bundleName, + String message, + Object[] params) + { + LogRecord rec = new LogRecord(level, message); + + rec.setResourceBundleName(bundleName); + rec.setSourceClassName(sourceClass); + rec.setSourceMethodName(sourceMethod); + rec.setParameters(params); + + log(rec); + } + + + public synchronized void logrb(Level level, + String sourceClass, + String sourceMethod, + String bundleName, + String message, + Throwable thrown) + { + LogRecord rec = new LogRecord(level, message); + + rec.setResourceBundleName(bundleName); + rec.setSourceClassName(sourceClass); + rec.setSourceMethodName(sourceMethod); + rec.setThrown(thrown); + + log(rec); + } + + + public synchronized void entering(String sourceClass, + String sourceMethod) + { + if (isLoggable(Level.FINER)) + logp(Level.FINER, sourceClass, sourceMethod, "ENTRY"); + } + + + public synchronized void entering(String sourceClass, + String sourceMethod, + Object param) + { + if (isLoggable(Level.FINER)) + logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param); + } + + + public synchronized void entering(String sourceClass, + String sourceMethod, + Object[] params) + { + if (isLoggable(Level.FINER)) + { + StringBuffer buf = new StringBuffer(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 synchronized void exiting(String sourceClass, + String sourceMethod) + { + if (isLoggable(Level.FINER)) + logp(Level.FINER, sourceClass, sourceMethod, "RETURN"); + } + + + public synchronized void exiting(String sourceClass, + String sourceMethod, + Object result) + { + if (isLoggable(Level.FINER)) + logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result); + } + + + public synchronized void throwing(String sourceClass, + String sourceMethod, + Throwable thrown) + { + 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 synchronized void severe(String message) + { + 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 synchronized void warning(String message) + { + 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 synchronized void info(String message) + { + 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 synchronized void config(String message) + { + 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 synchronized void fine(String message) + { + 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 synchronized void finer(String message) + { + 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 synchronized void finest(String message) + { + 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 synchronized void addHandler(Handler handler) + throws SecurityException + { + /* Throw a new NullPointerException if handler is null. */ + handler.getClass(); + + /* 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 synchronized void removeHandler(Handler handler) + throws SecurityException + { + /* An application is allowed to control an anonymous logger + * without having the permission to control the logging + * infrastructure. + */ + if (!anonymous) + LogManager.getLogManager().checkAccess(); + + /* Throw a new NullPointerException if handler is null. */ + handler.getClass(); + + 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 synchronized Handler[] getHandlers() + { + /* 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 synchronized boolean getUseParentHandlers() + { + 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 synchronized void setUseParentHandlers(boolean useParentHandlers) + { + /* 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 synchronized Logger getParent() + { + 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 synchronized void setParent(Logger parent) + { + LogManager lm; + + /* Throw a new NullPointerException if parent is null. */ + parent.getClass(); + + lm = LogManager.getLogManager(); + + if (this == lm.rootLogger) + { + if (parent != null) + throw new IllegalArgumentException( + "only the root logger can have a null parent"); + this.parent = null; + return; + } + + /* 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; + } +} |