changeset 8032:94335b6ffb32

8002070: Remove the stack search for a resource bundle for Logger to use Summary: The fragile, vulnerable, stack crawling has been eliminated from findResourceBundle(String) Reviewed-by: mchung, alanb
author jgish
date Wed, 13 Mar 2013 11:24:48 -0400
parents e33cbbe21419
children ef0c60b93a17
files src/share/classes/java/util/logging/Logger.java test/java/util/logging/LoggerResourceBundleRace.java
diffstat 2 files changed, 34 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/util/logging/Logger.java	Wed Mar 13 17:58:45 2013 +0000
+++ b/src/share/classes/java/util/logging/Logger.java	Wed Mar 13 11:24:48 2013 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,10 +26,13 @@
 
 package java.util.logging;
 
-import java.util.*;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
 import java.util.concurrent.CopyOnWriteArrayList;
-import java.security.*;
-import java.lang.ref.WeakReference;
 import java.util.function.Supplier;
 
 /**
@@ -104,7 +107,7 @@
  * unnecessary message construction. For example, if the developer wants to
  * log system health status for diagnosis, with the String-accepting version,
  * the code would look like:
- <code><pre>
+ <pre><code>
 
    class DiagnosisMessages {
      static String systemHealthStatus() {
@@ -114,26 +117,20 @@
    }
    ...
    logger.log(Level.FINER, DiagnosisMessages.systemHealthStatus());
- </pre></code>
+</code></pre>
  * With the above code, the health status is collected unnecessarily even when
  * the log level FINER is disabled. With the Supplier-accepting version as
  * below, the status will only be collected when the log level FINER is
  * enabled.
- <code><pre>
+ <pre><code>
 
    logger.log(Level.FINER, DiagnosisMessages::systemHealthStatus);
- </pre></code>
+</code></pre>
  * <p>
  * When mapping ResourceBundle names to ResourceBundles, the Logger
  * will first try to use the Thread's ContextClassLoader.  If that
- * is null it will try the SystemClassLoader instead.  As a temporary
- * transition feature in the initial implementation, if the Logger is
- * unable to locate a ResourceBundle from the ContextClassLoader or
- * SystemClassLoader the Logger will also search up the class stack
- * and use successive calling ClassLoaders to try to locate a ResourceBundle.
- * (This call stack search is to allow containers to transition to
- * using ContextClassLoaders and is likely to be removed in future
- * versions.)
+ * is null it will try the
+ * {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader} instead.
  * <p>
  * Formatting (including localization) is the responsibility of
  * the output Handler, which will typically call a Formatter.
@@ -1541,12 +1538,16 @@
         return useParentHandlers;
     }
 
-    // Private utility method to map a resource bundle name to an
-    // actual resource bundle, using a simple one-entry cache.
-    // Returns null for a null name.
-    // May also return null if we can't find the resource bundle and
-    // there is no suitable previous cached value.
-
+    /**
+     * Private utility method to map a resource bundle name to an
+     * actual resource bundle, using a simple one-entry cache.
+     * Returns null for a null name.
+     * May also return null if we can't find the resource bundle and
+     * there is no suitable previous cached value.
+     *
+     * @param name the ResourceBundle to locate
+     * @return ResourceBundle specified by name or null if not found
+     */
     private synchronized ResourceBundle findResourceBundle(String name) {
         // Return a null bundle for a null name.
         if (name == null) {
@@ -1556,13 +1557,13 @@
         Locale currentLocale = Locale.getDefault();
 
         // Normally we should hit on our simple one entry cache.
-        if (catalog != null && currentLocale == catalogLocale
-                                        && name == catalogName) {
+        if (catalog != null && currentLocale.equals(catalogLocale)
+                && name.equals(catalogName)) {
             return catalog;
         }
 
-        // Use the thread's context ClassLoader.  If there isn't one,
-        // use the SystemClassloader.
+        // Use the thread's context ClassLoader.  If there isn't one, use the
+        // {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader}.
         ClassLoader cl = Thread.currentThread().getContextClassLoader();
         if (cl == null) {
             cl = ClassLoader.getSystemClassLoader();
@@ -1573,45 +1574,8 @@
             catalogLocale = currentLocale;
             return catalog;
         } catch (MissingResourceException ex) {
-            // Woops.  We can't find the ResourceBundle in the default
-            // ClassLoader.  Drop through.
+            return null;
         }
-
-
-        // Fall back to searching up the call stack and trying each
-        // calling ClassLoader.
-        for (int ix = 0; ; ix++) {
-            Class clz = sun.reflect.Reflection.getCallerClass(ix);
-            if (clz == null) {
-                break;
-            }
-            ClassLoader cl2 = clz.getClassLoader();
-            if (cl2 == null) {
-                cl2 = ClassLoader.getSystemClassLoader();
-            }
-            if (cl == cl2) {
-                // We've already checked this classloader.
-                continue;
-            }
-            cl = cl2;
-            try {
-                catalog = ResourceBundle.getBundle(name, currentLocale, cl);
-                catalogName = name;
-                catalogLocale = currentLocale;
-                return catalog;
-            } catch (MissingResourceException ex) {
-                // Ok, this one didn't work either.
-                // Drop through, and try the next one.
-            }
-        }
-
-        if (name.equals(catalogName)) {
-            // Return the previous cached value for that name.
-            // This may be null.
-            return catalog;
-        }
-        // Sorry, we're out of luck.
-        return null;
     }
 
     // Private utility method to initialize our one entry
@@ -1638,8 +1602,7 @@
                 resourceBundleName + " != " + name);
         }
 
-        ResourceBundle rb = findResourceBundle(name);
-        if (rb == null) {
+        if (findResourceBundle(name) == null) {
             // We've failed to find an expected ResourceBundle.
             throw new MissingResourceException("Can't find " + name + " bundle", name, "");
         }
--- a/test/java/util/logging/LoggerResourceBundleRace.java	Wed Mar 13 17:58:45 2013 +0000
+++ b/test/java/util/logging/LoggerResourceBundleRace.java	Wed Mar 13 11:24:48 2013 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,13 +23,14 @@
 
 /*
  * @test
- * @bug     7045594
+ * @bug     7045594 8002070
  * @summary ResourceBundle setting race in Logger.getLogger(name, rbName)
  * @author  Daniel D. Daugherty
  * @build RacingThreadsTest LoggerResourceBundleRace
- * @run main LoggerResourceBundleRace
+ * @run main/othervm LoggerResourceBundleRace
+ *
+ * (In samevm mode, the bundle classes don't end up in the classpath.)
  */
-
 import java.util.ListResourceBundle;
 import java.util.MissingResourceException;
 import java.util.concurrent.atomic.AtomicInteger;