harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jessewil...@apache.org
Subject svn commit: r833502 - in /harmony/enhanced/classlib/trunk/modules/logging/src: main/java/java/util/logging/LogManager.java main/java/java/util/logging/Logger.java test/java/org/apache/harmony/logging/tests/java/util/logging/LogManagerTest.java
Date Fri, 06 Nov 2009 18:01:34 GMT
Author: jessewilson
Date: Fri Nov  6 18:01:33 2009
New Revision: 833502

URL: http://svn.apache.org/viewvc?rev=833502&view=rev
Log:
Fixing loggers to load handlers eagerly and track them with a CopyOnWriteArrayList. This improves performance and fixes a bug in our current implementation. A test for the bug is included; performance metrics are available in this JIRA:
  https://issues.apache.org/jira/browse/HARMONY-6362
The change to CopyOnWriteArrayList also fixes some concurrency problems. Finally, I've addressed some minor readability issues. I intend to separate style from substance in forthcoming CLs...

Modified:
    harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogManager.java
    harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Logger.java
    harmony/enhanced/classlib/trunk/modules/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LogManagerTest.java

Modified: harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogManager.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogManager.java?rev=833502&r1=833501&r2=833502&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogManager.java (original)
+++ harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/LogManager.java Fri Nov  6 18:01:33 2009
@@ -123,24 +123,17 @@
  * named as ".level".
  * <p>
  * 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
+    /** The line separator of the underlying OS. */
     private static final String lineSeparator = getPrivilegedSystemProperty("line.separator"); //$NON-NLS-1$
 
-    // The shared logging permission
+    /** The shared logging permission. */
     private static final LoggingPermission perm = new LoggingPermission(
             "control", null); //$NON-NLS-1$
 
-    // the singleton instance
+    /** The singleton instance. */
     static LogManager manager;
 
     /**
@@ -151,7 +144,7 @@
     /**
      * Get the {@code LoggingMXBean} instance. this implementation always throws
      * an UnsupportedOperationException.
-     * 
+     *
      * @return the {@code LoggingMXBean} instance
      */
     public static LoggingMXBean getLoggingMXBean() {
@@ -188,10 +181,10 @@
     // FIXME: use weak reference to avoid heap memory leak
     private Hashtable<String, Logger> loggers;
 
-    // the configuration properties
+    /** The configuration properties */
     private Properties props;
 
-    // the property change listener
+    /** the property change listener */
     private PropertyChangeSupport listeners;
 
     static {
@@ -230,7 +223,7 @@
     /**
      * Default constructor. This is not public because there should be only one
      * {@code LogManager} instance, which can be get by
-     * {@code LogManager.getLogManager(}. This is protected so that
+     * {@code LogManager.getLogManager()}. This is protected so that
      * application can subclass the object.
      */
     protected LogManager() {
@@ -265,7 +258,7 @@
      * that it is trusted to modify the configuration for logging framework. If
      * the check passes, just return, otherwise {@code SecurityException}
      * will be thrown.
-     * 
+     *
      * @throws SecurityException
      *             if there is a security manager in operation and the invoker
      *             of this method does not have the required security permission
@@ -288,7 +281,7 @@
      * 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
@@ -314,17 +307,17 @@
             parentName = parentName.substring(0, lastSeparator);
             parent = loggers.get(parentName);
             if (parent != null) {
-                logger.internalSetParent(parent);
+                setParent(logger, parent);
                 break;
             } else if (getProperty(parentName + ".level") != null || //$NON-NLS-1$
                     getProperty(parentName + ".handlers") != null) { //$NON-NLS-1$
                 parent = Logger.getLogger(parentName);
-                logger.internalSetParent(parent);
+                setParent(logger, parent);
                 break;
             }
         }
         if (parent == null && null != (parent = loggers.get(""))) { //$NON-NLS-1$
-            logger.internalSetParent(parent);
+            setParent(logger, parent);
         }
 
         // find children
@@ -344,7 +337,7 @@
                 });
                 if (null != oldParent) {
                     // -- remove from old parent as the parent has been changed
-                    oldParent.removeChild(child);
+                    oldParent.children.remove(child);
                 }
             }
         }
@@ -352,7 +345,7 @@
 
     /**
      * Get the logger with the given name.
-     * 
+     *
      * @param name
      *            name of logger
      * @return logger with given name, or {@code null} if nothing is found.
@@ -363,7 +356,7 @@
 
     /**
      * Get a {@code Enumeration} of all registered logger names.
-     * 
+     *
      * @return enumeration of registered logger names
      */
     public synchronized Enumeration<String> getLoggerNames() {
@@ -372,7 +365,7 @@
 
     /**
      * Get the global {@code LogManager} instance.
-     * 
+     *
      * @return the global {@code LogManager} instance
      */
     public static LogManager getLogManager() {
@@ -381,7 +374,7 @@
 
     /**
      * Get the value of property with given name.
-     * 
+     *
      * @param name
      *            the name of property
      * @return the value of property
@@ -396,7 +389,7 @@
      * <p>
      * Notice : No {@code PropertyChangeEvent} are fired.
      * </p>
-     * 
+     *
      * @throws IOException
      *             if any IO related problems happened.
      * @throws SecurityException
@@ -472,6 +465,13 @@
         reset();
         props.load(ins);
 
+        // The RI treats the root logger as special. For compatibility, always
+        // update the root logger's handlers.
+        Logger root = loggers.get("");
+        if (root != null) {
+            root.setManager(this);
+        }
+
         // parse property "config" and apply setting
         String configs = props.getProperty("config"); //$NON-NLS-1$
         if (null != configs) {
@@ -499,7 +499,7 @@
      * <p>
      * Notice : No {@code PropertyChangeEvent} are fired.
      * </p>
-     * 
+     *
      * @param ins
      *            the input stream
      * @throws IOException
@@ -520,12 +520,12 @@
      * level is set to null, except the root logger's level is set to
      * {@code Level.INFO}.
      * </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() {
+    public synchronized void reset() {
         checkAccess();
         props = new Properties();
         Enumeration<String> names = getLoggerNames();
@@ -545,12 +545,12 @@
     /**
      * Add a {@code PropertyChangeListener}, which will be invoked when
      * the properties are reread.
-     * 
+     *
      * @param l
      *            the {@code 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
+     *             not have the required permissions to perform this action.
      */
     public void addPropertyChangeListener(PropertyChangeListener l) {
         if (l == null) {
@@ -563,15 +563,77 @@
     /**
      * Remove a {@code PropertyChangeListener}, do nothing if the given
      * listener is not found.
-     * 
+     *
      * @param l
      *            the {@code 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
+     *             not have the required permissions to perform this action.
      */
     public void removePropertyChangeListener(PropertyChangeListener l) {
         checkAccess();
         listeners.removePropertyChangeListener(l);
     }
+
+    /**
+     * Returns a named logger associated with the supplied resource bundle.
+     *
+     * @param resourceBundleName the resource bundle to associate, or null for
+     *      no associated resource bundle.
+     */
+    synchronized Logger getOrCreate(String name, String resourceBundleName) {
+        Logger result = getLogger(name);
+        if (result == null) {
+            result = new Logger(name, resourceBundleName);
+            addLogger(result);
+        }
+        return result;
+    }
+
+
+    /**
+     * Sets the parent of this logger in the namespace. Callers must first
+     * {@link #checkAccess() check security}.
+     *
+     * @param newParent
+     *            the parent logger to set.
+     */
+    synchronized void setParent(Logger logger, Logger newParent) {
+        logger.parent = newParent;
+
+        if (logger.levelObjVal == null) {
+            setLevelRecursively(logger, null);
+        }
+        newParent.children.add(logger);
+    }
+
+    /**
+     * Sets the level on {@code logger} to {@code newLevel}. Any child loggers
+     * currently inheriting their level from {@code logger} will be updated
+     * recursively.
+     *
+     * @param newLevel the new minimum logging threshold. If null, the logger's
+     *      parent level will be used; or {@code Level.INFO} for loggers with no
+     *      parent.
+     */
+    synchronized void setLevelRecursively(Logger logger, Level newLevel) {
+        int previous = logger.levelIntVal;
+        logger.levelObjVal = newLevel;
+
+        if (newLevel == null) {
+            logger.levelIntVal = logger.parent != null
+                    ? logger.parent.levelIntVal
+                    : Level.INFO.intValue();
+        } else {
+            logger.levelIntVal = newLevel.intValue();
+        }
+
+        if (previous != logger.levelIntVal) {
+            for (Logger child : logger.children) {
+                if (child.levelObjVal == null) {
+                    setLevelRecursively(child, null);
+                }
+            }
+        }
+    }
 }

Modified: harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Logger.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Logger.java?rev=833502&r1=833501&r2=833502&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Logger.java (original)
+++ harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Logger.java Fri Nov  6 18:01:33 2009
@@ -17,15 +17,17 @@
 
 package java.util.logging;
 
+import org.apache.harmony.logging.internal.nls.Messages;
+
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import java.util.ResourceBundle;
-
-import org.apache.harmony.logging.internal.nls.Messages;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * Loggers are used to log records to certain outputs, including file, console,
@@ -67,49 +69,69 @@
  */
 public class Logger {
 
+    /** The global logger is provided as convenience for casual use. */
+    public final static Logger global = new Logger("global", null); //$NON-NLS-1$
+
     /**
-     * The global logger is provided as convenience for casual use.
+     * When converting the concurrent collection of handlers to an array, we
+     * always pass a zero-length array to avoid size miscalculations. Passing
+     * properly-sized arrays is non-atomic, and risks a null element in the
+     * result.
      */
-    public final static Logger global = new Logger("global", null); //$NON-NLS-1$
+    private static final Handler[] EMPTY_HANDLERS_ARRAY = new Handler[0];
 
-    // the name of this logger
+    /** The name of this logger. */
     private volatile String name;
 
-    // the parent logger of this logger
-    private Logger parent;
+    /** The parent logger of this logger. */
+    Logger parent;
 
-    // the logging level of this logger
-    private volatile Level levelObjVal;
+    /** The logging level of this logger, or null if none is set. */
+    volatile Level levelObjVal;
 
-    // the logging level as int of this logger
-    private volatile int levelIntVal;
+    /**
+     * The effective logging level of this logger. In order of preference this
+     * is the first applicable of:
+     * <ol>
+     * <li>the int value of this logger's {@link #levelObjVal}
+     * <li>the logging level of the parent
+     * <li>the default level ({@link Level#INFO})
+     * </ol>
+     */
+    volatile int levelIntVal = Level.INFO.intValue();
 
-    // the filter
+    /** The filter. */
     private Filter filter;
 
-    // the name of the resource bundle used to localize logging messages
-    private String resBundleName;
-
-    // the loaded resource bundle according to the specified name
-    private ResourceBundle resBundle;
+    /**
+     * The resource bundle used to localize logging messages. If null, no
+     * localization will be performed.
+     */
+    private volatile String resourceBundleName;
 
-    // the handlers attached to this logger
-    private List<Handler> handlers;
+    /** The loaded resource bundle according to the specified name. */
+    private volatile ResourceBundle resourceBundle;
 
-    /*
-     * flag indicating whether to notify parent's handlers on receiving a log
-     * request
+    /**
+     * The handlers attached to this logger. Eagerly initialized and
+     * concurrently modified.
      */
-    private boolean notifyParentHandlers;
+    private final List<Handler> handlers = new CopyOnWriteArrayList<Handler>();
 
-    // flag indicating whether this logger is named or anonymous
-    private boolean isNamed;
+    /** True to notify the parent's handlers of each log message. */
+    private boolean notifyParentHandlers = true;
 
-    private List<Logger> childs;
-
-    private LogManager manager;
+    /**
+     * Indicates whether this logger is named. Only {@link #getAnonymousLogger
+     * anonymous loggers} are unnamed.
+     */
+    private boolean isNamed = true;
 
-    private boolean handlerInited;
+    /**
+     * Child loggers. Should be accessed only while synchronized on {@code
+     * LogManager.getLogManager()}.
+     */
+    final List<Logger> children = new ArrayList<Logger>();
 
     /**
      * Constructs a {@code Logger} object with the supplied name and resource
@@ -127,60 +149,13 @@
      *             if the specified resource bundle can not be loaded.
      */
     protected Logger(String name, String resourceBundleName) {
-        // try to load the specified resource bundle first
-        if (null == resourceBundleName) {
-            this.resBundleName = null;
-            this.resBundle = null;
-        } else {
-            this.resBundle = loadResourceBundle(resourceBundleName);
-            this.resBundleName = resourceBundleName;
-        }
         this.name = name;
-        this.parent = null;
-        this.filter = null;
-        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);
-            }
-        }
+        initResourceBundle(resourceBundleName);
     }
 
     /**
      * Load the specified resource bundle, use privileged code.
-     * 
+     *
      * @param resourceBundleName
      *            the name of the resource bundle to load, cannot be {@code null}.
      * @return the loaded resource bundle.
@@ -195,7 +170,7 @@
                         return Thread.currentThread().getContextClassLoader();
                     }
                 });
-        if (null != cl) {
+        if (cl != null) {
             try {
                 return ResourceBundle.getBundle(resourceBundleName, Locale
                         .getDefault(), cl);
@@ -209,7 +184,7 @@
                 return ClassLoader.getSystemClassLoader();
             }
         });
-        if (null != cl) {
+        if (cl != null) {
             try {
                 return ResourceBundle.getBundle(resourceBundleName, Locale
                         .getDefault(), cl);
@@ -235,7 +210,7 @@
                                 return classes[index].getClassLoader();
                             }
                         });
-                if (null == cl) {
+                if (cl == null) {
                     continue;
                 }
                 return ResourceBundle.getBundle(resourceBundleName, Locale
@@ -279,73 +254,45 @@
      *             if the specified resource bundle can not be loaded.
      */
     public static Logger getAnonymousLogger(String resourceBundleName) {
-        final Logger l = new Logger(null, resourceBundleName);
-        l.isNamed = false;
-        l.internalSetParent(LogManager.getLogManager().getLogger("")); //$NON-NLS-1$
-        return l;
+        Logger result = new Logger(null, resourceBundleName);
+        result.isNamed = false;
+        LogManager logManager = LogManager.getLogManager();
+        logManager.setParent(result, logManager.getLogger(""));
+        return result;
     }
 
-    /*
-     * Check whether the same resource bundle has been specified.
-     * Synchronize to ensure the consistency between resource bundle
-     * and its name.
-     */
-    private static void updateResourceBundle(Logger l, String resourceBundleName) {
-        synchronized (l) {
-            if (null == l.getResourceBundleName()) {
-                if (null == resourceBundleName) {
-                    return;
-                }
-                /*
-                 * load the resource bundle if none is specified before
-                 */
-                l.resBundle = loadResourceBundle(resourceBundleName);
-                l.resBundleName = resourceBundleName;
-            } else if (!l.getResourceBundleName().equals(resourceBundleName)) {
-                /*
-                 * throw exception if the specified resource bundles are
-                 * inconsistent with each other, i.e., different names
-                 */
+    /**
+     * Initializes this logger's resource bundle.
+     *
+     * @throws IllegalArgumentException if this logger's resource bundle already
+     *      exists and is different from the resource bundle specified.
+     */
+    private synchronized void initResourceBundle(String resourceBundleName) {
+        String current = this.resourceBundleName;
+
+        if (current != null) {
+            if (current.equals(resourceBundleName)) {
+                return;
+            } else {
                 // logging.9=The specified resource bundle name "{0}" is
                 // inconsistent with the existing one "{1}".
                 throw new IllegalArgumentException(Messages.getString(
                         "logging.9", //$NON-NLS-1$
-                        resourceBundleName, l.getResourceBundleName()));
+                        resourceBundleName, current));
             }
         }
-    }
 
-    /*
-     * Gets a named logger associated with the supplied resource bundle. This
-     * method accepts null resource bundle name. The method body is synchronized
-     * on the instance of the LogManager to insure the consistency of the whole
-     * operation.
-     */
-    private static Logger getLoggerWithRes(String name,
-            String resourceBundleName, boolean hasResourceName) {
-        LogManager man = LogManager.getLogManager();
-        Logger l = null;
-        synchronized (man) {
-            // Try to find an existing logger with the specified name
-            l = man.getLogger(name);
-            // If no existing logger with the same name, create a new one
-            if (null == l) {
-                l = new Logger(name, resourceBundleName);
-                man.addLogger(l);
-                return l;
-            }
-        }
-        if (hasResourceName) {
-            updateResourceBundle(l, resourceBundleName);
+        if (resourceBundleName != null) {
+            this.resourceBundle = loadResourceBundle(resourceBundleName);
+            this.resourceBundleName = resourceBundleName;
         }
-        return l;
     }
 
     /**
      * Gets a named logger. The returned logger may already exist or may be
      * newly created. In the latter case, its level will be set to the
      * configured level according to the {@code LogManager}'s properties.
-     * 
+     *
      * @param name
      *            the name of the logger to get, cannot be {@code null}.
      * @return a named logger.
@@ -353,13 +300,13 @@
      *             If the specified resource bundle can not be loaded.
      */
     public static Logger getLogger(String name) {
-        return getLoggerWithRes(name, null, false);
+        return LogManager.getLogManager().getOrCreate(name, null);
     }
 
     /**
      * Gets a named logger associated with the supplied resource bundle. The
      * resource bundle will be used to localize logging messages.
-     * 
+     *
      * @param name
      *            the name of the logger to get, cannot be {@code null}.
      * @param resourceBundleName
@@ -373,13 +320,16 @@
      * @return a named logger.
      */
     public static Logger getLogger(String name, String resourceBundleName) {
-        return getLoggerWithRes(name, resourceBundleName, true);
+        Logger result = LogManager.getLogManager()
+                .getOrCreate(name, resourceBundleName);
+        result.initResourceBundle(resourceBundleName);
+        return result;
     }
 
     /**
      * Adds a handler to this logger. The {@code name} will be fed with log
      * records received by this logger.
-     * 
+     *
      * @param handler
      *            the handler object to add, cannot be {@code null}.
      * @throws SecurityException
@@ -387,7 +337,7 @@
      *             have the required permission.
      */
     public void addHandler(Handler handler) {
-        if (null == handler) {
+        if (handler == null) {
             // logging.A=The 'handler' parameter is null.
             throw new NullPointerException(Messages.getString("logging.A")); //$NON-NLS-1$
         }
@@ -395,70 +345,67 @@
         if (this.isNamed) {
             LogManager.getLogManager().checkAccess();
         }
-        initHandler();
-        synchronized (this) {
-            this.handlers.add(handler);
-        }
+        this.handlers.add(handler);
     }
 
-    /*
-     * Be cautious to avoid deadlock when using this method, it gets lock on manager
-     * at first, and then gets lock on this Logger, so any methods should not hold
-     * lock on this Logger when invoking this method.
-     */
-    private void initHandler() {
-        if (!handlerInited) {
-            synchronized (this) {
-                if (!handlerInited) {
-                    if (handlers == null) {
-                        handlers = new ArrayList<Handler>();
-                    }
-                    if (manager == null) {
-                        return;
-                    }
+    /**
+     * Set the logger's manager and initializes its configuration from the
+     * manager's properties.
+     */
+    @SuppressWarnings("nls")
+    void setManager(LogManager manager) {
+        String levelProperty = manager.getProperty(name + ".level");
+        if (levelProperty != null) {
+            try {
+                manager.setLevelRecursively(Logger.this, Level.parse(levelProperty));
+            } catch (IllegalArgumentException invalidLevel) {
+                invalidLevel.printStackTrace();
+            }
+        }
 
-                    String handlerStr = manager
-                            .getProperty("".equals(name) ? "handlers" : name + ".handlers"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-                    if (null == handlerStr) {
-                        return;
-                    }
-                    String[] strs = handlerStr.split(",|\\s"); //$NON-NLS-1$
-                    for (int i = 0; i < strs.length; i++) {
-                        String handlerName = strs[i];
-                        if (handlerName.equals("")) { //$NON-NLS-1$
-                            continue;
-                        }
-                        Handler handler = (Handler) LogManager
-                                .getInstanceByClass(handlerName);
-                        handlers.add(handler);
-                        String level = manager.getProperty(handlerName
-                                + ".level"); //$NON-NLS-1$
-                        if (null != level) {
-                            handler.setLevel(Level.parse(level));
-                        }
+        String handlersPropertyName = "".equals(name) ? "handlers" : name + ".handlers";
+        String handlersProperty = manager.getProperty(handlersPropertyName);
+        if (handlersProperty != null) {
+            for (String handlerName : handlersProperty.split(",|\\s")) {
+                if (handlerName.equals("")) {
+                    continue;
+                }
+
+                final Handler handler;
+                try {
+                    handler = (Handler) LogManager.getInstanceByClass(handlerName);
+                } catch (Exception invalidHandlerName) {
+                    invalidHandlerName.printStackTrace();
+                    continue;
+                }
+
+                try {
+                    String level = manager.getProperty(handlerName + ".level");
+                    if (level != null) {
+                        handler.setLevel(Level.parse(level));
                     }
-                    handlerInited = true;
+                } catch (Exception invalidLevel) {
+                    invalidLevel.printStackTrace();
                 }
+
+                handlers.add(handler);
             }
         }
     }
 
     /**
      * Gets all the handlers associated with this logger.
-     * 
+     *
      * @return an array of all the handlers associated with this logger.
      */
     public Handler[] getHandlers() {
-        initHandler();
-        synchronized (this) {
-            return handlers.toArray(new Handler[handlers.size()]);
-        }
+        return handlers.toArray(EMPTY_HANDLERS_ARRAY);
     }
 
     /**
      * Removes a handler from this logger. If the specified handler does not
      * exist then this method has no effect.
-     * 
+     *
      * @param handler
      *            the handler to be removed.
      * @throws SecurityException
@@ -470,18 +417,15 @@
         if (this.isNamed) {
             LogManager.getLogManager().checkAccess();
         }
-        if (null == handler) {
+        if (handler == null) {
             return;
         }
-        initHandler();
-        synchronized (this) {
-            this.handlers.remove(handler);
-        }
+        this.handlers.remove(handler);
     }
 
     /**
      * Gets the filter used by this logger.
-     * 
+     *
      * @return the filter used by this logger, may be {@code null}.
      */
     public Filter getFilter() {
@@ -490,7 +434,7 @@
 
     /**
      * Sets the filter used by this logger.
-     * 
+     *
      * @param newFilter
      *            the filter to set, may be {@code null}.
      * @throws SecurityException
@@ -508,7 +452,7 @@
     /**
      * Gets the logging level of this logger. A {@code null} level indicates
      * that this logger inherits its parent's level.
-     * 
+     *
      * @return the logging level of this logger.
      */
     public Level getLevel() {
@@ -518,7 +462,7 @@
     /**
      * Sets the logging level for this logger. A {@code null} level indicates
      * that this logger will inherit its parent's level.
-     * 
+     *
      * @param newLevel
      *            the logging level to set.
      * @throws SecurityException
@@ -527,19 +471,18 @@
      */
     public void setLevel(Level newLevel) {
         // Anonymous loggers can always set the level
+        LogManager logManager = LogManager.getLogManager();
         if (this.isNamed) {
-            LogManager.getLogManager().checkAccess();
-        }
-        synchronized (LogManager.getLogManager()) {
-            setLevelImpl(newLevel);
+            logManager.checkAccess();
         }
+        logManager.setLevelRecursively(this, newLevel);
     }
 
     /**
      * Gets the flag which indicates whether to use the handlers of this
      * logger's parent to publish incoming log records, potentially recursively
      * up the namespace.
-     * 
+     *
      * @return {@code true} if set to use parent's handlers, {@code false}
      *         otherwise.
      */
@@ -550,7 +493,7 @@
     /**
      * Sets the flag which indicates whether to use the handlers of this
      * logger's parent, potentially recursively up the namespace.
-     * 
+     *
      * @param notifyParentHandlers
      *            the new flag indicating whether to use the parent's handlers.
      * @throws SecurityException
@@ -568,7 +511,7 @@
     /**
      * Gets the nearest parent of this logger in the namespace, a {@code null}
      * value will be returned if called on the root logger.
-     * 
+     *
      * @return the parent of this logger in the namespace.
      */
     public Logger getParent() {
@@ -576,31 +519,9 @@
     }
 
     /**
-     * Sets the parent of this logger in the namespace. This method should
-     * usually be used by the {@code LogManager} object only. This method does
-     * not check security.
-     * 
-     * @param newParent
-     *            the parent logger to set.
-     */
-    void internalSetParent(Logger newParent) {
-        // All hierarchy related modifications should get LogManager lock at
-        // first
-        synchronized (LogManager.getLogManager()) {
-            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);
-        }
-    }
-
-    /**
      * Sets the parent of this logger in the namespace. This method should be
      * used by the {@code LogManager} object only.
-     * 
+     *
      * @param parent
      *            the parent logger to set.
      * @throws SecurityException
@@ -608,26 +529,20 @@
      *             have the required permission.
      */
     public void setParent(Logger parent) {
-        if (null == parent) {
+        if (parent == null) {
             // logging.B=The 'parent' parameter is null.
             throw new NullPointerException(Messages.getString("logging.B")); //$NON-NLS-1$
         }
-        // even anonymous loggers are checked
-        LogManager.getLogManager().checkAccess();
-        internalSetParent(parent);
-    }
 
-    final void addChild(Logger logger) {
-        childs.add(logger);
-    }
-
-    final void removeChild(Logger child) {
-        childs.remove(child);
+        // even anonymous loggers are checked
+        LogManager logManager = LogManager.getLogManager();
+        logManager.checkAccess();
+        logManager.setParent(this, parent);
     }
 
     /**
      * Gets the name of this logger, {@code null} for anonymous loggers.
-     * 
+     *
      * @return the name of this logger.
      */
     public String getName() {
@@ -638,22 +553,22 @@
      * Gets the loaded resource bundle used by this logger to localize logging
      * messages. If the value is {@code null}, the parent's resource bundle will be
      * inherited.
-     * 
+     *
      * @return the loaded resource bundle used by this logger.
      */
     public ResourceBundle getResourceBundle() {
-        return this.resBundle;
+        return this.resourceBundle;
     }
 
     /**
      * Gets the name of the loaded resource bundle used by this logger to
      * localize logging messages. If the value is {@code null}, the parent's resource
      * bundle name will be inherited.
-     * 
+     *
      * @return the name of the loaded resource bundle used by this logger.
      */
     public String getResourceBundleName() {
-        return this.resBundleName;
+        return this.resourceBundleName;
     }
 
     /**
@@ -675,7 +590,7 @@
      * Determines whether this logger will actually log messages of the
      * specified level. The effective level used to do the determination may be
      * inherited from its parent. The default level is {@code Level.INFO}.
-     * 
+     *
      * @param l
      *            the level to check.
      * @return {@code true} if this logger will actually log this level,
@@ -685,28 +600,19 @@
         return internalIsLoggable(l);
     }
 
-    /*
+    /**
      * Sets the resource bundle and its name for a supplied LogRecord object.
      * This method first tries to use this logger's resource bundle if any,
      * otherwise try to inherit from this logger's parent, recursively up the
-     * namespace. Synchronize to ensure the consistency between resource bundle
-     * and its name.
+     * namespace.
      */
     private void setResourceBundle(LogRecord record) {
-        if (null != this.resBundleName) {
-            record.setResourceBundle(this.resBundle);
-            record.setResourceBundleName(this.resBundleName);
-        } else {
-            Logger anyParent = this.parent;
-            // no need to synchronize here, because if resBundleName
-            // is not null, there is no chance to modify it
-            while (null != anyParent) {
-                if (null != anyParent.resBundleName) {
-                    record.setResourceBundle(anyParent.resBundle);
-                    record.setResourceBundleName(anyParent.resBundleName);
-                    return;
-                }
-                anyParent = anyParent.parent;
+        for (Logger p = this; p != null; p = p.parent) {
+            String resourceBundleName = p.resourceBundleName;
+            if (resourceBundleName != null) {
+                record.setResourceBundle(p.resourceBundle);
+                record.setResourceBundleName(resourceBundleName);
+                return;
             }
         }
     }
@@ -715,21 +621,23 @@
      * Logs a message indicating that a method has been entered. A log record
      * with log level {@code Level.FINER}, log message "ENTRY", the specified
      * source class name and source method name is submitted for logging.
-     * 
+     *
      * @param sourceClass
      *            the calling class name.
      * @param sourceMethod
      *            the method name.
      */
     public void entering(String sourceClass, String sourceMethod) {
-        if (internalIsLoggable(Level.FINER)) {
-            LogRecord record = new LogRecord(Level.FINER, "ENTRY"); //$NON-NLS-1$
-            record.setLoggerName(this.name);
-            record.setSourceClassName(sourceClass);
-            record.setSourceMethodName(sourceMethod);
-            setResourceBundle(record);
-            log(record);
+        if (!internalIsLoggable(Level.FINER)) {
+            return;
         }
+
+        LogRecord record = new LogRecord(Level.FINER, "ENTRY"); //$NON-NLS-1$
+        record.setLoggerName(this.name);
+        record.setSourceClassName(sourceClass);
+        record.setSourceMethodName(sourceMethod);
+        setResourceBundle(record);
+        log(record);
     }
 
     /**
@@ -737,7 +645,7 @@
      * with log level {@code Level.FINER}, log message "ENTRY", the specified
      * source class name, source method name and one parameter is submitted for
      * logging.
-     * 
+     *
      * @param sourceClass
      *            the source class name.
      * @param sourceMethod
@@ -746,15 +654,17 @@
      *            the parameter for the method call.
      */
     public void entering(String sourceClass, String sourceMethod, Object param) {
-        if (internalIsLoggable(Level.FINER)) {
-            LogRecord record = new LogRecord(Level.FINER, "ENTRY" + " {0}"); //$NON-NLS-1$ //$NON-NLS-2$
-            record.setLoggerName(this.name);
-            record.setSourceClassName(sourceClass);
-            record.setSourceMethodName(sourceMethod);
-            record.setParameters(new Object[] { param });
-            setResourceBundle(record);
-            log(record);
+        if (!internalIsLoggable(Level.FINER)) {
+            return;
         }
+
+        LogRecord record = new LogRecord(Level.FINER, "ENTRY" + " {0}"); //$NON-NLS-1$ //$NON-NLS-2$
+        record.setLoggerName(this.name);
+        record.setSourceClassName(sourceClass);
+        record.setSourceMethodName(sourceMethod);
+        record.setParameters(new Object[] { param });
+        setResourceBundle(record);
+        log(record);
     }
 
     /**
@@ -762,7 +672,7 @@
      * with log level {@code Level.FINER}, log message "ENTRY", the specified
      * source class name, source method name and array of parameters is
      * submitted for logging.
-     * 
+     *
      * @param sourceClass
      *            the source class name.
      * @param sourceMethod
@@ -770,53 +680,58 @@
      * @param params
      *            an array of parameters for the method call.
      */
+    @SuppressWarnings("nls")
     public void entering(String sourceClass, String sourceMethod,
             Object[] params) {
-        if (internalIsLoggable(Level.FINER)) {
-            String msg = "ENTRY"; //$NON-NLS-1$
-            if (null != params) {
-                StringBuilder msgBuffer = new StringBuilder("ENTRY"); //$NON-NLS-1$
-                for (int i = 0; i < params.length; i++) {
-                    msgBuffer.append(" {" + i + "}"); //$NON-NLS-1$ //$NON-NLS-2$
-                }
-                msg = msgBuffer.toString();
+        if (!internalIsLoggable(Level.FINER)) {
+            return;
+        }
+
+        String msg = "ENTRY";
+        if (params != null) {
+            StringBuilder msgBuffer = new StringBuilder("ENTRY");
+            for (int i = 0; i < params.length; i++) {
+                msgBuffer.append(" {").append(i).append("}");
             }
-            LogRecord record = new LogRecord(Level.FINER, msg);
-            record.setLoggerName(this.name);
-            record.setSourceClassName(sourceClass);
-            record.setSourceMethodName(sourceMethod);
-            record.setParameters(params);
-            setResourceBundle(record);
-            log(record);
+            msg = msgBuffer.toString();
         }
+        LogRecord record = new LogRecord(Level.FINER, msg);
+        record.setLoggerName(this.name);
+        record.setSourceClassName(sourceClass);
+        record.setSourceMethodName(sourceMethod);
+        record.setParameters(params);
+        setResourceBundle(record);
+        log(record);
     }
 
     /**
      * Logs a message indicating that a method is exited. A log record with log
      * level {@code Level.FINER}, log message "RETURN", the specified source
      * class name and source method name is submitted for logging.
-     * 
+     *
      * @param sourceClass
      *            the calling class name.
      * @param sourceMethod
      *            the method name.
      */
     public void exiting(String sourceClass, String sourceMethod) {
-        if (internalIsLoggable(Level.FINER)) {
-            LogRecord record = new LogRecord(Level.FINER, "RETURN"); //$NON-NLS-1$
-            record.setLoggerName(this.name);
-            record.setSourceClassName(sourceClass);
-            record.setSourceMethodName(sourceMethod);
-            setResourceBundle(record);
-            log(record);
+        if (!internalIsLoggable(Level.FINER)) {
+            return;
         }
+
+        LogRecord record = new LogRecord(Level.FINER, "RETURN"); //$NON-NLS-1$
+        record.setLoggerName(this.name);
+        record.setSourceClassName(sourceClass);
+        record.setSourceMethodName(sourceMethod);
+        setResourceBundle(record);
+        log(record);
     }
 
     /**
      * Logs a message indicating that a method is exited. A log record with log
      * level {@code Level.FINER}, log message "RETURN", the specified source
      * class name, source method name and return value is submitted for logging.
-     * 
+     *
      * @param sourceClass
      *            the source class name.
      * @param sourceMethod
@@ -825,15 +740,17 @@
      *            the return value of the method call.
      */
     public void exiting(String sourceClass, String sourceMethod, Object result) {
-        if (internalIsLoggable(Level.FINER)) {
-            LogRecord record = new LogRecord(Level.FINER, "RETURN" + " {0}"); //$NON-NLS-1$ //$NON-NLS-2$
-            record.setLoggerName(this.name);
-            record.setSourceClassName(sourceClass);
-            record.setSourceMethodName(sourceMethod);
-            record.setParameters(new Object[] { result });
-            setResourceBundle(record);
-            log(record);
+        if (!internalIsLoggable(Level.FINER)) {
+            return;
         }
+
+        LogRecord record = new LogRecord(Level.FINER, "RETURN" + " {0}"); //$NON-NLS-1$ //$NON-NLS-2$
+        record.setLoggerName(this.name);
+        record.setSourceClassName(sourceClass);
+        record.setSourceMethodName(sourceMethod);
+        record.setParameters(new Object[] { result });
+        setResourceBundle(record);
+        log(record);
     }
 
     /**
@@ -841,7 +758,7 @@
      * log level {@code Level.FINER}, log message "THROW", the specified source
      * class name, source method name and the {@code Throwable} object is
      * submitted for logging.
-     * 
+     *
      * @param sourceClass
      *            the source class name.
      * @param sourceMethod
@@ -851,151 +768,120 @@
      */
     public void throwing(String sourceClass, String sourceMethod,
             Throwable thrown) {
-        if (internalIsLoggable(Level.FINER)) {
-            LogRecord record = new LogRecord(Level.FINER, "THROW"); //$NON-NLS-1$
-            record.setLoggerName(this.name);
-            record.setSourceClassName(sourceClass);
-            record.setSourceMethodName(sourceMethod);
-            record.setThrown(thrown);
-            setResourceBundle(record);
-            log(record);
+        if (!internalIsLoggable(Level.FINER)) {
+            return;
         }
+
+        LogRecord record = new LogRecord(Level.FINER, "THROW"); //$NON-NLS-1$
+        record.setLoggerName(this.name);
+        record.setSourceClassName(sourceClass);
+        record.setSourceMethodName(sourceMethod);
+        record.setThrown(thrown);
+        setResourceBundle(record);
+        log(record);
     }
 
     /**
      * Logs a message of level {@code Level.SEVERE}; the message is transmitted
      * to all subscribed handlers.
-     * 
+     *
      * @param msg
      *            the message to log.
      */
     public void severe(String msg) {
-        if (internalIsLoggable(Level.SEVERE)) {
-            LogRecord record = new LogRecord(Level.SEVERE, msg);
-            record.setLoggerName(this.name);
-            setResourceBundle(record);
-            log(record);
-        }
+        log(Level.SEVERE, msg);
     }
 
     /**
      * Logs a message of level {@code Level.WARNING}; the message is
      * transmitted to all subscribed handlers.
-     * 
+     *
      * @param msg
      *            the message to log.
      */
     public void warning(String msg) {
-        if (internalIsLoggable(Level.WARNING)) {
-            LogRecord record = new LogRecord(Level.WARNING, msg);
-            record.setLoggerName(this.name);
-            setResourceBundle(record);
-            log(record);
-        }
+        log(Level.WARNING, msg);
     }
 
     /**
      * Logs a message of level {@code Level.INFO}; the message is transmitted
      * to all subscribed handlers.
-     * 
+     *
      * @param msg
      *            the message to log.
      */
     public void info(String msg) {
-        if (internalIsLoggable(Level.INFO)) {
-            LogRecord record = new LogRecord(Level.INFO, msg);
-            record.setLoggerName(this.name);
-            setResourceBundle(record);
-            log(record);
-        }
+        log(Level.INFO, msg);
     }
 
     /**
      * Logs a message of level {@code Level.CONFIG}; the message is transmitted
      * to all subscribed handlers.
-     * 
+     *
      * @param msg
      *            the message to log.
      */
     public void config(String msg) {
-        if (internalIsLoggable(Level.CONFIG)) {
-            LogRecord record = new LogRecord(Level.CONFIG, msg);
-            record.setLoggerName(this.name);
-            setResourceBundle(record);
-            log(record);
-        }
+        log(Level.CONFIG, msg);
     }
 
     /**
      * Logs a message of level {@code Level.FINE}; the message is transmitted
      * to all subscribed handlers.
-     * 
+     *
      * @param msg
      *            the message to log.
      */
     public void fine(String msg) {
-        if (internalIsLoggable(Level.FINE)) {
-            LogRecord record = new LogRecord(Level.FINE, msg);
-            record.setLoggerName(this.name);
-            setResourceBundle(record);
-            log(record);
-        }
+        log(Level.FINE, msg);
     }
 
     /**
      * Logs a message of level {@code Level.FINER}; the message is transmitted
      * to all subscribed handlers.
-     * 
+     *
      * @param msg
      *            the message to log.
      */
     public void finer(String msg) {
-        if (internalIsLoggable(Level.FINER)) {
-            LogRecord record = new LogRecord(Level.FINER, msg);
-            record.setLoggerName(this.name);
-            setResourceBundle(record);
-            log(record);
-        }
+        log(Level.FINER, msg);
     }
 
     /**
      * Logs a message of level {@code Level.FINEST}; the message is transmitted
      * to all subscribed handlers.
-     * 
+     *
      * @param msg
      *            the message to log.
      */
     public void finest(String msg) {
-        if (internalIsLoggable(Level.FINEST)) {
-            LogRecord record = new LogRecord(Level.FINEST, msg);
-            record.setLoggerName(this.name);
-            setResourceBundle(record);
-            log(record);
-        }
+        log(Level.FINEST, msg);
     }
 
     /**
      * Logs a message of the specified level. The message is transmitted to all
      * subscribed handlers.
-     * 
+     *
      * @param logLevel
      *            the level of the specified message.
      * @param msg
      *            the message to log.
      */
     public void log(Level logLevel, String msg) {
-        if (internalIsLoggable(logLevel)) {
-            LogRecord record = new LogRecord(logLevel, msg);
-            record.setLoggerName(this.name);
-            setResourceBundle(record);
-            log(record);
+        if (!internalIsLoggable(logLevel)) {
+            return;
         }
+
+        LogRecord record = new LogRecord(logLevel, msg);
+        record.setLoggerName(this.name);
+        setResourceBundle(record);
+        log(record);
     }
 
     /**
      * Logs a message of the specified level with the supplied parameter. The
      * message is then transmitted to all subscribed handlers.
-     * 
+     *
      * @param logLevel
      *            the level of the given message.
      * @param msg
@@ -1004,13 +890,15 @@
      *            the parameter associated with the event that is logged.
      */
     public void log(Level logLevel, String msg, Object param) {
-        if (internalIsLoggable(logLevel)) {
-            LogRecord record = new LogRecord(logLevel, msg);
-            record.setLoggerName(this.name);
-            record.setParameters(new Object[] { param });
-            setResourceBundle(record);
-            log(record);
+        if (!internalIsLoggable(logLevel)) {
+            return;
         }
+
+        LogRecord record = new LogRecord(logLevel, msg);
+        record.setLoggerName(this.name);
+        record.setParameters(new Object[] { param });
+        setResourceBundle(record);
+        log(record);
     }
 
     /**
@@ -1025,19 +913,21 @@
      *            the parameter array associated with the event that is logged.
      */
     public void log(Level logLevel, String msg, Object[] params) {
-        if (internalIsLoggable(logLevel)) {
-            LogRecord record = new LogRecord(logLevel, msg);
-            record.setLoggerName(this.name);
-            record.setParameters(params);
-            setResourceBundle(record);
-            log(record);
+        if (!internalIsLoggable(logLevel)) {
+            return;
         }
+
+        LogRecord record = new LogRecord(logLevel, msg);
+        record.setLoggerName(this.name);
+        record.setParameters(params);
+        setResourceBundle(record);
+        log(record);
     }
 
     /**
      * Logs a message of the specified level with the supplied {@code Throwable}
      * object. The message is then transmitted to all subscribed handlers.
-     * 
+     *
      * @param logLevel
      *            the level of the given message.
      * @param msg
@@ -1047,13 +937,15 @@
      *            logged.
      */
     public void log(Level logLevel, String msg, Throwable thrown) {
-        if (internalIsLoggable(logLevel)) {
-            LogRecord record = new LogRecord(logLevel, msg);
-            record.setLoggerName(this.name);
-            record.setThrown(thrown);
-            setResourceBundle(record);
-            log(record);
+        if (!internalIsLoggable(logLevel)) {
+            return;
         }
+
+        LogRecord record = new LogRecord(logLevel, msg);
+        record.setLoggerName(this.name);
+        record.setThrown(thrown);
+        setResourceBundle(record);
+        log(record);
     }
 
     /**
@@ -1067,43 +959,45 @@
      * logging action, subclasses of this class can override this method to
      * catch all logging activities.
      * </p>
-     * 
+     *
      * @param record
      *            the log record to be logged.
      */
     public void log(LogRecord record) {
-        if (internalIsLoggable(record.getLevel())) {
-            // apply the filter if any
-            Filter f = filter;
-            if (null != f && !f.isLoggable(record)) {
-                return;
-            }
-            initHandler();
-            /*
-             * call the handlers of this logger, throw any exception that occurs
-             */
-            Handler[] allHandlers = getHandlers();
-            for (Handler element : allHandlers) {
+        if (!internalIsLoggable(record.getLevel())) {
+            return;
+        }
+
+        // apply the filter if any
+        Filter f = filter;
+        if (f != null && !f.isLoggable(record)) {
+            return;
+        }
+
+        /*
+         * call the handlers of this logger, throw any exception that occurs
+         */
+        Handler[] allHandlers = getHandlers();
+        for (Handler element : allHandlers) {
+            element.publish(record);
+        }
+        // call the parent's handlers if set useParentHandlers
+        Logger temp = this;
+        Logger theParent = temp.parent;
+        while (theParent != null && temp.getUseParentHandlers()) {
+            Handler[] ha = theParent.getHandlers();
+            for (Handler element : ha) {
                 element.publish(record);
             }
-            // call the parent's handlers if set useParentHandlers
-            Logger temp = this;
-            Logger theParent = temp.parent;
-            while (theParent != null && temp.getUseParentHandlers()) {
-                Handler[] ha = theParent.getHandlers();
-                for (Handler element : ha) {
-                    element.publish(record);
-                }
-                temp = theParent;
-                theParent = temp.parent;
-            }
+            temp = theParent;
+            theParent = temp.parent;
         }
     }
 
     /**
      * Logs a message of the given level with the specified source class name
      * and source method name.
-     * 
+     *
      * @param logLevel
      *            the level of the given message.
      * @param sourceClass
@@ -1115,20 +1009,22 @@
      */
     public void logp(Level logLevel, String sourceClass, String sourceMethod,
             String msg) {
-        if (internalIsLoggable(logLevel)) {
-            LogRecord record = new LogRecord(logLevel, msg);
-            record.setLoggerName(this.name);
-            record.setSourceClassName(sourceClass);
-            record.setSourceMethodName(sourceMethod);
-            setResourceBundle(record);
-            log(record);
+        if (!internalIsLoggable(logLevel)) {
+            return;
         }
+
+        LogRecord record = new LogRecord(logLevel, msg);
+        record.setLoggerName(this.name);
+        record.setSourceClassName(sourceClass);
+        record.setSourceMethodName(sourceMethod);
+        setResourceBundle(record);
+        log(record);
     }
 
     /**
      * Logs a message of the given level with the specified source class name,
      * source method name and parameter.
-     * 
+     *
      * @param logLevel
      *            the level of the given message
      * @param sourceClass
@@ -1142,21 +1038,23 @@
      */
     public void logp(Level logLevel, String sourceClass, String sourceMethod,
             String msg, Object param) {
-        if (internalIsLoggable(logLevel)) {
-            LogRecord record = new LogRecord(logLevel, msg);
-            record.setLoggerName(this.name);
-            record.setSourceClassName(sourceClass);
-            record.setSourceMethodName(sourceMethod);
-            record.setParameters(new Object[] { param });
-            setResourceBundle(record);
-            log(record);
+        if (!internalIsLoggable(logLevel)) {
+            return;
         }
+
+        LogRecord record = new LogRecord(logLevel, msg);
+        record.setLoggerName(this.name);
+        record.setSourceClassName(sourceClass);
+        record.setSourceMethodName(sourceMethod);
+        record.setParameters(new Object[] { param });
+        setResourceBundle(record);
+        log(record);
     }
 
     /**
      * Logs a message of the given level with the specified source class name,
      * source method name and parameter array.
-     * 
+     *
      * @param logLevel
      *            the level of the given message.
      * @param sourceClass
@@ -1170,21 +1068,23 @@
      */
     public void logp(Level logLevel, String sourceClass, String sourceMethod,
             String msg, Object[] params) {
-        if (internalIsLoggable(logLevel)) {
-            LogRecord record = new LogRecord(logLevel, msg);
-            record.setLoggerName(this.name);
-            record.setSourceClassName(sourceClass);
-            record.setSourceMethodName(sourceMethod);
-            record.setParameters(params);
-            setResourceBundle(record);
-            log(record);
+        if (!internalIsLoggable(logLevel)) {
+            return;
         }
+
+        LogRecord record = new LogRecord(logLevel, msg);
+        record.setLoggerName(this.name);
+        record.setSourceClassName(sourceClass);
+        record.setSourceMethodName(sourceMethod);
+        record.setParameters(params);
+        setResourceBundle(record);
+        log(record);
     }
 
     /**
      * Logs a message of the given level with the specified source class name,
      * source method name and {@code Throwable} object.
-     * 
+     *
      * @param logLevel
      *            the level of the given message.
      * @param sourceClass
@@ -1198,15 +1098,17 @@
      */
     public void logp(Level logLevel, String sourceClass, String sourceMethod,
             String msg, Throwable thrown) {
-        if (internalIsLoggable(logLevel)) {
-            LogRecord record = new LogRecord(logLevel, msg);
-            record.setLoggerName(this.name);
-            record.setSourceClassName(sourceClass);
-            record.setSourceMethodName(sourceMethod);
-            record.setThrown(thrown);
-            setResourceBundle(record);
-            log(record);
+        if (!internalIsLoggable(logLevel)) {
+            return;
         }
+
+        LogRecord record = new LogRecord(logLevel, msg);
+        record.setLoggerName(this.name);
+        record.setSourceClassName(sourceClass);
+        record.setSourceMethodName(sourceMethod);
+        record.setThrown(thrown);
+        setResourceBundle(record);
+        log(record);
     }
 
     /**
@@ -1214,7 +1116,7 @@
      * and source method name, using the given resource bundle to localize the
      * message. If {@code bundleName} is null, the empty string or not valid then
      * the message is not localized.
-     * 
+     *
      * @param logLevel
      *            the level of the given message.
      * @param sourceClass
@@ -1228,21 +1130,23 @@
      */
     public void logrb(Level logLevel, String sourceClass, String sourceMethod,
             String bundleName, String msg) {
-        if (internalIsLoggable(logLevel)) {
-            LogRecord record = new LogRecord(logLevel, msg);
-            if (null != bundleName) {
-                try {
-                    record.setResourceBundle(loadResourceBundle(bundleName));
-                } catch (MissingResourceException e) {
-                    // ignore
-                }
-                record.setResourceBundleName(bundleName);
+        if (!internalIsLoggable(logLevel)) {
+            return;
+        }
+
+        LogRecord record = new LogRecord(logLevel, msg);
+        if (bundleName != null) {
+            try {
+                record.setResourceBundle(loadResourceBundle(bundleName));
+            } catch (MissingResourceException e) {
+                // ignore
             }
-            record.setLoggerName(this.name);
-            record.setSourceClassName(sourceClass);
-            record.setSourceMethodName(sourceMethod);
-            log(record);
+            record.setResourceBundleName(bundleName);
         }
+        record.setLoggerName(this.name);
+        record.setSourceClassName(sourceClass);
+        record.setSourceMethodName(sourceMethod);
+        log(record);
     }
 
     /**
@@ -1266,22 +1170,24 @@
      */
     public void logrb(Level logLevel, String sourceClass, String sourceMethod,
             String bundleName, String msg, Object param) {
-        if (internalIsLoggable(logLevel)) {
-            LogRecord record = new LogRecord(logLevel, msg);
-            if (null != bundleName) {
-                try {
-                    record.setResourceBundle(loadResourceBundle(bundleName));
-                } catch (MissingResourceException e) {
-                    // ignore
-                }
-                record.setResourceBundleName(bundleName);
+        if (!internalIsLoggable(logLevel)) {
+            return;
+        }
+
+        LogRecord record = new LogRecord(logLevel, msg);
+        if (bundleName != null) {
+            try {
+                record.setResourceBundle(loadResourceBundle(bundleName));
+            } catch (MissingResourceException e) {
+                // ignore
             }
-            record.setLoggerName(this.name);
-            record.setSourceClassName(sourceClass);
-            record.setSourceMethodName(sourceMethod);
-            record.setParameters(new Object[] { param });
-            log(record);
+            record.setResourceBundleName(bundleName);
         }
+        record.setLoggerName(this.name);
+        record.setSourceClassName(sourceClass);
+        record.setSourceMethodName(sourceMethod);
+        record.setParameters(new Object[] { param });
+        log(record);
     }
 
     /**
@@ -1289,7 +1195,7 @@
      * source method name and parameter array, using the given resource bundle
      * to localize the message. If {@code bundleName} is null, the empty string
      * or not valid then the message is not localized.
-     * 
+     *
      * @param logLevel
      *            the level of the given message.
      * @param sourceClass
@@ -1305,22 +1211,24 @@
      */
     public void logrb(Level logLevel, String sourceClass, String sourceMethod,
             String bundleName, String msg, Object[] params) {
-        if (internalIsLoggable(logLevel)) {
-            LogRecord record = new LogRecord(logLevel, msg);
-            if (null != bundleName) {
-                try {
-                    record.setResourceBundle(loadResourceBundle(bundleName));
-                } catch (MissingResourceException e) {
-                    // ignore
-                }
-                record.setResourceBundleName(bundleName);
+        if (!internalIsLoggable(logLevel)) {
+            return;
+        }
+
+        LogRecord record = new LogRecord(logLevel, msg);
+        if (bundleName != null) {
+            try {
+                record.setResourceBundle(loadResourceBundle(bundleName));
+            } catch (MissingResourceException e) {
+                // ignore
             }
-            record.setLoggerName(this.name);
-            record.setSourceClassName(sourceClass);
-            record.setSourceMethodName(sourceMethod);
-            record.setParameters(params);
-            log(record);
+            record.setResourceBundleName(bundleName);
         }
+        record.setLoggerName(this.name);
+        record.setSourceClassName(sourceClass);
+        record.setSourceMethodName(sourceMethod);
+        record.setParameters(params);
+        log(record);
     }
 
     /**
@@ -1328,7 +1236,7 @@
      * source method name and {@code Throwable} object, using the given resource
      * bundle to localize the message. If {@code bundleName} is null, the empty
      * string or not valid then the message is not localized.
-     * 
+     *
      * @param logLevel
      *            the level of the given message
      * @param sourceClass
@@ -1344,22 +1252,24 @@
      */
     public void logrb(Level logLevel, String sourceClass, String sourceMethod,
             String bundleName, String msg, Throwable thrown) {
-        if (internalIsLoggable(logLevel)) {
-            LogRecord record = new LogRecord(logLevel, msg);
-            if (null != bundleName) {
-                try {
-                    record.setResourceBundle(loadResourceBundle(bundleName));
-                } catch (MissingResourceException e) {
-                    // ignore
-                }
-                record.setResourceBundleName(bundleName);
+        if (!internalIsLoggable(logLevel)) {
+            return;
+        }
+
+        LogRecord record = new LogRecord(logLevel, msg);
+        if (bundleName != null) {
+            try {
+                record.setResourceBundle(loadResourceBundle(bundleName));
+            } catch (MissingResourceException e) {
+                // ignore
             }
-            record.setLoggerName(this.name);
-            record.setSourceClassName(sourceClass);
-            record.setSourceMethodName(sourceMethod);
-            record.setThrown(thrown);
-            log(record);
+            record.setResourceBundleName(bundleName);
         }
+        record.setLoggerName(this.name);
+        record.setSourceClassName(sourceClass);
+        record.setSourceMethodName(sourceMethod);
+        record.setThrown(thrown);
+        log(record);
     }
 
     /*
@@ -1371,42 +1281,17 @@
         }
     }
 
-    void setManager(LogManager manager) {
-        if (this.manager != manager) {
-            this.manager = manager;
-            handlerInited = false;
-        }
-        // init level here, but let handlers be for lazy loading
-        final String configedLevel = manager.getProperty(name + ".level"); //$NON-NLS-1$
-        if (null != configedLevel) {
-            try {
-                AccessController.doPrivileged(new PrivilegedAction<Object>() {
-                    public Object run() {
-                        setLevel(Level.parse(configedLevel));
-                        return null;
-                    }
-                });
-            } catch (IllegalArgumentException e) {
-                // ignore
-            }
-        }
-    }
-
-    synchronized void reset() {
+    void reset() {
         levelObjVal = null;
         levelIntVal = Level.INFO.intValue();
-        if (handlers != null) {
-            for (Handler element : handlers) {
-                // close all handlers, when unknown exceptions happen,
-                // ignore them and go on
-                try {
-                    element.close();
-                } catch (Exception e) {
-                    // Ignored.
+
+        for (Handler handler : handlers) {
+            try {
+                if (handlers.remove(handler)) {
+                    handler.close();
                 }
+            } catch (Exception ignored) {
             }
-            handlers.clear();
         }
-        handlerInited = false;
     }
 }

Modified: harmony/enhanced/classlib/trunk/modules/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LogManagerTest.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LogManagerTest.java?rev=833502&r1=833501&r2=833502&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LogManagerTest.java (original)
+++ harmony/enhanced/classlib/trunk/modules/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LogManagerTest.java Fri Nov  6 18:01:33 2009
@@ -599,6 +599,39 @@
 		stream.close();
 	}
 
+    public void testReadConfigurationUpdatesRootLoggersHandlers()
+            throws IOException {
+        Properties properties = new Properties();
+        LogManager.getLogManager().readConfiguration(
+                EnvironmentHelper.PropertiesToInputStream(properties));
+
+        Logger root = Logger.getLogger("");
+        assertEquals(0, root.getHandlers().length);
+
+        properties.put("handlers", "java.util.logging.ConsoleHandler");
+        LogManager.getLogManager().readConfiguration(
+                EnvironmentHelper.PropertiesToInputStream(properties));
+
+        assertEquals(1, root.getHandlers().length);
+    }
+
+    public void testReadConfigurationDoesNotUpdateOtherLoggers()
+            throws IOException {
+        Properties properties = new Properties();
+        LogManager.getLogManager().readConfiguration(
+                EnvironmentHelper.PropertiesToInputStream(properties));
+
+        Logger logger = Logger.getLogger("testReadConfigurationDoesNotUpdateOtherLoggers");
+        assertEquals(0, logger.getHandlers().length);
+
+        properties.put("testReadConfigurationDoesNotUpdateOtherLoggers.handlers",
+                "java.util.logging.ConsoleHandler");
+        LogManager.getLogManager().readConfiguration(
+                EnvironmentHelper.PropertiesToInputStream(properties));
+
+        assertEquals(0, logger.getHandlers().length);
+    }
+
 	public void testAddRemovePropertyChangeListener() throws Exception {
 		MockPropertyChangeListener listener1 = new MockPropertyChangeListener();
 		MockPropertyChangeListener listener2 = new MockPropertyChangeListener();



Mime
View raw message