You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ml...@apache.org on 2006/06/28 12:54:55 UTC
svn commit: r417718 - in
/incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging:
LogManager.java Logger.java
Author: mloenko
Date: Wed Jun 28 03:54:54 2006
New Revision: 417718
URL: http://svn.apache.org/viewvc?rev=417718&view=rev
Log:
applied patch from HARMONY-673
perf improving for util.logging.Logger
Modified:
incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogManager.java
incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Logger.java
Modified: incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogManager.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogManager.java?rev=417718&r1=417717&r2=417718&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogManager.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogManager.java Wed Jun 28 03:54:54 2006
@@ -1,600 +1,614 @@
-/* Copyright 2004, 2006 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<String, Logger> 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<String, Logger>();
- 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<Object>() {
- 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 = loggers.get(parentName)) != null) {
- logger.setParent(parent);
- break;
- }
- }
- if (parent == null && parent != root) {
- parent = root;
- logger.setParent(parent);
- }
-
- // find children
- Logger[] values = loggers.values().toArray(new Logger[0]);
- for (Logger child : values) {
- 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 loggers.get(name);
- }
-
- /**
- * Get a <code>Enumeration</code> of all registered logger names
- *
- * @return enumeration of registered logger names
- */
- public synchronized Enumeration<String> 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 AccessController.doPrivileged(new PrivilegedAction<String>() {
- public String 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 = 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 (Handler element : handlers) {
- l.removeHandler(element);
- // close all handlers, when unknown exceptions happen,
- // ignore them and go on
- try {
- element.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);
- }
-}
+/* Copyright 2004, 2006 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<String, Logger> 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<String, Logger>();
+ 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<Object>() {
+ 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;
+ }
+
+ setLoggerLevel(logger, name, false);
+ return true;
+ }
+
+ private void setLoggerLevel(Logger logger, String loggerName,
+ boolean inherit) {
+ String configedLevel = getProperty(loggerName + ".level");
+ if (null != configedLevel) {
+ try {
+ logger.setLevel(Level.parse(configedLevel));
+ } catch (IllegalArgumentException e) {
+ // Print invalid level setting to the screen
+ System.err.print("Invalid level name: " + configedLevel
+ + ".");
+ }
+ } else if (inherit) {
+ logger.setLevel(null);
+ }
+ }
+
+ 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 = loggers.get(parentName)) != null) {
+ logger.setParent(parent);
+ break;
+ }
+ }
+ if (parent == null && parent != root) {
+ parent = root;
+ logger.setParent(parent);
+ }
+
+ // find children
+ Logger[] values = loggers.values().toArray(new Logger[0]);
+ for (Logger child : values) {
+ Logger oldParent = child.getParent();
+ if (parent == oldParent
+ && (name.length() == 0 || child.getName().startsWith(
+ name + '.'))) {
+ child.setParent(logger);
+ if (null != oldParent) {
+ //-- remove from old parent childs as the parent has been changed
+ oldParent.removeChild(child);
+ }
+ }
+ }
+ }
+
+ /**
+ * 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 loggers.get(name);
+ }
+
+ /**
+ * Get a <code>Enumeration</code> of all registered logger names
+ *
+ * @return enumeration of registered logger names
+ */
+ public synchronized Enumeration<String> 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 AccessController.doPrivileged(new PrivilegedAction<String>() {
+ public String 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 = loggers.get(loggerName);
+ if (null == l) {
+ continue;
+ }
+ setLoggerLevel(l, loggerName, true);
+ }
+ }
+
+ // 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 synchronized void reset() {
+ checkAccess();
+ props.clear();
+ Iterator it = loggers.values().iterator();
+ while (it.hasNext()) {
+ Logger l = (Logger) it.next();
+ l.setLevel(null);
+ Handler[] handlers = l.getHandlers();
+ for (Handler element : handlers) {
+ l.removeHandler(element);
+ // close all handlers, when unknown exceptions happen,
+ // ignore them and go on
+ try {
+ element.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);
+ }
+}
Modified: incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Logger.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Logger.java?rev=417718&r1=417717&r2=417718&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Logger.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Logger.java Wed Jun 28 03:54:54 2006
@@ -20,8 +20,9 @@
import java.security.PrivilegedAction;
import java.util.Locale;
import java.util.ResourceBundle;
-import java.util.Vector;
import java.util.MissingResourceException;
+import java.util.List;
+import java.util.ArrayList;
/**
* Loggers are used to log records to certain outputs, including file, console,
@@ -84,6 +85,8 @@
// message of "throwing" series methods
private final static String MSG_THROWING = "THROW"; //$NON-NLS-1$
+ private final static int OFF_VALUE = Level.OFF.intValue();
+
/*
* --------------------------------------------------------------------
* Class variables
@@ -108,7 +111,10 @@
private Logger parent;
// the logging level of this logger
- private Level level;
+ private volatile Level levelObjVal;
+
+ // the logging level as int of this logger
+ private volatile int levelIntVal;
// the filter
private Filter filter;
@@ -120,7 +126,7 @@
private ResourceBundle resBundle;
// the handlers attached to this logger
- private Vector<Handler> handlers;
+ private List<Handler> handlers;
/*
* flag indicating whether to notify parent's handlers on receiving a log
@@ -131,6 +137,8 @@
// flag indicating whether this logger is named or anonymous
private boolean isNamed;
+ private List<Logger> childs;
+
/*
* -------------------------------------------------------------------
* Constructors
@@ -160,12 +168,46 @@
}
this.name = name;
this.parent = null;
- this.level = null;
this.filter = null;
- this.handlers = new Vector<Handler>();
+ this.handlers = new ArrayList<Handler>();
+ this.childs = new ArrayList<Logger>();
this.notifyParentHandlers = true;
// any logger is not anonymous by default
this.isNamed = true;
+
+ //-- 'null' means that level will be inherited from parent (see getLevel)
+ //-- Level.INFO is default level if we don't set it. It will be
+ //-- changed to parent level or to configLevel after adding to the
+ //-- family tree. As of this, actually, setting to Level.INFO is
+ //-- not needed here.
+ this.levelObjVal = null;
+ this.levelIntVal = Level.INFO.intValue();
+ }
+
+ //-- should be called under the lm lock
+ private void setLevelImpl(Level newLevel) {
+ // update levels for the whole hierarchy
+ int oldVal = levelIntVal;
+ levelObjVal = newLevel;
+ if (null == newLevel) {
+ levelIntVal = null != parent
+ ? parent.levelIntVal
+ : Level.INFO.intValue();
+ } else {
+ levelIntVal = newLevel.intValue();
+ }
+ if (oldVal != levelIntVal) {
+ forceChildsToInherit();
+ }
+ }
+
+ //-- should be called under the lm lock
+ private void forceChildsToInherit() {
+ for (Logger child : childs) {
+ if (null == child.levelObjVal) { // should inherit
+ child.setLevelImpl(null);
+ }
+ }
}
/*
@@ -324,16 +366,6 @@
// 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);
@@ -398,7 +430,7 @@
* @return an array of all the hanlders associated with this logger
*/
public synchronized Handler[] getHandlers() {
- return this.handlers.toArray(new Handler[0]);
+ return handlers.toArray(new Handler[handlers.size()]);
}
/**
@@ -453,8 +485,8 @@
*
* @return the logging level of this logger
*/
- public synchronized Level getLevel() {
- return this.level;
+ public Level getLevel() {
+ return levelObjVal;
}
/**
@@ -467,12 +499,16 @@
* If a security manager determines that the caller does not
* have the required permission.
*/
- public synchronized void setLevel(Level newLevel) {
+ public void setLevel(Level newLevel) {
// anonymouse loggers can always set the level
if (this.isNamed) {
LogManager.getLogManager().checkAccess();
}
- this.level = newLevel;
+ LogManager lm = LogManager.getLogManager();
+
+ synchronized (lm) {
+ setLevelImpl(newLevel);
+ }
}
/**
@@ -523,6 +559,12 @@
*/
synchronized void internalSetParent(Logger newParent) {
this.parent = newParent;
+ //-- update level after setting a parent.
+ //-- if level == null we should inherit the parent's level
+ if (null == levelObjVal) {
+ setLevelImpl(levelObjVal);
+ }
+ newParent.addChild(this);
}
/**
@@ -541,9 +583,18 @@
}
// even anonymous loggers are checked
LogManager.getLogManager().checkAccess();
- this.parent = parent;
+ internalSetParent(parent);
+ }
+
+ final void addChild(Logger logger) {
+ childs.add(logger);
}
+ final void removeChild(Logger child) {
+ childs.remove(child);
+ }
+
+
/**
* Gets the name of this logger.
*
@@ -580,32 +631,13 @@
* 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()) {
+ private boolean internalIsLoggable(Level l) {
+ int effectiveLevel = levelIntVal;
+ if (effectiveLevel == OFF_VALUE) {
// always return false if the effective level is off
return false;
- } else if (l.intValue() >= effectiveLevel.intValue()) {
- return true;
} else {
- return false;
+ return l.intValue() >= effectiveLevel;
}
}