Return-Path: Delivered-To: apmail-incubator-harmony-commits-archive@www.apache.org Received: (qmail 57440 invoked from network); 28 Jun 2006 10:55:18 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 28 Jun 2006 10:55:18 -0000 Received: (qmail 96365 invoked by uid 500); 28 Jun 2006 10:55:18 -0000 Delivered-To: apmail-incubator-harmony-commits-archive@incubator.apache.org Received: (qmail 96325 invoked by uid 500); 28 Jun 2006 10:55:17 -0000 Mailing-List: contact harmony-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: harmony-dev@incubator.apache.org Delivered-To: mailing list harmony-commits@incubator.apache.org Received: (qmail 96314 invoked by uid 99); 28 Jun 2006 10:55:17 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 28 Jun 2006 03:55:17 -0700 X-ASF-Spam-Status: No, hits=-8.6 required=10.0 tests=ALL_TRUSTED,INFO_TLD,NO_REAL_NAME X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: local policy) Received: from [140.211.166.113] (HELO eris.apache.org) (140.211.166.113) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 28 Jun 2006 03:55:15 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id A4FFF1A983A; Wed, 28 Jun 2006 03:54:55 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r417718 - in /incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging: LogManager.java Logger.java Date: Wed, 28 Jun 2006 10:54:55 -0000 To: harmony-commits@incubator.apache.org From: mloenko@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20060628105455.A4FFF1A983A@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N 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; - -/** - * LogManager is used to maintain configuration properties of the - * logging framework, and to manage a hierarchical namespace of all named - * Logger objects. - *

- * There is only one global LogManager instance in the - * application, which can be get by calling static method - * LogManager.getLogManager(). This instance is created and - * inited during class initialization and cannot be changed. - *

- *

- * The LogManager class can be specified by - * java.util.logging.manager system property, if the property is unavailable or - * invalid, the default class java.util.logging.LogManager will - * be used. - *

- *

- * When initialization, LogManager read its configuration from a - * properties file, which by default is the "lib/logging.properties" in the JRE - * directory. - *

- *

- * However, two optional system properties can be used to customize the initial - * configuration process of LogManager. - *

    - *
  • "java.util.logging.config.class"
  • - *
  • "java.util.logging.config.file"
  • - *
- *

- *

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

- *

- * The "java.util.logging.config.class" should specifies a class name. If it is - * set, this given class will be loaded and instantiated during - * LogManager initialization, so that this object's default - * constructor can read the initial configuration and define properties for - * LogManager. - *

- *

- * 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 LogManager will read initial - * configuration from this file. - *

- *

- * If neither of these properties is defined, or some exception is throwed - * during these two properties using, the LogManager will read - * its initial configuration from default properties file, as described above. - *

- *

- * The global logging properties may include: - *

    - *
  • "handlers". This property's valus should be a list of class names for - * handler classes separated by whitespace, these classes must be subclasses of - * Handler and each must have a default constructor, these - * classes will be loaded, instantiated and registered as handlers on the root - * Logger (the Logger named ""). These - * Handlers maybe inited lazily.
  • - *
  • "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 - * LogManager configuration
  • - *
- *

- *

- * This class, together with any handler and configuration classes associated - * with it, must be loaded from the system classpath when - * LogManager configuration occurs. - *

- *

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

- *

- * In the LogManager's hierarchical namespace, - * Loggers are organized based on their dot separated names. For - * example, "x.y.z" is child of "x.y". - *

- *

- * Levels for Loggers 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". - *

- *

- * All methods on this type can be taken as being thread safe. - *

- * - */ -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 - * LogManager instance, which can be get by - * LogManager.getLogManager(. 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 LoggingPermission("control") so - * that it is trusted to modify the configuration for logging framework. If - * the check passes, just return, otherwise SecurityException - * 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 - * LoggingPermission("control") - */ - public void checkAccess() { - if (null != System.getSecurityManager()) { - System.getSecurityManager().checkPermission(perm); - } - } - - /** - * Add a given logger into the hierarchical namespace. The - * Logger.addLogger() 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 - *

- * Note that the LogManager may only retain weak references - * to registered loggers. In order to prevent Logger objects - * from being unexpectedly garbage collected it is necessary for - * applications to maintain references to them. - *

- * - * @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 Enumeration of all registered logger names - * - * @return enumeration of registered logger names - */ - public synchronized Enumeration getLoggerNames() { - return loggers.keys(); - } - - /** - * Get the global LogManager instance - * - * @return the global LogManager 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 LogManager instantiation. - *

- * A PropertyChangeEvent must be fired. - *

- * - * @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() { - 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 - * InputStream - *

- * A PropertyChangeEvent must be fired. - *

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

- * 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 - * Level.INFO. - *

- * - * @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 PropertyChangeListener, which will be invoked when - * the properties are reread. - * - * @param l - * the PropertyChangeListener 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 PropertyChangeListener, do nothing if the given - * listener is not found. - * - * @param l - * the PropertyChangeListener 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; + +/** + * LogManager is used to maintain configuration properties of the + * logging framework, and to manage a hierarchical namespace of all named + * Logger objects. + *

+ * There is only one global LogManager instance in the + * application, which can be get by calling static method + * LogManager.getLogManager(). This instance is created and + * inited during class initialization and cannot be changed. + *

+ *

+ * The LogManager class can be specified by + * java.util.logging.manager system property, if the property is unavailable or + * invalid, the default class java.util.logging.LogManager will + * be used. + *

+ *

+ * When initialization, LogManager read its configuration from a + * properties file, which by default is the "lib/logging.properties" in the JRE + * directory. + *

+ *

+ * However, two optional system properties can be used to customize the initial + * configuration process of LogManager. + *

    + *
  • "java.util.logging.config.class"
  • + *
  • "java.util.logging.config.file"
  • + *
+ *

+ *

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

+ *

+ * The "java.util.logging.config.class" should specifies a class name. If it is + * set, this given class will be loaded and instantiated during + * LogManager initialization, so that this object's default + * constructor can read the initial configuration and define properties for + * LogManager. + *

+ *

+ * 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 LogManager will read initial + * configuration from this file. + *

+ *

+ * If neither of these properties is defined, or some exception is throwed + * during these two properties using, the LogManager will read + * its initial configuration from default properties file, as described above. + *

+ *

+ * The global logging properties may include: + *

    + *
  • "handlers". This property's valus should be a list of class names for + * handler classes separated by whitespace, these classes must be subclasses of + * Handler and each must have a default constructor, these + * classes will be loaded, instantiated and registered as handlers on the root + * Logger (the Logger named ""). These + * Handlers maybe inited lazily.
  • + *
  • "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 + * LogManager configuration
  • + *
+ *

+ *

+ * This class, together with any handler and configuration classes associated + * with it, must be loaded from the system classpath when + * LogManager configuration occurs. + *

+ *

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

+ *

+ * In the LogManager's hierarchical namespace, + * Loggers are organized based on their dot separated names. For + * example, "x.y.z" is child of "x.y". + *

+ *

+ * Levels for Loggers 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". + *

+ *

+ * All methods on this type can be taken as being thread safe. + *

+ * + */ +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 + * LogManager instance, which can be get by + * LogManager.getLogManager(. 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 LoggingPermission("control") so + * that it is trusted to modify the configuration for logging framework. If + * the check passes, just return, otherwise SecurityException + * 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 + * LoggingPermission("control") + */ + public void checkAccess() { + if (null != System.getSecurityManager()) { + System.getSecurityManager().checkPermission(perm); + } + } + + /** + * Add a given logger into the hierarchical namespace. The + * Logger.addLogger() 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 + *

+ * Note that the LogManager may only retain weak references + * to registered loggers. In order to prevent Logger objects + * from being unexpectedly garbage collected it is necessary for + * applications to maintain references to them. + *

+ * + * @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 Enumeration of all registered logger names + * + * @return enumeration of registered logger names + */ + public synchronized Enumeration getLoggerNames() { + return loggers.keys(); + } + + /** + * Get the global LogManager instance + * + * @return the global LogManager 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 LogManager instantiation. + *

+ * A PropertyChangeEvent must be fired. + *

+ * + * @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() { + 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 + * InputStream + *

+ * A PropertyChangeEvent must be fired. + *

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

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

+ * + * @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 PropertyChangeListener, which will be invoked when + * the properties are reread. + * + * @param l + * the PropertyChangeListener 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 PropertyChangeListener, do nothing if the given + * listener is not found. + * + * @param l + * the PropertyChangeListener 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 handlers; + private List 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 childs; + /* * ------------------------------------------------------------------- * Constructors @@ -160,12 +168,46 @@ } this.name = name; this.parent = null; - this.level = null; this.filter = null; - this.handlers = new Vector(); + this.handlers = new ArrayList(); + this.childs = new ArrayList(); 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; } }