You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by te...@apache.org on 2006/03/15 15:57:17 UTC
svn commit: r386087 [22/45] - in /incubator/harmony/enhanced/classlib/trunk:
make/ make/patternsets/ modules/jndi/ modules/jndi/META-INF/
modules/jndi/make/ modules/jndi/make/common/ modules/jndi/src/
modules/jndi/src/main/ modules/jndi/src/main/java/ ...
Added: incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogManager.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogManager.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogManager.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogManager.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,598 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package java.util.logging;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+/**
+ * <code>LogManager</code> is used to maintain configuration properties of the
+ * logging framework, and to manage a hierarchical namespace of all named
+ * <code>Logger</code> objects.
+ * <p>
+ * There is only one global <code>LogManager</code> instance in the
+ * application, which can be get by calling static method
+ * <code>LogManager.getLogManager()</code>. This instance is created and
+ * inited during class initialization and cannot be changed.
+ * </p>
+ * <p>
+ * The <code>LogManager</code> class can be specified by
+ * java.util.logging.manager system property, if the property is unavailable or
+ * invalid, the default class <code>java.util.logging.LogManager</code> will
+ * be used.
+ * </p>
+ * <p>
+ * When initialization, <code>LogManager</code> read its configuration from a
+ * properties file, which by default is the "lib/logging.properties" in the JRE
+ * directory.
+ * </p>
+ * <p>
+ * However, two optional system properties can be used to customize the initial
+ * configuration process of <code>LogManager</code>.
+ * <ul>
+ * <li>"java.util.logging.config.class"</li>
+ * <li>"java.util.logging.config.file"</li>
+ * </ul>
+ * </p>
+ * <p>
+ * These two properties can be set in three ways, by the Preferences API, by the
+ * "java" command line property definitions, or by system property definitions
+ * passed to JNI_CreateJavaVM.
+ * </p>
+ * <p>
+ * The "java.util.logging.config.class" should specifies a class name. If it is
+ * set, this given class will be loaded and instantiated during
+ * <code>LogManager</code> initialization, so that this object's default
+ * constructor can read the initial configuration and define properties for
+ * <code>LogManager</code>.
+ * </p>
+ * <p>
+ * If "java.util.logging.config.class" property is not set, or it is invalid, or
+ * some exception is throwed during the instantiation, then the
+ * "java.util.logging.config.file" system property can be used to specify a
+ * properties file. The <code>LogManager</code> will read initial
+ * configuration from this file.
+ * </p>
+ * <p>
+ * If neither of these properties is defined, or some exception is throwed
+ * during these two properties using, the <code>LogManager</code> will read
+ * its initial configuration from default properties file, as described above.
+ * </p>
+ * <p>
+ * The global logging properties may include:
+ * <ul>
+ * <li>"handlers". This property's valus should be a list of class names for
+ * handler classes separated by whitespace, these classes must be subclasses of
+ * <code>Handler</code> and each must have a default constructor, these
+ * classes will be loaded, instantiated and registered as handlers on the root
+ * <code>Logger</code> (the <code>Logger</code> named ""). These
+ * <code>Handler</code>s maybe inited lazily.</li>
+ * <li>"config". The property defines a list of class names separated by
+ * whitespace. Each class must have a default constructor, in which it can
+ * update the logging configuration, such as levels, handlers, or filters for
+ * some logger, etc. These classes will be loaded and instantiated during
+ * <code>LogManager</code> configuration</li>
+ * </ul>
+ * </p>
+ * <p>
+ * This class, together with any handler and configuration classes associated
+ * with it, <b>must</b> be loaded from the system classpath when
+ * <code>LogManager</code> configuration occurs.
+ * </p>
+ * <p>
+ * Besides global properties, the properties for loggers and Handlers can be
+ * specified in the property files. The names of these properties will start
+ * with the complete dot separated names for the handlers or loggers.
+ * </p>
+ * <p>
+ * In the <code>LogManager</code>'s hierarchical namespace,
+ * <code>Loggers</code> are organized based on their dot separated names. For
+ * example, "x.y.z" is child of "x.y".
+ * </p>
+ * <p>
+ * Levels for <code>Loggers</code> can be defined by properties whose name end
+ * with ".level". Thus "alogger.level" defines a level for the logger named as
+ * "alogger" and for all its children in the naming hierarchy. Log levels
+ * properties are read and applied in the same order as they are specified in
+ * the property file. The root logger's level can be defined by the property
+ * named as ".level".
+ * </p>
+ * <p>
+ * All methods on this type can be taken as being thread safe.
+ * </p>
+ *
+ */
+public class LogManager {
+ /*
+ * -------------------------------------------------------------------
+ * Class variables
+ * -------------------------------------------------------------------
+ */
+
+ // The line separator of the underlying OS
+ // Use privileged code to read the line.separator system property
+ private static final String lineSeparator = getPrivilegedSystemProperty("line.separator"); //$NON-NLS-1$
+
+ // The file separator of the underlying OS
+ private static final String fileSeparator = File.separator;
+
+ // The shared logging permission
+ private static final LoggingPermission perm = new LoggingPermission(
+ "control", null); //$NON-NLS-1$
+
+ //the singleton instance
+ private static LogManager manager;
+
+ /*
+ * -------------------------------------------------------------------
+ * Instance variables
+ * -------------------------------------------------------------------
+ */
+ private Hashtable loggers;
+
+ private Logger root;
+
+ //the configuration properties
+ private Properties props = null;
+
+ //the property change listener
+ private PropertyChangeSupport listeners = null;
+
+ /*
+ * -------------------------------------------------------------------
+ * Global initialization
+ * -------------------------------------------------------------------
+ */
+
+ static {
+ //init LogManager singleton instance
+ String className = getPrivilegedSystemProperty("java.util.logging.manager"); //$NON-NLS-1$
+ if (null != className) {
+ manager = (LogManager) getInstanceByClass(className);
+ }
+ if (null == manager) {
+ manager = new LogManager();
+ }
+ //init root logger
+ manager.root = new Logger("", null); //$NON-NLS-1$
+ manager.loggers.put("", manager.root); //$NON-NLS-1$
+ //read configuration
+ try {
+ manager.readConfigurationImpl();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ //if global logger has been inited, set root as its parent
+ if (null != Logger.global) {
+ Logger.global.setParent(manager.root);
+ }
+ }
+
+ /*
+ * -------------------------------------------------------------------
+ * Constructor
+ * -------------------------------------------------------------------
+ */
+ /**
+ *
+ * Default constructor. This is not public because there should be only one
+ * <code>LogManager</code> instance, which can be get by
+ * <code>LogManager.getLogManager(</code>. This is protected so that application
+ * can subclass the object.
+ */
+ protected LogManager() {
+ loggers = new Hashtable();
+ props = new Properties();
+ listeners = new PropertyChangeSupport(this);
+ //add shutdown hook to ensure that the associated resource will be freed when JVM exits
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ public void run() {
+ reset();
+ }
+ });
+ return null;
+ }
+ });
+ }
+
+ /*
+ * -------------------------------------------------------------------
+ * Methods
+ * -------------------------------------------------------------------
+ */
+ /*
+ * Package private utilities
+ * Returns the line separator of the underlying OS.
+ */
+ static String getSystemLineSeparator() {
+ return lineSeparator;
+ }
+
+ /**
+ * Check that the caller has <code>LoggingPermission("control")</code> so
+ * that it is trusted to modify the configuration for logging framework.
+ * If the check passes, just return, otherwise <code>SecurityException</code>
+ * will be throwed.
+ *
+ * @throws SecurityException
+ * if there is a security manager in operation and the
+ * invoker of this method does not have the required security
+ * permission <code>LoggingPermission("control")</code>
+ */
+ public void checkAccess() {
+ if (null != System.getSecurityManager()) {
+ System.getSecurityManager().checkPermission(perm);
+ }
+ }
+
+ /**
+ * Add a given logger into the hierarchical namespace. The
+ * <code>Logger.addLogger()</code> factory methods call this method to add
+ * newly created Logger. This returns false if a logger with the given name
+ * has existed in the namespace
+ * <p>
+ * Note that the <code>LogManager</code> may only retain weak references
+ * to registered loggers. In order to prevent <code>Logger</code> objects
+ * from being unexpectedly garbage collected it is necessary for
+ * <i>applications</i> to maintain references to them.
+ * </p>
+ *
+ * @param logger
+ * the logger to be added
+ * @return true if the given logger is added into the namespace
+ * successfully, false if the logger of given name has existed in
+ * the namespace
+ */
+ public synchronized boolean addLogger(Logger logger) {
+ String name = logger.getName();
+ if (null != loggers.get(name)) {
+ return false;
+ }
+ addToFamilyTree(logger, name);
+ loggers.put(name, logger);
+ if (name.length() == 0) {
+ root = logger;
+ }
+ return true;
+ }
+
+ private void addToFamilyTree(Logger logger, String name) {
+ Logger parent = null;
+ //find parent
+ int lastSeparator;
+ String parentName = name;
+ while ((lastSeparator = parentName.lastIndexOf('.')) != -1) {
+ parentName = parentName.substring(0, lastSeparator);
+ if ((parent = (Logger) loggers.get(parentName)) != null) {
+ logger.setParent(parent);
+ break;
+ }
+ }
+ if (parent==null && parent != root) {
+ parent = root;
+ logger.setParent(parent);
+ }
+
+ //find children
+ Logger[] values = (Logger[]) loggers.values().toArray(new Logger[0]);
+ for (int i = 0; i < values.length; i++) {
+ Logger child = values[i];
+ Logger oldParent = child.getParent();
+ if (parent == oldParent && (name.length() == 0 || child.getName().startsWith(name+'.'))) {
+ child.setParent(logger);
+ }
+ }
+ }
+
+ /**
+ * Get the logger with the given name
+ *
+ * @param name name of logger
+ * @return logger with given name, or null if nothing is found
+ */
+ public synchronized Logger getLogger(String name) {
+ return (Logger) loggers.get(name);
+ }
+
+ /**
+ * Get a <code>Enumeration</code> of all registered logger names
+ *
+ * @return enumeration of registered logger names
+ */
+ public synchronized Enumeration getLoggerNames() {
+ return loggers.keys();
+ }
+
+ /**
+ * Get the global <code>LogManager</code> instance
+ *
+ * @return the global <code>LogManager</code> instance
+ */
+ public static LogManager getLogManager() {
+ return manager;
+ }
+
+ /**
+ * Get the value of property with given name
+ *
+ * @param name the name of property
+ * @return the value of property
+ */
+ public synchronized String getProperty(String name) {
+ return props.getProperty(name);
+ }
+
+ /**
+ * Reinitialize the properties and configuration. The initialization process
+ * is same as the <code>LogManager</code> instantiation.
+ * <p>
+ * A <code>PropertyChangeEvent</code> must be fired.
+ * </p>
+ * @throws IOException
+ * if any IO related problems happened
+ * @throws SecurityException
+ * if security manager exists and it determines that caller
+ * does not have the required permissions to perform this
+ * action
+ */
+ public void readConfiguration() throws IOException {
+ readConfigurationImpl();
+ }
+
+ //use privilege code to get system property
+ static String getPrivilegedSystemProperty(final String key) {
+ return (String) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return System.getProperty(key);
+ }
+ });
+ }
+
+ //get system property
+ static String getSystemProperty(final String key) {
+ return System.getProperty(key);
+ }
+
+ //use SystemClassLoader to load class from system classpath
+ static Object getInstanceByClass(final String className) {
+ try {
+ Class clazz = ClassLoader.getSystemClassLoader().loadClass(
+ className);
+ return clazz.newInstance();
+ } catch (Exception e) {
+ System.err
+ .println("Cannot get instance for class name:" + className); //$NON-NLS-1$
+ System.err.println("Caused by " + e.toString()); //$NON-NLS-1$
+ return null;
+ }
+
+ }
+
+ //actual default initilization process
+ private synchronized void readConfigurationImpl() throws IOException {
+ checkAccess();
+ boolean needInit = true;
+
+ //check config class
+ String configClassName = getSystemProperty("java.util.logging.config.class"); //$NON-NLS-1$
+ if (null != configClassName) {
+ if (null == getInstanceByClass(configClassName))
+ throw new RuntimeException("Cannot instantiate " //$NON-NLS-1$
+ + configClassName);
+ needInit = false;
+ }
+ //if config class failed, check config file
+ if (needInit) {
+ String configFile = getSystemProperty("java.util.logging.config.file"); //$NON-NLS-1$
+ if (null == configFile) {
+ //if cannot find configFile, use default logging.properties
+ configFile = new StringBuffer().append(
+ System.getProperty("java.home")).append(fileSeparator) //$NON-NLS-1$
+ .append("lib").append(fileSeparator).append( //$NON-NLS-1$
+ "logging.properties").toString(); //$NON-NLS-1$
+ }
+ InputStream input = null;
+ try {
+ input = new BufferedInputStream(new FileInputStream(configFile));
+ readConfigurationImpl(input);
+ } finally {
+ try {
+ input.close();
+ } catch (Exception e) {//ignore
+ }
+ }
+ }
+ }
+
+ //actual initialization process from a given input stream
+ private synchronized void readConfigurationImpl(InputStream ins)
+ throws IOException {
+ reset();
+ props.load(ins);
+
+ //configs
+ parseConfigProp();
+
+ //handlers
+ parseHandlerProp();
+
+ //set levels for logger
+ initLevelForLoggers();
+ listeners.firePropertyChange(null, null, null);
+ }
+
+ //init "level" properties for all registered loggers
+ private void initLevelForLoggers() {
+ Enumeration enumeration = props.propertyNames();
+ while (enumeration.hasMoreElements()) {
+ //search for all properties whose name is ended with ".level"
+ String loggerLevel = (String) enumeration.nextElement();
+ if (!loggerLevel.endsWith(".level")) { //$NON-NLS-1$
+ continue;
+ }
+ //if find such properties, search for relevant registered logger
+ String loggerName = loggerLevel.substring(0,
+ loggerLevel.length() - 6);
+ Logger l = (Logger) loggers.get(loggerName);
+ if (null == l) {
+ continue;
+ }
+ //if find relevant registered logger, set level for it
+ String levelName = props.getProperty(loggerLevel);
+ Level level = Level.parse(levelName);
+ if (null == level) {
+ continue;
+ }
+ l.setLevel(level);
+ }
+ }
+
+ //parse "handlers" property and apply setting
+ private void parseHandlerProp() {
+ // Logger rootLogger = root.getLogger();
+ String handlers = props.getProperty("handlers"); //$NON-NLS-1$
+ if (null == root || null == handlers) {
+ return;
+ }
+ StringTokenizer st = new StringTokenizer(handlers, " "); //$NON-NLS-1$
+ while (st.hasMoreTokens()) {
+ String handlerName = st.nextToken();
+ Handler handler = (Handler) getInstanceByClass(handlerName);
+ root.addHandler(handler);
+ String level = props.getProperty(handlerName + ".level"); //$NON-NLS-1$
+ if (null != level) {
+ handler.setLevel(Level.parse(level));
+ }
+ }
+ }
+
+ //parse property "config" and apply setting
+ private void parseConfigProp() {
+ String configs = props.getProperty("config"); //$NON-NLS-1$
+ if (null != configs) {
+ StringTokenizer st = new StringTokenizer(configs, " "); //$NON-NLS-1$
+ while (st.hasMoreTokens()) {
+ String configerName = st.nextToken();
+ getInstanceByClass(configerName);
+ }
+ }
+ }
+
+ /**
+ * Reinitialize the properties and configuration from the given
+ * <code>InputStream</code>
+ * <p>
+ * A <code>PropertyChangeEvent</code> must be fired.
+ * </p>
+ *
+ * @param ins the input stream.
+ * @throws IOException
+ * if any IO related problems happened
+ * @throws SecurityException
+ * if security manager exists and it determines that caller
+ * does not have the required permissions to perform this
+ * action
+ */
+ public void readConfiguration(InputStream ins) throws IOException {
+ checkAccess();
+ readConfigurationImpl(ins);
+ }
+
+ /**
+ * Reset configuration.
+ * <p>
+ * All handlers are closed and removed from any named loggers. All loggers'
+ * level is set to null, except the root logger's level is set to
+ * <code>Level.INFO</code>.
+ * </p>
+ *
+ * @throws SecurityException
+ * if security manager exists and it determines that caller
+ * does not have the required permissions to perform this
+ * action
+ */
+ public void reset() {
+ checkAccess();
+ synchronized (this) {
+ props.clear();
+ Iterator it = loggers.values().iterator();
+ while (it.hasNext()) {
+ Logger l = (Logger) it.next();
+ l.setLevel(null);
+ Handler[] handlers = l.getHandlers();
+ for (int i = 0; i < handlers.length; i++) {
+ l.removeHandler(handlers[i]);
+ //close all handlers, when unknown exceptions happen, ignore them and go on
+ try {
+ handlers[i].close();
+ } catch (Exception e) {
+ // Ignored.
+ }
+ }
+ }
+ if (null != root) {
+ root.setLevel(Level.INFO);
+ }
+ }
+ }
+
+ /**
+ * Add a <code>PropertyChangeListener</code>, which will be invoked when
+ * the properties are reread.
+ *
+ * @param l the <code>PropertyChangeListener</code> to be added
+ * @throws SecurityException
+ * if security manager exists and it determines that caller
+ * does not have the required permissions to perform this
+ * action
+ */
+ public void addPropertyChangeListener(PropertyChangeListener l) {
+ checkAccess();
+ listeners.addPropertyChangeListener(l);
+ }
+
+ /**
+ * Remove a <code>PropertyChangeListener</code>, do nothing if the given
+ * listener is not found.
+ *
+ * @param l the <code>PropertyChangeListener</code> to be removed
+ * @throws SecurityException
+ * if security manager exists and it determines that caller
+ * does not have the required permissions to perform this
+ * action
+ */
+ public void removePropertyChangeListener(PropertyChangeListener l) {
+ checkAccess();
+ listeners.removePropertyChangeListener(l);
+ }
+}
+
+
Added: incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogRecord.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogRecord.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogRecord.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogRecord.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,525 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package java.util.logging;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * A <code>LogRecord</code> object represents a logging request. It is passed
+ * between the logging framework and individual logging handlers. Client
+ * applications should not modify a <code>LogRecord</code> object that has
+ * been passed into the logging framework.
+ * <p>
+ * The <code>LogRecord</code> class will infer the source method name and
+ * source class name the first time they are accessed if the client applicaiton
+ * didn't specify them explicitly. This automatic inference is based on the
+ * analysis of the call stack and is not guaranteed to be precise. Client
+ * applications should force the initialization of these two fields by calling
+ * <code>getSourceClassName</code> or <code>getSourceMethodName</code> if
+ * they expect to use them after passing the <code>LogRecord</code> object to
+ * another thread or transmitting it over RMI.
+ * </p>
+ *
+ */
+public class LogRecord implements Serializable {
+
+ //for serialization compability with J2SE1.4.2
+ private static final long serialVersionUID = 5372048053134512534L;
+
+ /*
+ * -------------------------------------------------------------------
+ * Constants
+ * -------------------------------------------------------------------
+ */
+
+ // The major byte used in serialization.
+ private static final int MAJOR = 1;
+
+ // The minor byte used in serialization.
+ private static final int MINOR = 4;
+
+ /*
+ * ------------------------------------------------------------------- Class
+ * variables
+ * -------------------------------------------------------------------
+ */
+
+ // Store the current value for the sequence number.
+ private static long currentSequenceNumber = 0;
+
+ // Store the id for each thread.
+ private static ThreadLocal currentThreadId = new ThreadLocal();
+
+ // The base id as the starting point for thread ID allocation.
+ private static int initThreadId = 0;
+
+ /*
+ * -------------------------------------------------------------------
+ * Instance variables
+ * -------------------------------------------------------------------
+ */
+
+ /**
+ * The logging level.
+ *
+ * @serial
+ */
+ private Level level;
+
+ /**
+ * The sequence number.
+ *
+ * @serial
+ */
+ private long sequenceNumber;
+
+ /**
+ * The name of the class that issued the logging call.
+ *
+ * @serial
+ */
+ private String sourceClassName;
+
+ /**
+ * The name of the method that issued the logging call.
+ *
+ * @serial
+ */
+ private String sourceMethodName;
+
+ /**
+ * The original message text.
+ *
+ * @serial
+ */
+ private String message;
+
+ /**
+ * The ID of the thread that issued the logging call.
+ *
+ * @serial
+ */
+ private int threadID;
+
+ /**
+ * The time that the event occured, in milliseconds since 1970.
+ *
+ * @serial
+ */
+ private long millis;
+
+ /**
+ * The associated <code>Throwable</code> object if any.
+ *
+ * @serial
+ */
+ private Throwable thrown;
+
+ /**
+ * The name of the source logger.
+ *
+ * @serial
+ */
+ private String loggerName;
+
+ /**
+ * The name of the resource bundle used to localize the log message.
+ *
+ * @serial
+ */
+ private String resourceBundleName;
+
+ // The associated resource bundle if any.
+ private transient ResourceBundle resourceBundle;
+
+ // The parameters.
+ private transient Object[] parameters;
+
+ // If the source method and source class has been inited
+ private transient boolean sourceInited = false;
+
+ /*
+ * -------------------------------------------------------------------
+ * Constructors
+ * -------------------------------------------------------------------
+ */
+
+ /**
+ * Constructs a <code>LogRecord</code> object using the supplied the
+ * logging level and message. The millis property is set to the current
+ * time. The sequence property is set to a new unique value, allocated in
+ * increasing order within a VM. The thread ID is set to a unique value for
+ * the current thread. All other properties are set to <code>null</code>.
+ *
+ * @param level
+ * the logging level which may not be null
+ * @param msg
+ * the raw message
+ */
+ public LogRecord(Level level, String msg) {
+ if (null == level) {
+ throw new NullPointerException("null"); //$NON-NLS-1$
+ }
+ this.level = level;
+ this.message = msg;
+ this.millis = System.currentTimeMillis();
+
+ synchronized (LogRecord.class) {
+ this.sequenceNumber = currentSequenceNumber++;
+ Object id = currentThreadId.get();
+ if (null == id) {
+ this.threadID = initThreadId;
+ currentThreadId.set(new Integer(initThreadId++));
+ } else {
+ this.threadID = ((Integer) id).intValue();
+ }
+ }
+
+ this.sourceClassName = null;
+ this.sourceMethodName = null;
+ this.loggerName = null;
+ this.parameters = null;
+ this.resourceBundle = null;
+ this.resourceBundleName = null;
+ this.thrown = null;
+ }
+
+ /*
+ * -------------------------------------------------------------------
+ * Methods
+ * -------------------------------------------------------------------
+ */
+
+ /**
+ * Gets the logging level.
+ *
+ * @return the logging level
+ */
+ public Level getLevel() {
+ return level;
+ }
+
+ /**
+ * Sets the logging level.
+ *
+ * @param level
+ * the level to set
+ */
+ public void setLevel(Level level) {
+ if (null == level)
+ throw new NullPointerException("null"); //$NON-NLS-1$
+ this.level = level;
+ }
+
+ /**
+ * Gets the name of the logger.
+ *
+ * @return the logger name
+ */
+ public String getLoggerName() {
+ return loggerName;
+ }
+
+ /**
+ * Sets the name of the logger.
+ *
+ * @param loggerName
+ * the logger name to set
+ */
+ public void setLoggerName(String loggerName) {
+ this.loggerName = loggerName;
+ }
+
+ /**
+ * Gets the raw message.
+ *
+ * @return the raw message
+ */
+ public String getMessage() {
+ return message;
+ }
+
+ /**
+ * Sets the raw message.
+ *
+ * @param message
+ * the raw message to set
+ */
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ /**
+ * Gets the time that the event occured, in milliseconds since 1970.
+ *
+ * @return the time that the event occured, in milliseconds since 1970
+ */
+ public long getMillis() {
+ return millis;
+ }
+
+ /**
+ * Sets the time that the event occured, in milliseconds since 1970.
+ *
+ * @param millis
+ * the time that the event occured, in milliseconds since 1970
+ */
+ public void setMillis(long millis) {
+ this.millis = millis;
+ }
+
+ /**
+ * Gets the parameters.
+ *
+ * @return the array of parameters
+ */
+ public Object[] getParameters() {
+ return parameters;
+ }
+
+ /**
+ * Sets the parameters.
+ *
+ * @param parameters
+ * the array of parameters to set
+ */
+ public void setParameters(Object[] parameters) {
+ this.parameters = parameters;
+ }
+
+ /**
+ * Gets the resource bundle used to localize the raw message during
+ * formatting.
+ *
+ * @return the associated resource bundle
+ */
+ public ResourceBundle getResourceBundle() {
+ return resourceBundle;
+ }
+
+ /**
+ * Sets the resource bundle used to localize the raw message during
+ * formatting.
+ *
+ * @param resourceBundle
+ * the resource bundle to set
+ */
+ public void setResourceBundle(ResourceBundle resourceBundle) {
+ this.resourceBundle = resourceBundle;
+ }
+
+ /**
+ * Gets the name of the resource bundle.
+ *
+ * @return the name of the resource bundle
+ */
+ public String getResourceBundleName() {
+ return resourceBundleName;
+ }
+
+ /**
+ * Sets the name of the resource bundle.
+ *
+ * @param resourceBundleName
+ * the name of the resource bundle to set
+ */
+ public void setResourceBundleName(String resourceBundleName) {
+ this.resourceBundleName = resourceBundleName;
+ }
+
+ /**
+ * Gets the sequence number.
+ *
+ * @return the sequence number
+ */
+ public long getSequenceNumber() {
+ return sequenceNumber;
+ }
+
+ /**
+ * Sets the sequence number. It is usually unnecessary to call this method
+ * to change the sequence number because the number is allocated when this
+ * instance is constructed.
+ *
+ * @param sequenceNumber
+ * the sequence number to set
+ */
+ public void setSequenceNumber(long sequenceNumber) {
+ this.sequenceNumber = sequenceNumber;
+ }
+
+ /**
+ * Gets the name of the class that issued the logging call.
+ *
+ * @return the name of the class that issued the logging call
+ */
+ public String getSourceClassName() {
+ initSource();
+ return sourceClassName;
+ }
+
+ /*
+ * Init the sourceClass and sourceMethod fields.
+ */
+ private void initSource() {
+ if (!sourceInited) {
+ StackTraceElement[] elements = (new Throwable()).getStackTrace();
+ int i = 0;
+ String current = null;
+ FINDLOG: for (; i < elements.length; i++) {
+ current = elements[i].getClassName();
+ if (current.equals(Logger.class.getName())) {
+ break FINDLOG;
+ }
+ }
+ while(++i<elements.length && elements[i].getClassName().equals(current)) {
+ // do nothing
+ }
+ if (i < elements.length) {
+ this.sourceClassName = elements[i].getClassName();
+ this.sourceMethodName = elements[i].getMethodName();
+ }
+ sourceInited = true;
+ }
+ }
+
+ /**
+ * Sets the name of the class that issued the logging call.
+ *
+ * @param sourceClassName
+ * the name of the class that issued the logging call
+ */
+ public void setSourceClassName(String sourceClassName) {
+ sourceInited = true;
+ this.sourceClassName = sourceClassName;
+ }
+
+ /**
+ * Gets the name of the method that issued the logging call.
+ *
+ * @return the name of the method that issued the logging call
+ */
+ public String getSourceMethodName() {
+ initSource();
+ return sourceMethodName;
+ }
+
+ /**
+ * Sets the name of the method that issued the logging call.
+ *
+ * @param sourceMethodName
+ * the name of the method that issued the logging call
+ */
+ public void setSourceMethodName(String sourceMethodName) {
+ sourceInited = true;
+ this.sourceMethodName = sourceMethodName;
+ }
+
+ /**
+ * Gets the ID of the thread originating the message.
+ *
+ * @return the ID of the thread originating the message
+ */
+ public int getThreadID() {
+ return threadID;
+ }
+
+ /**
+ * Sets the ID of the thread originating the message.
+ *
+ * @param threadID
+ * the ID of the thread originating the message
+ */
+ public void setThreadID(int threadID) {
+ this.threadID = threadID;
+ }
+
+ /**
+ * Gets the <code>Throwable</code> object associated with this log record.
+ *
+ * @return the <code>Throwable</code> object associated with this log
+ * record
+ */
+ public Throwable getThrown() {
+ return thrown;
+ }
+
+ /**
+ * Sets the <code>Throwable</code> object associated with this log record.
+ *
+ * @param thrown
+ * the <code>Throwable</code> object associated with this log
+ * record
+ */
+ public void setThrown(Throwable thrown) {
+ this.thrown = thrown;
+ }
+
+ /*
+ * Customized serialization.
+ */
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ out.writeByte(MAJOR);
+ out.writeByte(MINOR);
+ if (null == parameters) {
+ out.writeInt(-1);
+ } else {
+ out.writeInt(parameters.length);
+ for (int i = 0; i < parameters.length; i++) {
+ out.writeObject(null == parameters[i] ? null : parameters[i]
+ .toString());
+ }
+ }
+ }
+
+ /*
+ * Customized deserialization.
+ */
+ private void readObject(ObjectInputStream in) throws IOException,
+ ClassNotFoundException {
+ in.defaultReadObject();
+ byte major = in.readByte();
+ byte minor = in.readByte();
+ //only check MAJOR version
+ if (major != MAJOR) {
+ throw new IOException("Different version - " + major + "." + minor); //$NON-NLS-1$//$NON-NLS-2$
+ }
+
+ int length = in.readInt();
+ if (length >= 0) {
+ parameters = new Object[length];
+ for (int i = 0; i < parameters.length; i++) {
+ parameters[i] = in.readObject();
+ }
+ }
+ if (null != resourceBundleName) {
+ try {
+ resourceBundle = Logger.loadResourceBundle(resourceBundleName);
+ } catch (MissingResourceException e) {
+ // Cannot find the specified resource bundle
+ resourceBundle = null;
+ }
+ }
+ }
+}
+
Added: incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Logger.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Logger.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Logger.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Logger.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,1324 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package java.util.logging;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.Vector;
+import java.util.MissingResourceException;
+
+/**
+ * Loggers are used to log records to certain outputs, including file, console,
+ * etc. They use various handlers to actually do the output-dependent
+ * operations.
+ * <p>
+ * Client applications can get named loggers by calling the methods
+ * <code>getLogger</code>. They can also get anonymous loggers by calling the
+ * methods <code>getAnonymousLogger</code>. Named loggers are organized in a
+ * namespace hierarchy managed by a log manager. The naming convention is
+ * usually the same as java package's naming convention, i.e., using
+ * dot-separated strings. Anonymous loggers do not belong to any namespace.
+ * </p>
+ * <p>
+ * Loggers "inherit" log level setting from their parent if its own level is set
+ * to <code>null</code>. This is also true for the resource bundle. The
+ * logger's resource bundle is used to localize the log messages if no resource
+ * bundle name is given when a log method is called. If
+ * <code>getUseParentHandlers</code> is <code>true</code>, loggers also
+ * inherit their parent's handlers. Here "inherit" only means the "behaviors"
+ * are inherited. The internal fields value will not change, for example,
+ * <code>getLevel()</code> still returns <code>null</code>.
+ * </p>
+ * <p>
+ * When loading a given resource bundle, the logger first tries to use the
+ * context classloader. If that fails, it tries the system classloader. And if
+ * that still fails, it searches up the class stack and uses each class's
+ * classloader to try to locate the resource bundle.
+ * </p>
+ * <p>
+ * Some log methods accept log requests that do not specify the source class and
+ * source method. In these cases, the logging framework will automatically infer
+ * the calling class and method, but not guaranteed to be accurate.
+ * </p>
+ * <p>
+ * Once a <code>LogRecord</code> object has been passed into the logging
+ * framework, it is owned by the logging framework and the client applications
+ * should not use it any longer.
+ * </p>
+ * <p>
+ * All methods of this class are thread-safe.
+ * </p>
+ *
+ * @see LogManager
+ */
+public class Logger {
+
+ /*
+ * -------------------------------------------------------------------
+ * Constants
+ * -------------------------------------------------------------------
+ */
+
+ // message of "entering" series methods
+ private final static String MSG_ENTERING = "ENTRY"; //$NON-NLS-1$
+
+ // message of "exiting" series methods
+ private final static String MSG_EXITING = "RETURN"; //$NON-NLS-1$
+
+ // message of "throwing" series methods
+ private final static String MSG_THROWING = "THROW"; //$NON-NLS-1$
+
+ /*
+ * --------------------------------------------------------------------
+ * Class variables
+ * --------------------------------------------------------------------
+ */
+
+ /**
+ * The global logger is provided as convenience for casual use.
+ */
+ public final static Logger global = Logger.getLogger("global"); //$NON-NLS-1$
+
+ /*
+ * -------------------------------------------------------------------
+ * Instance variables
+ * -------------------------------------------------------------------
+ */
+
+ // the name of this logger
+ private volatile String name;
+
+ // the parent logger of this logger
+ private Logger parent;
+
+ // the logging level of this logger
+ private Level level;
+
+ // the filter
+ private Filter filter;
+
+ // the name of the resource bundle used to localize logging messages
+ private String resBundleName;
+
+ // the loaded resource bundle according to the specified name
+ private ResourceBundle resBundle;
+
+ // the handlers attached to this logger
+ private Vector handlers;
+
+ /*
+ * flag indicating whether to notify parent's handlers on receiving a log
+ * request
+ */
+ private boolean notifyParentHandlers;
+
+ // flag indicating whether this logger is named or anonymous
+ private boolean isNamed;
+
+ /*
+ * -------------------------------------------------------------------
+ * Constructors
+ * -------------------------------------------------------------------
+ */
+
+ /**
+ * Constructs a <code>Logger</code> object with the supplied name and
+ * resource bundle name.
+ *
+ * @param name
+ * the name of this logger, may be null for anonymous loggers
+ * @param resourceBundleName
+ * the name of the resource bundle used to localize logging
+ * messages, may be null
+ * @throws MissingResourceException
+ * If the specified resource bundle can not be loaded.
+ */
+ protected Logger(String name, String resourceBundleName) {
+ // try to load the specified resource bundle first
+ if (null == resourceBundleName) {
+ this.resBundleName = null;
+ this.resBundle = null;
+ } else {
+ this.resBundle = loadResourceBundle(resourceBundleName);
+ this.resBundleName = resourceBundleName;
+ }
+ this.name = name;
+ this.parent = null;
+ this.level = null;
+ this.filter = null;
+ this.handlers = new Vector();
+ this.notifyParentHandlers = true;
+ // any logger is not anonymous by default
+ this.isNamed = true;
+ }
+
+ /*
+ * -------------------------------------------------------------------
+ * Methods
+ * -------------------------------------------------------------------
+ */
+
+ /**
+ * Load the specified resource bundle, use privileged code.
+ *
+ * @param resourceBundleName
+ * the name of the resource bundle to load, cannot be null
+ * @return the loaded resource bundle.
+ * @throws MissingResourceException
+ * If the specified resource bundle can not be loaded.
+ */
+ static ResourceBundle loadResourceBundle(String resourceBundleName) {
+ // try context class loader to load the resource
+ ClassLoader cl = (ClassLoader) AccessController
+ .doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+ });
+ if (null != cl) {
+ try {
+ return ResourceBundle.getBundle(resourceBundleName, Locale
+ .getDefault(), cl);
+ } catch (MissingResourceException e) {
+ // Failed to load using context classloader, ignore
+ }
+ }
+ // try system class loader to load the resource
+ cl = (ClassLoader) AccessController
+ .doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return ClassLoader.getSystemClassLoader();
+ }
+ });
+ if (null != cl) {
+ try {
+ return ResourceBundle.getBundle(resourceBundleName, Locale
+ .getDefault(), cl);
+ } catch (MissingResourceException e) {
+ // Failed to load using system classloader, ignore
+ }
+ }
+ // try all class loaders up the class stack
+ final Class[] classes = (new PrivateSecurityManager())
+ .privateGetClassContext();
+ // the first class, which is PrivateSecurityManager, is skipped
+ for (int i = 1; i < classes.length; i++) {
+ final int index = i;
+ try {
+ cl = (ClassLoader) AccessController
+ .doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return classes[index].getClassLoader();
+ }
+ });
+ if (null == cl) {
+ continue;
+ }
+ return ResourceBundle.getBundle(resourceBundleName, Locale
+ .getDefault(), cl);
+ } catch (MissingResourceException e) {
+ // Failed to load using the current class's classloader, ignore
+ }
+ }
+ throw new MissingResourceException(
+ "Failed to load the specified resource bundle \"" //$NON-NLS-1$
+ + resourceBundleName + "\".", resourceBundleName, null); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets an anonymous logger to use internally in a thread. Anonymous loggers
+ * are not registered in the log manager's namespace. No security checks
+ * will be performed when updating an anonymous logger's control settings
+ * so that they can be used in applets.
+ * <p>
+ * Anonymous loggers' parent is set to be the root logger. This enables
+ * them to inherit default logging level and handlers from the root logger.
+ * </p>
+ *
+ * @return a new instance of anonymous logger
+ */
+ public static Logger getAnonymousLogger() {
+ return getAnonymousLogger(null);
+ }
+
+ /**
+ * Gets an anonymous logger to use internally in a thread. Anonymous loggers
+ * are not registered in the log manager's namespace. No security checks
+ * will be performed when updating an anonymous logger's control settings
+ * so that they can be used in applets.
+ * <p>
+ * Anonymous loggers' parent is set to be the root logger. This enables
+ * them to inherit default logging level and handlers from the root logger.
+ * </p>
+ *
+ * @param resourceBundleName
+ * the name of the resource bundle used to localize log messages
+ * @return a new instance of anonymous logger
+ * @throws MissingResourceException
+ * If the specified resource bundle can not be loaded.
+ */
+ public static Logger getAnonymousLogger(String resourceBundleName) {
+ final Logger l = new Logger(null, resourceBundleName);
+ l.isNamed = false;
+ l.internalSetParent(LogManager.getLogManager().getLogger("")); //$NON-NLS-1$
+ return l;
+ }
+
+ /*
+ * Check whether the same resource bundle has been specified.
+ * Synchronize to ensure the consistency between resouece bundle
+ * and its name.
+ */
+ private static void updateResourceBundle(Logger l, String resourceBundleName) {
+ synchronized (l) {
+ if (null == l.getResourceBundleName()) {
+ /*
+ * load the resource bundle if none is specified
+ * before
+ */
+ l.resBundle = loadResourceBundle(resourceBundleName);
+ l.resBundleName = resourceBundleName;
+ } else if (!l.getResourceBundleName().equals(resourceBundleName)) {
+ /*
+ * throw exception if the specified resource bundles
+ * are inconsistent with each other, i.e., different
+ * names
+ */
+ throw new IllegalArgumentException(
+ "The specified resource bundle name \"" //$NON-NLS-1$
+ + resourceBundleName
+ + "\" is inconsistent with the existing one \"" //$NON-NLS-1$
+ + l.getResourceBundleName() + "\"."); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /*
+ * Gets a named logger associated with the supplied resource bundle. This
+ * method accepts null resource bundle name. The method body is synchronized
+ * on the instance of the LogManager to insure the consistency of the whole
+ * operation.
+ */
+ private static Logger getLoggerWithRes(String name,
+ String resourceBundleName, boolean hasResourceName) {
+ LogManager man = LogManager.getLogManager();
+ synchronized (man) {
+ // Try to find an existing logger with the specifed name
+ Logger l = man.getLogger(name);
+ // If no existing logger with the same name, create a new one
+ if (null == l) {
+ l = new Logger(name, resourceBundleName);
+ String configedLevel = man.getProperty(name + ".level"); //$NON-NLS-1$
+ if (null != configedLevel) {
+ try {
+ l.setLevel(Level.parse(configedLevel));
+ } catch (IllegalArgumentException e) {
+ // Print invalid level setting to the screen
+ System.err.print("Invalid level name: " + configedLevel //$NON-NLS-1$
+ + "."); //$NON-NLS-1$
+ }
+ }
+ man.addLogger(l);
+ } else if (hasResourceName) {
+ updateResourceBundle(l, resourceBundleName);
+ }
+ return l;
+ }
+ }
+
+ /**
+ * Gets a named logger. The returned logger may already exist, or may be
+ * newly created. If the latter, its level will be set to the configured
+ * level according to the <code>LogManager</code>'s properties if any.
+ *
+ * @param name
+ * the name of the logger to get, cannot be null
+ * @return a named logger
+ * @throws MissingResourceException
+ * If the specified resource bundle can not be loaded.
+ */
+ public static Logger getLogger(String name) {
+ return getLoggerWithRes(name, null, false);
+ }
+
+ /**
+ * Gets a named logger associated with the supplied resource bundle. The
+ * resource bundle will be used to localize logging messages.
+ *
+ * @param name
+ * the name of the logger to get, cannot be null
+ * @param resourceBundleName
+ * the name of the resource bundle, may be null
+ * @return a named logger
+ */
+ public static Logger getLogger(String name, String resourceBundleName) {
+ return getLoggerWithRes(name, resourceBundleName, true);
+ }
+
+ /**
+ * Adds a handler to this logger. The handler will be fed with log records
+ * received by this logger.
+ *
+ * @param handler
+ * the handler object to add, cannot be null
+ * @throws SecurityException
+ * If a security manager determines that the caller does not
+ * have the required permission.
+ */
+ public synchronized void addHandler(Handler handler) {
+ if (null == handler) {
+ throw new NullPointerException("null"); //$NON-NLS-1$
+ }
+ // anonymouse loggers can always add handlers
+ if (this.isNamed) {
+ LogManager.getLogManager().checkAccess();
+ }
+ this.handlers.add(handler);
+ }
+
+ /**
+ * Gets all the hanlders associated with this logger.
+ *
+ * @return an array of all the hanlders associated with this logger
+ */
+ public synchronized Handler[] getHandlers() {
+ return (Handler[]) this.handlers.toArray(new Handler[0]);
+ }
+
+ /**
+ * Removes a handler for this logger. If the specified handler does not
+ * exist, this method has no effect.
+ *
+ * @param handler
+ * the handler to be removed, cannot be null
+ * @throws SecurityException
+ * If a security manager determines that the caller does not
+ * have the required permission.
+ */
+ public synchronized void removeHandler(Handler handler) {
+ // anonymouse loggers can always remove handlers
+ if (this.isNamed) {
+ LogManager.getLogManager().checkAccess();
+ }
+ if (null == handler) {
+ throw new NullPointerException("null"); //$NON-NLS-1$
+ }
+ this.handlers.remove(handler);
+ }
+
+ /**
+ * Gets the filter used by this logger.
+ *
+ * @return the filter used by this logger
+ */
+ public synchronized Filter getFilter() {
+ return this.filter;
+ }
+
+ /**
+ * Sets the filter used by this logger.
+ *
+ * @param newFilter
+ * the filter to set
+ * @throws SecurityException
+ * If a security manager determines that the caller does not
+ * have the required permission.
+ */
+ public synchronized void setFilter(Filter newFilter) {
+ // anonymouse loggers can always set the filter
+ if (this.isNamed) {
+ LogManager.getLogManager().checkAccess();
+ }
+ this.filter = newFilter;
+ }
+
+ /**
+ * Gets the logging level of this logger.
+ *
+ * @return the logging level of this logger
+ */
+ public synchronized Level getLevel() {
+ return this.level;
+ }
+
+ /**
+ * Sets the loggine level for this logger. A <code>null</code> level
+ * indicates this logger will inherit its parent's level.
+ *
+ * @param newLevel
+ * the logging level to set
+ * @throws SecurityException
+ * If a security manager determines that the caller does not
+ * have the required permission.
+ */
+ public synchronized void setLevel(Level newLevel) {
+ // anonymouse loggers can always set the level
+ if (this.isNamed) {
+ LogManager.getLogManager().checkAccess();
+ }
+ this.level = newLevel;
+ }
+
+ /**
+ * Gets the flag which indicates whether to use parent's handlers to publish
+ * incoming log records, potentially recursively up the namespace.
+ *
+ * @return <code>true</code> if set to use parent's handlers, otherwise
+ * <code>false</code>
+ */
+ public synchronized boolean getUseParentHandlers() {
+ return this.notifyParentHandlers;
+ }
+
+ /**
+ * Sets the flag which indicates whether to use parent's handlers to publish
+ * incoming log records, potentially recursively up the namespace.
+ *
+ * @param notifyParentHandlers
+ * the flag whether to use parent's handlers
+ * @throws SecurityException
+ * If a security manager determines that the caller does not
+ * have the required permission.
+ */
+ public synchronized void setUseParentHandlers(boolean notifyParentHandlers) {
+ // anonymouse loggers can always set the useParentHandlers flag
+ if (this.isNamed) {
+ LogManager.getLogManager().checkAccess();
+ }
+ this.notifyParentHandlers = notifyParentHandlers;
+ }
+
+ /**
+ * Gets the parent of this logger in the namespace.
+ *
+ * @return the parent of this logger in the namespace
+ */
+ public synchronized Logger getParent() {
+ return this.parent;
+ }
+
+ /**
+ * Sets the parent of this logger in the namespace. This method should
+ * usually be used by the <code>LogManager</code> object only. This
+ * method does not check security.
+ *
+ * @param newParent
+ * the parent logger to set
+ */
+ synchronized void internalSetParent(Logger newParent) {
+ this.parent = newParent;
+ }
+
+ /**
+ * Sets the parent of this logger in the namespace. This method should
+ * usually be used by the <code>LogManager</code> object only.
+ *
+ * @param parent
+ * the parent logger to set
+ * @throws SecurityException
+ * If a security manager determines that the caller does not
+ * have the required permission.
+ */
+ public synchronized void setParent(Logger parent) {
+ if (null == parent) {
+ throw new NullPointerException("null"); //$NON-NLS-1$
+ }
+ // even anonymous loggers are checked
+ LogManager.getLogManager().checkAccess();
+ this.parent = parent;
+ }
+
+ /**
+ * Gets the name of this logger.
+ *
+ * @return the name of this logger
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Gets the loaded resource bundle used by this logger to localize logging
+ * messages. If it's null, the parent's resource bundle will be inherited.
+ *
+ * @return the loaded resource bundle used by this logger
+ */
+ public synchronized ResourceBundle getResourceBundle() {
+ return this.resBundle;
+ }
+
+ /**
+ * Gets the name of the loaded resource bundle used by this logger to
+ * localize logging messages. If it's null, the parent's resource bundle
+ * name will be inherited.
+ *
+ * @return the name of the loaded resource bundle used by this logger
+ */
+ public synchronized String getResourceBundleName() {
+ return this.resBundleName;
+ }
+
+ /*
+ * This method is for compability. Tests written to the reference
+ * implementation API imply that the isLoggable() method is not called
+ * directly. This behaviour is important because subclass may override
+ * isLoggable() method, so that affect the result of log methods.
+ */
+ private synchronized boolean internalIsLoggable(Level l) {
+ Level effectiveLevel = this.level;
+
+ // try to inherit parent's level if this logger's level is not specified
+ if (null == effectiveLevel) {
+ Logger anyParent = this.parent;
+ while (null != anyParent) {
+ effectiveLevel = anyParent.level;
+ if (null != effectiveLevel) {
+ break;
+ }
+ anyParent = anyParent.parent;
+ }
+ }
+ // default to Level.INFO if no level is specified or inherited
+ if (null == effectiveLevel) {
+ effectiveLevel = Level.INFO;
+ }
+
+ if (effectiveLevel.intValue() == Level.OFF.intValue()) {
+ // always return false if the effective level is off
+ return false;
+ } else if (l.intValue() >= effectiveLevel.intValue()) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Determines whether this logger will actually log messages of the
+ * specified level. The effective level used to do the determination may be
+ * inherited from its parent. The default level is <code>Level.INFO</code>.
+ *
+ * @param l
+ * the level to check
+ * @return <code>true</code> if this logger will actually log this level,
+ * otherwise <code>false</code>
+ */
+ public boolean isLoggable(Level l) {
+ return internalIsLoggable(l);
+ }
+
+ /*
+ * Sets the resource bundle and its name for a supplied LogRecord object.
+ * This method first tries to use this logger's resource bundle if any,
+ * otherwise try to inherit from this logger's parent, recursively up the
+ * namespace. Synchronize to ensure the consistency between resouece bundle
+ * and its name.
+ */
+ private synchronized void setResourceBundle(LogRecord record) {
+ if (null != this.resBundleName) {
+ record.setResourceBundle(this.resBundle);
+ record.setResourceBundleName(this.resBundleName);
+ } else {
+ Logger anyParent = this.parent;
+ while (null != anyParent) {
+ /*
+ * Synchronize to ensure the consistency between resouece bundle
+ * and its name.
+ */
+ synchronized (anyParent) {
+ if (null != anyParent.resBundleName) {
+ record.setResourceBundle(anyParent.resBundle);
+ record.setResourceBundleName(anyParent.resBundleName);
+ return;
+ }
+ }
+ anyParent = anyParent.parent;
+ }
+ }
+ }
+
+ /**
+ * Logs a message indicating entering a method. A log record with log level
+ * <code>Level.FINER</code>, log message "ENTRY", and the specified
+ * source class name and source method name is submitted for logging.
+ *
+ * @param sourceClass
+ * the calling class name
+ * @param sourceMethod
+ * the method name
+ */
+ public void entering(String sourceClass, String sourceMethod) {
+ if (internalIsLoggable(Level.FINER)) {
+ LogRecord record = new LogRecord(Level.FINER, MSG_ENTERING);
+ record.setLoggerName(this.name);
+ record.setSourceClassName(sourceClass);
+ record.setSourceMethodName(sourceMethod);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message indicating entering a method. A log record with log level
+ * <code>Level.FINER</code>, log message "ENTRY", and the specified
+ * source class name and source method name and one parameter is submitted
+ * for logging.
+ *
+ * @param sourceClass
+ * the source class name
+ * @param sourceMethod
+ * the source method name
+ * @param param
+ * the parameter for the method call
+ */
+ public void entering(String sourceClass, String sourceMethod, Object param) {
+ if (internalIsLoggable(Level.FINER)) {
+ LogRecord record = new LogRecord(Level.FINER, MSG_ENTERING + " {0}"); //$NON-NLS-1$
+ record.setLoggerName(this.name);
+ record.setSourceClassName(sourceClass);
+ record.setSourceMethodName(sourceMethod);
+ record.setParameters(new Object[] { param });
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message indicating entering a method. A log record with log level
+ * <code>Level.FINER</code>, log message "ENTRY", and the specified
+ * source class name and source method name and parameters is submitted for
+ * logging.
+ *
+ * @param sourceClass
+ * the source class name
+ * @param sourceMethod
+ * the source method name
+ * @param params
+ * an array of parameters for the method call
+ */
+ public void entering(String sourceClass, String sourceMethod,
+ Object[] params) {
+ if (internalIsLoggable(Level.FINER)) {
+ StringBuffer msg = new StringBuffer(MSG_ENTERING);
+ for (int i = 0; i < params.length; i++) {
+ msg.append(" {" + i + "}"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ LogRecord record = new LogRecord(Level.FINER, msg.toString());
+ record.setLoggerName(this.name);
+ record.setSourceClassName(sourceClass);
+ record.setSourceMethodName(sourceMethod);
+ record.setParameters(params);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message indicating existing a method. A log record with log level
+ * <code>Level.FINER</code>, log message "RETURN", and the specified
+ * source class name and source method name is submitted for logging.
+ *
+ * @param sourceClass
+ * the calling class name
+ * @param sourceMethod
+ * the method name
+ */
+ public void exiting(String sourceClass, String sourceMethod) {
+ if (internalIsLoggable(Level.FINER)) {
+ LogRecord record = new LogRecord(Level.FINER, MSG_EXITING);
+ record.setLoggerName(this.name);
+ record.setSourceClassName(sourceClass);
+ record.setSourceMethodName(sourceMethod);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message indicating exiting a method. A log record with log level
+ * <code>Level.FINER</code>, log message "RETURN", and the specified
+ * source class name and source method name and return value is submitted
+ * for logging.
+ *
+ * @param sourceClass
+ * the source class name
+ * @param sourceMethod
+ * the source method name
+ * @param result
+ * the return value of the method call
+ */
+ public void exiting(String sourceClass, String sourceMethod, Object result) {
+ if (internalIsLoggable(Level.FINER)) {
+ LogRecord record = new LogRecord(Level.FINER, MSG_EXITING + " {0}"); //$NON-NLS-1$
+ record.setLoggerName(this.name);
+ record.setSourceClassName(sourceClass);
+ record.setSourceMethodName(sourceMethod);
+ record.setParameters(new Object[] { result });
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message indicating throwing an exception. A log record with log
+ * level <code>Level.FINER</code>, log message "THROW", and the specified
+ * source class name and source method name and <code>Throwable</code>
+ * object is submitted for logging.
+ *
+ * @param sourceClass
+ * the source class name
+ * @param sourceMethod
+ * the source method name
+ * @param thrown
+ * the <code>Throwable</code> object
+ */
+ public void throwing(String sourceClass, String sourceMethod,
+ Throwable thrown) {
+ if (internalIsLoggable(Level.FINER)) {
+ LogRecord record = new LogRecord(Level.FINER, MSG_THROWING);
+ record.setLoggerName(this.name);
+ record.setSourceClassName(sourceClass);
+ record.setSourceMethodName(sourceMethod);
+ record.setThrown(thrown);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of level <code>Level.SEVERE</code>.
+ *
+ * @param msg
+ * the message to log
+ */
+ public void severe(String msg) {
+ if (internalIsLoggable(Level.SEVERE)) {
+ LogRecord record = new LogRecord(Level.SEVERE, msg);
+ record.setLoggerName(this.name);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of level <code>Level.WARNING</code>.
+ *
+ * @param msg
+ * the message to log
+ */
+ public void warning(String msg) {
+ if (internalIsLoggable(Level.WARNING)) {
+ LogRecord record = new LogRecord(Level.WARNING, msg);
+ record.setLoggerName(this.name);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of level <code>Level.INFO</code>.
+ *
+ * @param msg
+ * the message to log
+ */
+ public void info(String msg) {
+ if (internalIsLoggable(Level.INFO)) {
+ LogRecord record = new LogRecord(Level.INFO, msg);
+ record.setLoggerName(this.name);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of level <code>Level.CONFIG</code>.
+ *
+ * @param msg
+ * the message to log
+ */
+ public void config(String msg) {
+ if (internalIsLoggable(Level.CONFIG)) {
+ LogRecord record = new LogRecord(Level.CONFIG, msg);
+ record.setLoggerName(this.name);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of level <code>Level.FINE</code>.
+ *
+ * @param msg
+ * the message to log
+ */
+ public void fine(String msg) {
+ if (internalIsLoggable(Level.FINE)) {
+ LogRecord record = new LogRecord(Level.FINE, msg);
+ record.setLoggerName(this.name);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of level <code>Level.FINER</code>.
+ *
+ * @param msg
+ * the message to log
+ */
+ public void finer(String msg) {
+ if (internalIsLoggable(Level.FINER)) {
+ LogRecord record = new LogRecord(Level.FINER, msg);
+ record.setLoggerName(this.name);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of level <code>Level.FINEST</code>.
+ *
+ * @param msg
+ * the message to log
+ */
+ public void finest(String msg) {
+ if (internalIsLoggable(Level.FINEST)) {
+ LogRecord record = new LogRecord(Level.FINEST, msg);
+ record.setLoggerName(this.name);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of the specified level.
+ *
+ * @param logLevel
+ * the level of the given message
+ * @param msg
+ * the message to log
+ */
+ public void log(Level logLevel, String msg) {
+ if (internalIsLoggable(logLevel)) {
+ LogRecord record = new LogRecord(logLevel, msg);
+ record.setLoggerName(this.name);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of the specified level with the supplied parameter.
+ *
+ * @param logLevel
+ * the level of the given message
+ * @param msg
+ * the message to log
+ * @param param
+ * the parameter associated with the event that need to be logged
+ */
+ public void log(Level logLevel, String msg, Object param) {
+ if (internalIsLoggable(logLevel)) {
+ LogRecord record = new LogRecord(logLevel, msg);
+ record.setLoggerName(this.name);
+ record.setParameters(new Object[] { param });
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of the specified level with the supplied parameter array.
+ *
+ * @param logLevel
+ * the level of the given message
+ * @param msg
+ * the message to log
+ * @param params
+ * the parameter array associated with the event that need to be
+ * logged
+ */
+ public void log(Level logLevel, String msg, Object[] params) {
+ if (internalIsLoggable(logLevel)) {
+ LogRecord record = new LogRecord(logLevel, msg);
+ record.setLoggerName(this.name);
+ record.setParameters(params);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of the specified level with the supplied
+ * <code>Throwable</code> object.
+ *
+ * @param logLevel
+ * the level of the given message
+ * @param msg
+ * the message to log
+ * @param thrown
+ * the <code>Throwable</code> object associated with the event
+ * that need to be logged
+ */
+ public void log(Level logLevel, String msg, Throwable thrown) {
+ if (internalIsLoggable(logLevel)) {
+ LogRecord record = new LogRecord(logLevel, msg);
+ record.setLoggerName(this.name);
+ record.setThrown(thrown);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a given log record. Only those with a logging level no lower than
+ * this logger's level will be submitted to this logger's handlers for
+ * logging. If <code>getUseParentHandlers()</code> is <code>true</code>,
+ * the log record will also be submitted to the parent logger's handlers,
+ * potentially recursively up the namespace.
+ * <p>
+ * Since all other log methods call this method to actually perform the
+ * logging action, subclasses of this class can override this method to
+ * catch all logging activities.
+ * </p>
+ *
+ * @param record
+ * the log record to be logged
+ */
+ public synchronized void log(LogRecord record) {
+ /*
+ * This method is synchronized so that all other log methods are
+ * synchronized because they all call log(LogRecord) to actually perform
+ * the action.
+ *
+ * Also note all other logging methods checks whether to do the logging.
+ * Since they all call log(LogRecord) to actually perform the action,
+ * this check is done twice. This leaves some room for performance
+ * improvement. Possible ways: 1. Use an instance variable
+ * "lastLoggableRecord" to save the record that passed the first check,
+ * so that the second check may be skipped if log(LogRecord) detects the
+ * supplied record is the same as "lastLoggableRecord". This field is
+ * then reset. 2. Use the field "millis" of LogRecord, negative its
+ * value to indicate it's been checked, then revert its value. Both
+ * approaches are ugly but might be more efficient.
+ */
+ if (internalIsLoggable(record.getLevel())) {
+ // apply the filter if any
+ if (null != this.filter) {
+ if (!this.filter.isLoggable(record)) {
+ return;
+ }
+ }
+ /*
+ * call the handlers of this logger, throw any exception that
+ * occurs
+ */
+ Handler[] ha = this.getHandlers();
+ for (int i = 0; i < ha.length; i++) {
+ ha[i].publish(record);
+ }
+ // call the parent's handlers if set useParentHandlers
+ if (getUseParentHandlers()) {
+ Logger anyParent = this.parent;
+ while (null != anyParent) {
+ ha = anyParent.getHandlers();
+ for (int i = 0; i < ha.length; i++) {
+ ha[i].publish(record);
+ }
+ if (anyParent.getUseParentHandlers()) {
+ anyParent = anyParent.parent;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Logs a message of the given level with the specified source class name
+ * and source method name.
+ *
+ * @param logLevel
+ * the level of the given message
+ * @param sourceClass
+ * the source class name
+ * @param sourceMethod
+ * the source method name
+ * @param msg
+ * the message to be logged
+ */
+ public void logp(Level logLevel, String sourceClass, String sourceMethod,
+ String msg) {
+ if (internalIsLoggable(logLevel)) {
+ LogRecord record = new LogRecord(logLevel, msg);
+ record.setLoggerName(this.name);
+ record.setSourceClassName(sourceClass);
+ record.setSourceMethodName(sourceMethod);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of the given level with the specified source class name
+ * and source method name and parameter.
+ *
+ * @param logLevel
+ * the level of the given message
+ * @param sourceClass
+ * the source class name
+ * @param sourceMethod
+ * the source method name
+ * @param msg
+ * the message to be logged
+ * @param param
+ * the parameter associated with the event that need to be logged
+ */
+ public void logp(Level logLevel, String sourceClass, String sourceMethod,
+ String msg, Object param) {
+ if (internalIsLoggable(logLevel)) {
+ LogRecord record = new LogRecord(logLevel, msg);
+ record.setLoggerName(this.name);
+ record.setSourceClassName(sourceClass);
+ record.setSourceMethodName(sourceMethod);
+ record.setParameters(new Object[] { param });
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of the given level with the specified source class name
+ * and source method name and parameter array.
+ *
+ * @param logLevel
+ * the level of the given message
+ * @param sourceClass
+ * the source class name
+ * @param sourceMethod
+ * the source method name
+ * @param msg
+ * the message to be logged
+ * @param params
+ * the parameter array associated with the event that need to be
+ * logged
+ */
+ public void logp(Level logLevel, String sourceClass, String sourceMethod,
+ String msg, Object[] params) {
+ if (internalIsLoggable(logLevel)) {
+ LogRecord record = new LogRecord(logLevel, msg);
+ record.setLoggerName(this.name);
+ record.setSourceClassName(sourceClass);
+ record.setSourceMethodName(sourceMethod);
+ record.setParameters(params);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of the given level with the specified source class name
+ * and source method name and <code>Throwable</code> object.
+ *
+ * @param logLevel
+ * the level of the given message
+ * @param sourceClass
+ * the source class name
+ * @param sourceMethod
+ * the source method name
+ * @param msg
+ * the message to be logged
+ * @param thrown
+ * the <code>Throwable</code> object
+ */
+ public void logp(Level logLevel, String sourceClass, String sourceMethod,
+ String msg, Throwable thrown) {
+ if (internalIsLoggable(logLevel)) {
+ LogRecord record = new LogRecord(logLevel, msg);
+ record.setLoggerName(this.name);
+ record.setSourceClassName(sourceClass);
+ record.setSourceMethodName(sourceMethod);
+ record.setThrown(thrown);
+ setResourceBundle(record);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of the given level with the specified source class name
+ * and source method name, using the given resource bundle to localize the
+ * message.
+ *
+ * @param logLevel
+ * the level of the given message
+ * @param sourceClass
+ * the source class name
+ * @param sourceMethod
+ * the source method name
+ * @param bundleName
+ * the name of the resource bundle, used to localize the message
+ * @param msg
+ * the message to be logged
+ */
+ public void logrb(Level logLevel, String sourceClass, String sourceMethod,
+ String bundleName, String msg) {
+ if (internalIsLoggable(logLevel)) {
+ LogRecord record = new LogRecord(logLevel, msg);
+ if (null != bundleName) {
+ try {
+ record.setResourceBundle(loadResourceBundle(bundleName));
+ } catch (MissingResourceException e) {
+ // ignore
+ }
+ record.setResourceBundleName(bundleName);
+ }
+ record.setLoggerName(this.name);
+ record.setSourceClassName(sourceClass);
+ record.setSourceMethodName(sourceMethod);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of the given level with the specified source class name
+ * and source method name and parameter, using the given resource bundle to
+ * localize the message.
+ *
+ * @param logLevel
+ * the level of the given message
+ * @param sourceClass
+ * the source class name
+ * @param sourceMethod
+ * the source method name
+ * @param bundleName
+ * the name of the resource bundle, used to localize the message
+ * @param msg
+ * the message to be logged
+ * @param param
+ * the parameter associated with the event that need to be logged
+ */
+ public void logrb(Level logLevel, String sourceClass, String sourceMethod,
+ String bundleName, String msg, Object param) {
+ if (internalIsLoggable(logLevel)) {
+ LogRecord record = new LogRecord(logLevel, msg);
+ if (null != bundleName) {
+ try {
+ record.setResourceBundle(loadResourceBundle(bundleName));
+ } catch (MissingResourceException e) {
+ // ignore
+ }
+ record.setResourceBundleName(bundleName);
+ }
+ record.setLoggerName(this.name);
+ record.setSourceClassName(sourceClass);
+ record.setSourceMethodName(sourceMethod);
+ record.setParameters(new Object[] { param });
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of the given level with the specified source class name
+ * and source method name and parameter array, using the given resource
+ * bundle to localize the message.
+ *
+ * @param logLevel
+ * the level of the given message
+ * @param sourceClass
+ * the source class name
+ * @param sourceMethod
+ * the source method name
+ * @param bundleName
+ * the name of the resource bundle, used to localize the message
+ * @param msg
+ * the message to be logged
+ * @param params
+ * the parameter array associated with the event that need to be
+ * logged
+ */
+ public void logrb(Level logLevel, String sourceClass, String sourceMethod,
+ String bundleName, String msg, Object[] params) {
+ if (internalIsLoggable(logLevel)) {
+ LogRecord record = new LogRecord(logLevel, msg);
+ if (null != bundleName) {
+ try {
+ record.setResourceBundle(loadResourceBundle(bundleName));
+ } catch (MissingResourceException e) {
+ // ignore
+ }
+ record.setResourceBundleName(bundleName);
+ }
+ record.setLoggerName(this.name);
+ record.setSourceClassName(sourceClass);
+ record.setSourceMethodName(sourceMethod);
+ record.setParameters(params);
+ log(record);
+ }
+ }
+
+ /**
+ * Logs a message of the given level with the specified source class name
+ * and source method name and <code>Throwable</code> object, using the
+ * given resource bundle to localize the message.
+ *
+ * @param logLevel
+ * the level of the given message
+ * @param sourceClass
+ * the source class name
+ * @param sourceMethod
+ * the source method name
+ * @param bundleName
+ * the name of the resource bundle, used to localize the message
+ * @param msg
+ * the message to be logged
+ * @param thrown
+ * the <code>Throwable</code> object
+ */
+ public void logrb(Level logLevel, String sourceClass, String sourceMethod,
+ String bundleName, String msg, Throwable thrown) {
+ if (internalIsLoggable(logLevel)) {
+ LogRecord record = new LogRecord(logLevel, msg);
+ if (null != bundleName) {
+ try {
+ record.setResourceBundle(loadResourceBundle(bundleName));
+ } catch (MissingResourceException e) {
+ // ignore
+ }
+ record.setResourceBundleName(bundleName);
+ }
+ record.setLoggerName(this.name);
+ record.setSourceClassName(sourceClass);
+ record.setSourceMethodName(sourceMethod);
+ record.setThrown(thrown);
+ log(record);
+ }
+ }
+
+ /*
+ * This security manager is used to access the class context.
+ */
+ private static class PrivateSecurityManager extends SecurityManager {
+ public Class[] privateGetClassContext() {
+ return super.getClassContext();
+ }
+ }
+
+}
+