harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From telli...@apache.org
Subject 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/ ...
Date Wed, 15 Mar 2006 14:57:17 GMT
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();
+        }
+    }
+
+}
+



Mime
View raw message