[kaffe] CVS kaffe (robilad): Resynced with GNU Classpath: ResourceBundle updated and remerged with Classpath
Kaffe CVS
cvs-commits at kaffe.org
Sat Nov 27 12:26:06 PST 2004
PatchSet 5496
Date: 2004/11/27 20:21:42
Author: robilad
Branch: HEAD
Tag: (none)
Log:
Resynced with GNU Classpath: ResourceBundle updated and remerged with Classpath
2004-11-27 Dalibor Topic <robilad at kaffe.org>
* libraries/javalib/java/util/ResourceBundle.java:
Resynced with GNU Classpath. Reverted Helmer's changes from
2004-07-11 as they break mauve tests for
java.util.logging.Logger.
2004-11-20 Tom Tromey <tromey at redhat.com>
* java/util/ResourceBundle.java (tryBundle): Use
Class.isAssignableFrom rather than catching ClassCastException.
2004-11-20 Bryce McKinlay <mckinlay at redhat.com>
* java/util/ResourceBundle.java (bundleCache): Renamed from
resourceBundleCache. Update comments.
(getObject): Don't catch MissingResourceException.
(getBundle(String)): Remove 'final'. Use system classloader if
getCallingClassLoader returned null.
(getBundle(String, Locale)): Likewise.
(BundleKey): New private class. HashMap key for bundle cache lookup.
(lookupKey): New. Singleton instance of BundleKey.
(nullEntry): New. Cache entry to represent failed lookups.
(getBundle(String, Locale, ClassLoader)): Re-written to use new
caching strategy, no-allocation lookup, and new tryBundle methods.
(tryBundle(String, ClassLoader)): New. Load a locale-qualified bundle
name using given classloader.
(tryBundle(String, Locale, ClassLoader, boolean): New. Qualify
baseName for given Locale and attempt to load bundle.
Members:
ChangeLog:1.3042->1.3043
libraries/javalib/java/util/ResourceBundle.java:1.22->1.23
Index: kaffe/ChangeLog
diff -u kaffe/ChangeLog:1.3042 kaffe/ChangeLog:1.3043
--- kaffe/ChangeLog:1.3042 Sat Nov 27 01:35:01 2004
+++ kaffe/ChangeLog Sat Nov 27 20:21:42 2004
@@ -1,6 +1,36 @@
2004-11-27 Dalibor Topic <robilad at kaffe.org>
* libraries/javalib/java/util/ResourceBundle.java:
+ Resynced with GNU Classpath. Reverted Helmer's changes from
+ 2004-07-11 as they break mauve tests for
+ java.util.logging.Logger.
+
+ 2004-11-20 Tom Tromey <tromey at redhat.com>
+
+ * java/util/ResourceBundle.java (tryBundle): Use
+ Class.isAssignableFrom rather than catching ClassCastException.
+
+ 2004-11-20 Bryce McKinlay <mckinlay at redhat.com>
+
+ * java/util/ResourceBundle.java (bundleCache): Renamed from
+ resourceBundleCache. Update comments.
+ (getObject): Don't catch MissingResourceException.
+ (getBundle(String)): Remove 'final'. Use system classloader if
+ getCallingClassLoader returned null.
+ (getBundle(String, Locale)): Likewise.
+ (BundleKey): New private class. HashMap key for bundle cache lookup.
+ (lookupKey): New. Singleton instance of BundleKey.
+ (nullEntry): New. Cache entry to represent failed lookups.
+ (getBundle(String, Locale, ClassLoader)): Re-written to use new
+ caching strategy, no-allocation lookup, and new tryBundle methods.
+ (tryBundle(String, ClassLoader)): New. Load a locale-qualified bundle
+ name using given classloader.
+ (tryBundle(String, Locale, ClassLoader, boolean): New. Qualify
+ baseName for given Locale and attempt to load bundle.
+
+2004-11-27 Dalibor Topic <robilad at kaffe.org>
+
+ * libraries/javalib/java/util/ResourceBundle.java:
Reindented to match GNU Classpath's version more closely.
2004-11-26 Dalibor Topic <robilad at kaffe.org>
Index: kaffe/libraries/javalib/java/util/ResourceBundle.java
diff -u kaffe/libraries/javalib/java/util/ResourceBundle.java:1.22 kaffe/libraries/javalib/java/util/ResourceBundle.java:1.23
--- kaffe/libraries/javalib/java/util/ResourceBundle.java:1.22 Sat Nov 27 01:35:05 2004
+++ kaffe/libraries/javalib/java/util/ResourceBundle.java Sat Nov 27 20:21:45 2004
@@ -104,14 +104,53 @@
* <code>getBundle</code>.
*/
private Locale locale;
-
+
+ /**
+ * We override SecurityManager in order to access getClassContext().
+ */
+ private static final class Security extends SecurityManager
+ {
+ /**
+ * Avoid accessor method of private constructor.
+ */
+ Security()
+ {
+ }
+
+ /**
+ * Return the ClassLoader of the class which called into this
+ * ResourceBundle, or null if it cannot be determined.
+ */
+ ClassLoader getCallingClassLoader()
+ {
+ Class[] stack = getClassContext();
+ for (int i = 0; i < stack.length; i++)
+ {
+ if (stack[i] != Security.class && stack[i] != ResourceBundle.class)
+ return stack[i].getClassLoader();
+ }
+
+ return null;
+ }
+ }
+
+ /** A security context for grabbing the correct class loader. */
+ private static final Security security
+ = (Security) AccessController.doPrivileged(new PrivilegedAction()
+ {
+ // This will always work since java.util classes have (all) system
+ // permissions.
+ public Object run()
+ {
+ return new Security();
+ }
+ }
+ );
+
/**
- * The resource bundle cache. This is a two-level hash map: The key
- * is the class loader, the value is a new HashMap. The key of this
- * second hash map is the localized name, the value is a soft
- * references to the resource bundle.
+ * The resource bundle cache.
*/
- private static Map resourceBundleCache;
+ private static Map bundleCache;
/**
* The last default Locale we saw. If this ever changes then we have to
@@ -173,18 +212,14 @@
public final Object getObject(String key)
{
for (ResourceBundle bundle = this; bundle != null; bundle = bundle.parent)
- try
- {
- Object o = bundle.handleGetObject(key);
- if (o != null)
- return o;
- }
- catch (MissingResourceException ex)
- {
- }
-
+ {
+ Object o = bundle.handleGetObject(key);
+ if (o != null)
+ return o;
+ }
+
throw new MissingResourceException("Key not found", getClass().getName(),
- key);
+ key);
}
/**
@@ -221,10 +256,12 @@
* @throws MissingResourceException if the resource bundle can't be found
* @throws NullPointerException if baseName is null
*/
- public static final ResourceBundle getBundle(String baseName)
+ public static ResourceBundle getBundle(String baseName)
{
- return getBundle(baseName, Locale.getDefault(),
- kaffe.lang.ThreadStack.getCallersClassLoader(true));
+ ClassLoader cl = security.getCallingClassLoader();
+ if (cl == null)
+ cl = ClassLoader.getSystemClassLoader();
+ return getBundle(baseName, Locale.getDefault(), cl);
}
/**
@@ -239,11 +276,62 @@
* @throws MissingResourceException if the resource bundle can't be found
* @throws NullPointerException if baseName or locale is null
*/
- public static final ResourceBundle getBundle(String baseName,
- Locale locale)
+ public static ResourceBundle getBundle(String baseName, Locale locale)
{
- return getBundle(baseName, locale, kaffe.lang.ThreadStack.getCallersClassLoader(true));
+ ClassLoader cl = security.getCallingClassLoader();
+ if (cl == null)
+ cl = ClassLoader.getSystemClassLoader();
+ return getBundle(baseName, locale, cl);
+ }
+
+ /** Cache key for the ResourceBundle cache. Resource bundles are keyed
+ by the combination of bundle name, locale, and class loader. */
+ private static class BundleKey
+ {
+ String baseName;
+ Locale locale;
+ ClassLoader classLoader;
+ int hashcode;
+
+ BundleKey() {}
+
+ BundleKey(String s, Locale l, ClassLoader cl)
+ {
+ set(s, l, cl);
+ }
+
+ void set(String s, Locale l, ClassLoader cl)
+ {
+ baseName = s;
+ locale = l;
+ classLoader = cl;
+ hashcode = baseName.hashCode() ^ locale.hashCode() ^
+ classLoader.hashCode();
+ }
+
+ public int hashCode()
+ {
+ return hashcode;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (! (o instanceof BundleKey))
+ return false;
+ BundleKey key = (BundleKey) o;
+ return hashcode == key.hashcode &&
+ baseName.equals(key.baseName) &&
+ locale.equals(key.locale) &&
+ classLoader.equals(key.classLoader);
+ }
}
+
+ /** A cache lookup key. This avoids having to a new one for every
+ * getBundle() call. */
+ private static BundleKey lookupKey = new BundleKey();
+
+ /** Singleton cache entry to represent previous failed lookups. */
+ private static Object nullEntry = new Object();
/**
* Get the appropriate ResourceBundle for the given locale. The following
@@ -307,7 +395,7 @@
* <li>Locale("es", "ES"): result MyResources_es_ES.class, parent
* MyResources.class</li>
* </ul>
- *
+ *
* <p>The file MyResources_fr_CH.properties is never used because it is hidden
* by MyResources_fr_CH.class.</p>
*
@@ -321,81 +409,60 @@
*/
// This method is synchronized so that the cache is properly
// handled.
- public static final synchronized ResourceBundle getBundle
+ public static synchronized ResourceBundle getBundle
(String baseName, Locale locale, ClassLoader classLoader)
{
- // This implementation searches the bundle in the reverse direction
- // and builds the parent chain on the fly.
+ // If the default locale changed since the last time we were called,
+ // all cache entries are invalidated.
Locale defaultLocale = Locale.getDefault();
if (defaultLocale != lastDefaultLocale)
{
- resourceBundleCache = new HashMap();
- lastDefaultLocale = defaultLocale;
+ bundleCache = new HashMap();
+ lastDefaultLocale = defaultLocale;
}
- HashMap cache = (HashMap) resourceBundleCache.get(classLoader);
- StringBuffer sb = new StringBuffer(60);
- sb.append(baseName).append('_').append(locale);
- String name = sb.toString();
- if (cache == null)
+ // This will throw NullPointerException if any arguments are null.
+ lookupKey.set(baseName, locale, classLoader);
+
+ Object obj = bundleCache.get(lookupKey);
+ ResourceBundle rb = null;
+
+ if (obj instanceof ResourceBundle)
{
- cache = new HashMap();
- resourceBundleCache.put(classLoader, cache);
+ return (ResourceBundle) obj;
}
- else if (cache.containsKey(name))
+ else if (obj == nullEntry)
{
- Reference ref = (Reference) cache.get(name);
- // If REF is null, that means that we added a `null' value to
- // the hash map. That means we failed to find the bundle
- // previously, and we cached that fact. The JDK does this, so
- // it must be ok.
- if (ref == null)
- throw new MissingResourceException("Bundle " + baseName
- + " not found",
- baseName, "");
- else
- {
- ResourceBundle rb = (ResourceBundle) ref.get();
- if (rb != null)
- {
- // RB should already have the right parent, except if
- // something very strange happened.
- return rb;
- }
- // If RB is null, then we previously found it but it was
- // collected. So we try again.
- }
+ // Lookup has failed previously. Fall through.
}
-
- // It is ok if this returns null. We aren't required to have the
- // base bundle.
- ResourceBundle baseBundle = tryBundle(baseName, emptyLocale,
- classLoader, null, cache);
-
- // Now use our locale, followed by the default locale. We only
- // need to try the default locale if our locale is different, and
- // if our locale failed to yield a result other than the base
- // bundle.
- ResourceBundle bundle = tryLocalBundle(baseName, locale,
- classLoader, baseBundle, cache);
- if (bundle == baseBundle && !locale.equals(defaultLocale))
+ else
{
- bundle = tryLocalBundle(baseName, defaultLocale,
- classLoader, baseBundle, cache);
- // We need to record that the argument locale maps to the
- // bundle we just found. If we didn't find a bundle, record
- // that instead.
+ // First, look for a bundle for the specified locale. We don't want
+ // the base bundle this time.
+ boolean wantBase = locale.equals(defaultLocale);
+ ResourceBundle bundle = tryBundle(baseName, locale, classLoader,
+ wantBase);
+
+ // Try the default locale if neccessary.
+ if (bundle == null && !locale.equals(defaultLocale))
+ bundle = tryBundle(baseName, defaultLocale, classLoader, true);
+
+ BundleKey key = new BundleKey(baseName, locale, classLoader);
if (bundle == null)
- cache.put(name, null);
- else
- cache.put(name, new SoftReference(bundle));
+ {
+ // Cache the fact that this lookup has previously failed.
+ bundleCache.put(key, nullEntry);
+ }
+ else
+ {
+ // Cache the result and return it.
+ bundleCache.put(key, bundle);
+ return bundle;
+ }
}
- if (bundle == null)
- throw new MissingResourceException("Bundle " + baseName + " not found",
- baseName, "");
-
- return bundle;
+ throw new MissingResourceException("Bundle " + baseName + " not found",
+ baseName, "");
}
/**
@@ -424,42 +491,13 @@
* Tries to load a class or a property file with the specified name.
*
* @param localizedName the name
- * @param locale the locale, that must be used exactly
* @param classloader the classloader
- * @param bundle the backup (parent) bundle
* @return the resource bundle if it was loaded, otherwise the backup
*/
- private static ResourceBundle tryBundle(String localizedName, Locale locale,
- ClassLoader classloader,
- ResourceBundle bundle, HashMap cache)
+ private static ResourceBundle tryBundle(String localizedName,
+ ClassLoader classloader)
{
- // First look into the cache.
- if (cache.containsKey(localizedName))
- {
- Reference ref = (Reference) cache.get(localizedName);
- // If REF is null, that means that we added a `null' value to
- // the hash map. That means we failed to find the bundle
- // previously, and we cached that fact. The JDK does this, so
- // it must be ok.
- if (ref == null)
- return null;
- else
- {
- ResourceBundle rb = (ResourceBundle) ref.get();
- if (rb != null)
- {
- // RB should already have the right parent, except if
- // something very strange happened.
- return rb;
- }
- // If RB is null, then we previously found it but it was
- // collected. So we try again.
- }
- }
-
- // foundBundle holds exact matches for the localizedName resource
- // bundle, which may later be cached.
- ResourceBundle foundBundle = null;
+ ResourceBundle bundle = null;
try
{
Class rbClass;
@@ -467,98 +505,118 @@
rbClass = Class.forName(localizedName);
else
rbClass = classloader.loadClass(localizedName);
- foundBundle = (ResourceBundle) rbClass.newInstance();
- foundBundle.parent = bundle;
- foundBundle.locale = locale;
- }
- catch (Exception ex)
- {
- // ignore them all
- foundBundle = null;
- }
- if (foundBundle == null)
+ // Note that we do the check up front instead of catching
+ // ClassCastException. The reason for this is that some crazy
+ // programs (Eclipse) have classes that do not extend
+ // ResourceBundle but that have the same name as a property
+ // bundle; in fact Eclipse relies on ResourceBundle not
+ // instantiating these classes.
+ if (ResourceBundle.class.isAssignableFrom(rbClass))
+ bundle = (ResourceBundle) rbClass.newInstance();
+ }
+ catch (IllegalAccessException ex) {}
+ catch (InstantiationException ex) {}
+ catch (ClassNotFoundException ex) {}
+
+ if (bundle == null)
{
- try
- {
- InputStream is;
- final String resourceName
- = localizedName.replace('.', '/') + ".properties";
- if (classloader == null)
- is = ClassLoader.getSystemResourceAsStream(resourceName);
- else
- is = classloader.getResourceAsStream(resourceName);
- if (is != null)
- {
- foundBundle = new PropertyResourceBundle(is);
- foundBundle.parent = bundle;
- foundBundle.locale = locale;
- }
- }
- catch (IOException ex)
- {
- }
+ try
+ {
+ InputStream is;
+ String resourceName
+ = localizedName.replace('.', '/') + ".properties";
+ if (classloader == null)
+ is = ClassLoader.getSystemResourceAsStream(resourceName);
+ else
+ is = classloader.getResourceAsStream(resourceName);
+ if (is != null)
+ bundle = new PropertyResourceBundle(is);
+ }
+ catch (IOException ex)
+ {
+ MissingResourceException mre = new MissingResourceException
+ ("Failed to load bundle", localizedName, "");
+ mre.initCause(ex);
+ throw mre;
+ }
}
- // Put the result into the hash table. If we didn't find anything
- // here, we record our parent bundle. If we record `null' that means
- // nothing, not even the base, was found.
- if (foundBundle == null)
- foundBundle = bundle;
- if (foundBundle == null)
- cache.put(localizedName, null);
- else
- cache.put(localizedName, new SoftReference(foundBundle));
- return foundBundle;
+ return bundle;
}
/**
* Tries to load a the bundle for a given locale, also loads the backup
* locales with the same language.
*
- * @param name the name
+ * @param baseName the raw bundle name, without locale qualifiers
* @param locale the locale
* @param classloader the classloader
* @param bundle the backup (parent) bundle
+ * @param wantBase whether a resource bundle made only from the base name
+ * (with no locale information attached) should be returned.
* @return the resource bundle if it was loaded, otherwise the backup
*/
- private static ResourceBundle tryLocalBundle(String baseName, Locale locale,
- ClassLoader classloader,
- ResourceBundle bundle,
- HashMap cache)
- {
- final String language = locale.getLanguage();
- final String country = locale.getCountry();
- final String variant = locale.getVariant();
+ private static ResourceBundle tryBundle(String baseName, Locale locale,
+ ClassLoader classLoader,
+ boolean wantBase)
+ {
+ String language = locale.getLanguage();
+ String country = locale.getCountry();
+ String variant = locale.getVariant();
+
+ int baseLen = baseName.length();
+
+ // Build up a StringBuffer containing the complete bundle name, fully
+ // qualified by locale.
+ StringBuffer sb = new StringBuffer(baseLen + variant.length() + 7);
- StringBuffer sb = new StringBuffer(60);
sb.append(baseName);
- sb.append('_');
-
+
if (language.length() > 0)
{
- sb.append(language);
- bundle = tryBundle(sb.toString(), new Locale(language),
- classloader, bundle, cache);
- }
- // If LANGUAGE was empty, we still need to try the other
- // components, and the `_' is required.
- sb.append('_');
-
- if (country.length() > 0)
- {
- sb.append(country);
- bundle = tryBundle(sb.toString(), new Locale(language, country),
- classloader, bundle, cache);
+ sb.append('_');
+ sb.append(language);
+
+ if (country.length() > 0)
+ {
+ sb.append('_');
+ sb.append(country);
+
+ if (variant.length() > 0)
+ {
+ sb.append('_');
+ sb.append(variant);
+ }
+ }
+ }
+
+ // Now try to load bundles, starting with the most specialized name.
+ // Build up the parent chain as we go.
+ String bundleName = sb.toString();
+ ResourceBundle first = null; // The most specialized bundle.
+ ResourceBundle last = null; // The least specialized bundle.
+
+ while (true)
+ {
+ ResourceBundle foundBundle = tryBundle(bundleName, classLoader);
+ if (foundBundle != null)
+ {
+ if (first == null)
+ first = foundBundle;
+ if (last != null)
+ last.parent = foundBundle;
+ foundBundle.locale = locale;
+ last = foundBundle;
+ }
+ int idx = bundleName.lastIndexOf('_');
+ // Try the non-localized base name only if we already have a
+ // localized child bundle, or wantBase is true.
+ if (idx > baseLen || (idx == baseLen && (first != null || wantBase)))
+ bundleName = bundleName.substring(0, idx);
+ else
+ break;
}
- sb.append('_');
-
- if (variant.length() > 0)
- {
- sb.append(variant);
- bundle = tryBundle(sb.toString(), locale,
- classloader, bundle, cache);
- }
-
- return bundle;
+
+ return first;
}
}
More information about the kaffe
mailing list