Initial load
diff --git a/test/java/util/ResourceBundle/ReferencesTest.java b/test/java/util/ResourceBundle/ReferencesTest.java
new file mode 100644
index 0000000..57b3aff
--- /dev/null
+++ b/test/java/util/ResourceBundle/ReferencesTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc.  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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+/*
+ * @test
+ * @bug 4405807
+ * @run main/othervm -Xms10m ReferencesTest
+ * @summary Verify that references from ResourceBundle cache don't prevent
+ * class loader reclamation.
+ */
+
+import java.io.File;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * This test relies on the current behavior of the garbage collector and is
+ * therefore no clear indicator of whether the fix for 4405807 works.
+ * If the test fails, it might indicate a regression, or it might just mean
+ * that a less aggressive garbage collector is used.
+ */
+public class ReferencesTest {
+
+    private static final int CLASS_LOADER_COUNT = 20;
+
+    // These two parallel arrays have references to the same class loaders.
+    // The weakLoaders array lets us track whether class loaders are being
+    // reclaimed after the references in the loaders array are nulled out.
+    private static ClassLoader[] loaders = new ClassLoader[CLASS_LOADER_COUNT];
+    private static WeakReference[] weakLoaders = new WeakReference[CLASS_LOADER_COUNT];
+
+    public static void main(String[] args) throws Exception {
+
+        URL testDirectory = new File(System.getProperty("test.classes", ".")).toURL();
+
+        for (int i = 0; i < loaders.length; i++) {
+            URL[] urls = { testDirectory };
+            loaders[i] = new URLClassLoader(urls);
+            weakLoaders[i] = new WeakReference(loaders[i]);
+        }
+
+        // fill the ResourceBundle cache with entries for half the class loaders
+        loadBundles(0, CLASS_LOADER_COUNT / 2);
+
+        report("After loading resource bundles for first half of class loaders: ");
+
+        // release the first half of the class loaders
+        for (int i = 0; i < CLASS_LOADER_COUNT / 2; i++) {
+            loaders[i] = null;
+        }
+
+        System.gc();
+
+        report("After releasing first half of class loaders: ");
+
+        // fill the ResourceBundle cache with entries for second half the class loaders
+        loadBundles(CLASS_LOADER_COUNT / 2, CLASS_LOADER_COUNT);
+
+        report("After loading resource bundles for second half of class loaders: ");
+
+        // release the second half of the class loaders
+        for (int i = CLASS_LOADER_COUNT / 2; i < CLASS_LOADER_COUNT; i++) {
+            loaders[i] = null;
+        }
+
+        System.gc();
+
+        report("After releasing second half of class loaders: ");
+
+        // The garbage collector in Tiger actually has reclaimed all class
+        // loaders at this point, but in order not to become too dependent
+        // on the current behavior, we only require that the first half
+        // has been reclaimed.
+        if (countLoaders(0, CLASS_LOADER_COUNT / 2) > 0) {
+            throw new RuntimeException("Too many class loaders not reclaimed yet.");
+        }
+    }
+
+    private static void report(String when) throws Exception {
+        int first = countLoaders(0, CLASS_LOADER_COUNT / 2);
+        int second = countLoaders(CLASS_LOADER_COUNT / 2, CLASS_LOADER_COUNT);
+
+        Class clazz = ResourceBundle.class;
+        Field cacheList = clazz.getDeclaredField("cacheList");
+        cacheList.setAccessible(true);
+        int cacheSize = ((Map)cacheList.get(clazz)).size();
+
+        System.out.println(when);
+        System.out.println("    " + first + " loaders alive in first half");
+        System.out.println("    " + second + " loaders alive in second half");
+        System.out.println("    " + cacheSize + " entries in resource bundle cache");
+    }
+
+    private static void loadBundles(int start, int end) throws Exception {
+        for (int i = start; i < end; i++) {
+            // There's no resource bundle for NonExistantBundle - this
+            // let's us test the case where a resource bundle is not found,
+            // which in the past created a SoftReference on the value side
+            // of the cache.
+            try {
+                ResourceBundle.getBundle("NonExistantBundle", Locale.US, loaders[i]);
+            } catch (MissingResourceException e) {
+            }
+            // There's a base resource bundle for ReferencesTestBundle - the
+            // normal case.
+            ResourceBundle.getBundle("ReferencesTestBundle", Locale.US, loaders[i]);
+        }
+    }
+
+    private static int countLoaders(int start, int end) {
+        int count = 0;
+        for (int i = start; i < end; i++) {
+            if (weakLoaders[i].get() != null) {
+                count++;
+            }
+        }
+        return count;
+    }
+}