From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- libjava/classpath/java/util/logging/Logger.java | 1193 +++++++++++++++++++++++ 1 file changed, 1193 insertions(+) create mode 100644 libjava/classpath/java/util/logging/Logger.java (limited to 'libjava/classpath/java/util/logging/Logger.java') diff --git a/libjava/classpath/java/util/logging/Logger.java b/libjava/classpath/java/util/logging/Logger.java new file mode 100644 index 000000000..c55e133e5 --- /dev/null +++ b/libjava/classpath/java/util/logging/Logger.java @@ -0,0 +1,1193 @@ +/* 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. + *

+ * 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 + * "org.gnu.foo" is the parent of logger + * "org.gnu.foo.bar". + *

+ * 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. + *

+ * 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 null if the logger is anonymous. + *

+ * 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. + *

+ * This variable cannot be declared as final because its value + * can change as a result of calling getLogger(String,String). + */ + private String resourceBundleName; + + /** + * The resource bundle used for localization. + *

+ * This variable cannot be declared as final 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. + *

+ * 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 null to indicate that messages do + * not need to be localized. + * @throws java.util.MissingResourceException if + * resourceBundleName is not null + * 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 name has already been created, but uses a a + * resource bundle for localizing messages. + * @throws NullPointerException if name is null. + * @return a logger for the subsystem specified by name 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. + *

+ * 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. + *

+ * + * @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 null to indicate that messages do + * not need to be localized. + * @return a logger for the subsystem specified by name. + * @throws java.util.MissingResourceException if + * resourceBundleName is not null + * and no such bundle could be located. + * @throws IllegalArgumentException if a logger for the subsystem identified + * by name has already been created, but uses a + * different resource bundle for localizing messages. + * @throws NullPointerException if name is null. + */ + 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. + *

+ * 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. + *

+ * 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 null to indicate that messages do + * not need to be localized. + * @throws java.util.MissingResourceException if + * resourceBundleName is not null + * 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 + * null 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 + * null 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 Handler. 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 + * Filter decides to discard it. + * + * @return the severity level below which all log messages will be discarded, + * or null 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 level is null. + */ + 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 Handler. 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 + * Filter decides to discard it. + * + * @param level the severity level below which all log messages will be + * discarded, or null 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 null 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}. + *

+ * 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. + *

+ * 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() : "", + caller != null ? caller.getMethodName() : "", + 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() : "", + caller != null ? caller.getMethodName() : "", + 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() : "", + caller != null ? caller.getMethodName() : "", + 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 null, 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 null, 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 null, 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 null, 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 null, 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 null, 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 null, 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 handler is null. + * @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 handler is null. + */ + 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 false if this Logger sends log records merely to + * Handlers registered with itself; true 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 false to let this Logger send log + * records merely to Handlers registered with itself; + * true 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 null + * 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 parent is null. + * @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(); + } +} -- cgit v1.2.3