FileDocCategorySizeDatePackage
ResourceBundle.javaAPI DocAndroid 1.5 API19416Wed May 06 22:41:04 BST 2009java.util

ResourceBundle

public abstract class ResourceBundle extends Object
{@code ResourceBundle} is an abstract class which is the superclass of classes which provide {@code Locale}-specific resources. A bundle contains a number of named resources, where the names are {@code Strings}. A bundle may have a parent bundle, and when a resource is not found in a bundle, the parent bundle is searched for the resource. If the fallback mechanism reaches the base bundle and still can't find the resource it throws a {@code MissingResourceException}.
  • All bundles for the same group of resources share a common base bundle. This base bundle acts as the root and is the last fallback in case none of its children was able to respond to a request.
  • The first level contains changes between different languages. Only the differences between a language and the language of the base bundle need to be handled by a language-specific {@code ResourceBundle}.
  • The second level contains changes between different countries that use the same language. Only the differences between a country and the country of the language bundle need to be handled by a country-specific {@code ResourceBundle}.
  • The third level contains changes that don't have a geographic reason (e.g. changes that where made at some point in time like {@code PREEURO} where the currency of come countries changed. The country bundle would return the current currency (Euro) and the {@code PREEURO} variant bundle would return the old currency (e.g. DM for Germany).
Examples
  • BaseName (base bundle)
  • BaseName_de (german language bundle)
  • BaseName_fr (french language bundle)
  • BaseName_de_DE (bundle with Germany specific resources in german)
  • BaseName_de_CH (bundle with Switzerland specific resources in german)
  • BaseName_fr_CH (bundle with Switzerland specific resources in french)
  • BaseName_de_DE_PREEURO (bundle with Germany specific resources in german of the time before the Euro)
  • BaseName_fr_FR_PREEURO (bundle with France specific resources in french of the time before the Euro)
It's also possible to create variants for languages or countries. This can be done by just skipping the country or language abbreviation: BaseName_us__POSIX or BaseName__DE_PREEURO. But it's not allowed to circumvent both language and country: BaseName___VARIANT is illegal.
see
Properties
see
PropertyResourceBundle
see
ListResourceBundle
since
Android 1.0

Fields Summary
protected ResourceBundle
parent
The parent of this {@code ResourceBundle} that is used if this bundle doesn't include the requested resource.
private Locale
locale
private static final ResourceBundle
MISSING
private static final ResourceBundle
MISSINGBASE
private static final WeakHashMap
cache
private static Locale
defaultLocale
Constructors Summary
public ResourceBundle()
Constructs a new instance of this class.

since
Android 1.0

    // END android-added

                    
      
        /* empty */
    
Methods Summary
public static final java.util.ResourceBundlegetBundle(java.lang.String bundleName)
Finds the named resource bundle for the default {@code Locale} and the caller's {@code ClassLoader}.

param
bundleName the name of the {@code ResourceBundle}.
return
the requested {@code ResourceBundle}.
exception
MissingResourceException if the {@code ResourceBundle} cannot be found.
since
Android 1.0

        // BEGIN android-changed
        return getBundleImpl(bundleName, Locale.getDefault(), VMStack
                .getCallingClassLoader());
        // END android-changed
    
public static final java.util.ResourceBundlegetBundle(java.lang.String bundleName, java.util.Locale locale)
Finds the named {@code ResourceBundle} for the specified {@code Locale} and the caller {@code ClassLoader}.

param
bundleName the name of the {@code ResourceBundle}.
param
locale the {@code Locale}.
return
the requested resource bundle.
exception
MissingResourceException if the resource bundle cannot be found.
since
Android 1.0

        // BEGIN android-changed
        return getBundleImpl(bundleName, locale,
                VMStack.getCallingClassLoader());
        // END android-changed
    
public static java.util.ResourceBundlegetBundle(java.lang.String bundleName, java.util.Locale locale, java.lang.ClassLoader loader)
Finds the named resource bundle for the specified {@code Locale} and {@code ClassLoader}. The passed base name and {@code Locale} are used to create resource bundle names. The first name is created by concatenating the base name with the result of {@link Locale#toString()}. From this name all parent bundle names are derived. Then the same thing is done for the default {@code Locale}. This results in a list of possible bundle names. Example For the basename "BaseName", the {@code Locale} of the German part of Switzerland (de_CH) and the default {@code Locale} en_US the list would look something like this:
  1. BaseName_de_CH
  2. BaseName_de
  3. Basename_en_US
  4. Basename_en
  5. BaseName
This list also shows the order in which the bundles will be searched for a requested resource in the German part of Switzerland (de_CH). As a first step, this method tries to instantiate a {@code ResourceBundle} with the names provided. If such a class can be instantiated and initialized, it is returned and all the parent bundles are instantiated too. If no such class can be found this method tries to load a {@code .properties} file with the names by replacing dots in the base name with a slash and by appending "{@code .properties}" at the end of the string. If such a resource can be found by calling {@link ClassLoader#getResource(String)} it is used to initialize a {@link PropertyResourceBundle}. If this succeeds, it will also load the parents of this {@code ResourceBundle}. For compatibility with older code, the bundle name isn't required to be a fully qualified class name. It's also possible to directly pass the path to a properties file (without a file extension).

param
bundleName the name of the {@code ResourceBundle}.
param
locale the {@code Locale}.
param
loader the {@code ClassLoader} to use.
return
the requested {@code ResourceBundle}.
exception
MissingResourceException if the {@code ResourceBundle} cannot be found.
since
Android 1.0

        if (loader == null) {
            throw new NullPointerException();
        }
        // BEGIN android-changed
        return getBundleImpl(bundleName, locale, loader);
        // END android-changed
    
private static java.util.ResourceBundlegetBundleImpl(java.lang.String bundleName, java.util.Locale locale, java.lang.ClassLoader loader)

        if (bundleName != null) {
            ResourceBundle bundle;
            // BEGIN android-added
            if (!defaultLocale.equals(Locale.getDefault())) {
                cache.clear();
                defaultLocale = Locale.getDefault();
            }
            // END android-added
            if (!locale.equals(Locale.getDefault())) {
                String localeName = locale.toString();
                if (localeName.length() > 0) {
                    localeName = "_" + localeName; //$NON-NLS-1$
                }
                if ((bundle = handleGetBundle(bundleName, localeName, false,
                        loader)) != null) {
                    return bundle;
                }
            }
            String localeName = Locale.getDefault().toString();
            if (localeName.length() > 0) {
                localeName = "_" + localeName; //$NON-NLS-1$
            }
            if ((bundle = handleGetBundle(bundleName, localeName, true, loader)) != null) {
                return bundle;
            }
            throw new MissingResourceException(null, bundleName + '_" + locale,
                    ""); //$NON-NLS-1$
        }
        throw new NullPointerException();
    
public abstract java.util.EnumerationgetKeys()
Returns the names of the resources contained in this {@code ResourceBundle}.

return
an {@code Enumeration} of the resource names.
since
Android 1.0

public java.util.LocalegetLocale()
Gets the {@code Locale} of this {@code ResourceBundle}. In case a bundle was not found for the requested {@code Locale}, this will return the actual {@code Locale} of this resource bundle that was found after doing a fallback.

return
the {@code Locale} of this {@code ResourceBundle}.
since
Android 1.0

        return locale;
    
public final java.lang.ObjectgetObject(java.lang.String key)
Returns the named resource from this {@code ResourceBundle}. If the resource cannot be found in this bundle, it falls back to the parent bundle (if it's not null) by calling the {@link #handleGetObject} method. If the resource still can't be found it throws a {@code MissingResourceException}.

param
key the name of the resource.
return
the resource object.
exception
MissingResourceException if the resource is not found.
since
Android 1.0

        ResourceBundle last, theParent = this;
        do {
            Object result = theParent.handleGetObject(key);
            if (result != null) {
                return result;
            }
            last = theParent;
            theParent = theParent.parent;
        } while (theParent != null);
        throw new MissingResourceException(null, last.getClass().getName(), key);
    
public final java.lang.StringgetString(java.lang.String key)
Returns the named string resource from this {@code ResourceBundle}.

param
key the name of the resource.
return
the resource string.
exception
MissingResourceException if the resource is not found.
exception
ClassCastException if the resource found is not a string.
see
#getObject(String)
since
Android 1.0

        return (String) getObject(key);
    
public final java.lang.String[]getStringArray(java.lang.String key)
Returns the named resource from this {@code ResourceBundle}.

param
key the name of the resource.
return
the resource string array.
exception
MissingResourceException if the resource is not found.
exception
ClassCastException if the resource found is not an array of strings.
see
#getObject(String)
since
Android 1.0

        return (String[]) getObject(key);
    
private static java.util.ResourceBundlehandleGetBundle(java.lang.String base, java.lang.String locale, boolean loadBase, java.lang.ClassLoader loader)

        ResourceBundle bundle = null;
        String bundleName = base + locale;
        Object cacheKey = loader != null ? (Object) loader : (Object) "null"; //$NON-NLS-1$
        Hashtable<String, ResourceBundle> loaderCache;
        synchronized (cache) {
            loaderCache = cache.get(cacheKey);
            if (loaderCache == null) {
                loaderCache = new Hashtable<String, ResourceBundle>(13);
                cache.put(cacheKey, loaderCache);
            }
        }
        ResourceBundle result = loaderCache.get(bundleName);
        if (result != null) {
            if (result == MISSINGBASE) {
                return null;
            }
            if (result == MISSING) {
                if (!loadBase) {
                    return null;
                }
                String extension = strip(locale);
                if (extension == null) {
                    return null;
                }
                return handleGetBundle(base, extension, loadBase, loader);
            }
            return result;
        }

        try {
            // BEGIN android-changed
            /*
             * Intercept loading of ResourceBundles that contain Harmony
             * I18N data. Deliver our special, ICU-based bundles in this case.
             * All other ResourceBundles use the ordinary mechanism, so user
             * code behaves as it should.
             */
            if(bundleName.startsWith("org.apache.harmony.luni.internal.locale.")) {
                String icuBundleName = bundleName.substring(40);
                String icuLocale = (locale.length() > 0 ? locale.substring(1) : locale);
                // we know that Resources will deliver an assignable class
                bundle = Resources.getInstance(icuBundleName, icuLocale);
            } else {
                Class<?> bundleClass = Class.forName(bundleName, true, loader);
                if (ResourceBundle.class.isAssignableFrom(bundleClass)) {
                    bundle = (ResourceBundle) bundleClass.newInstance();
                }
            }
            // END android-changed
        } catch (LinkageError e) {
        } catch (Exception e) {
        }

        // BEGIN android-added
        // copied from newer version of Harmony
        if (bundle != null) {
            bundle.setLocale(locale);
        }
        // END android-added
        if (bundle == null) {
            final String fileName = bundleName.replace('.", '/");
            InputStream stream = AccessController
                    .doPrivileged(new PrivilegedAction<InputStream>() {
                        public InputStream run() {
                            return loader == null ? ClassLoader
                                    .getSystemResourceAsStream(fileName
                                            + ".properties") : loader //$NON-NLS-1$
                                    .getResourceAsStream(fileName
                                            + ".properties"); //$NON-NLS-1$
                        }
                    });
            if (stream != null) {
                try {
                    try {
                        bundle = new PropertyResourceBundle(stream);
                    } finally {
                        stream.close();
                    }
                    bundle.setLocale(locale);
                } catch (IOException e) {
                }
            }
        }

        String extension = strip(locale);
        if (bundle != null) {
            if (extension != null) {
                ResourceBundle parent = handleGetBundle(base, extension, true,
                        loader);
                if (parent != null) {
                    bundle.setParent(parent);
                }
            }
            loaderCache.put(bundleName, bundle);
            return bundle;
        }

        if (extension != null && (loadBase || extension.length() > 0)) {
            bundle = handleGetBundle(base, extension, loadBase, loader);
            if (bundle != null) {
                loaderCache.put(bundleName, bundle);
                return bundle;
            }
        }
        loaderCache.put(bundleName, loadBase ? MISSINGBASE : MISSING);
        return null;
    
protected abstract java.lang.ObjecthandleGetObject(java.lang.String key)
Returns the named resource from this {@code ResourceBundle}, or null if the resource is not found.

param
key the name of the resource.
return
the resource object.
since
Android 1.0

private voidsetLocale(java.lang.String name)

        String language = "", country = "", variant = ""; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
        if (name.length() > 1) {
            int nextIndex = name.indexOf('_", 1);
            if (nextIndex == -1) {
                nextIndex = name.length();
            }
            language = name.substring(1, nextIndex);
            if (nextIndex + 1 < name.length()) {
                int index = nextIndex;
                nextIndex = name.indexOf('_", nextIndex + 1);
                if (nextIndex == -1) {
                    nextIndex = name.length();
                }
                country = name.substring(index + 1, nextIndex);
                if (nextIndex + 1 < name.length()) {
                    variant = name.substring(nextIndex + 1, name.length());
                }
            }
        }
        locale = new Locale(language, country, variant);
    
protected voidsetParent(java.util.ResourceBundle bundle)
Sets the parent resource bundle of this {@code ResourceBundle}. The parent is searched for resources which are not found in this {@code ResourceBundle}.

param
bundle the parent {@code ResourceBundle}.
since
Android 1.0

        parent = bundle;
    
private static java.lang.Stringstrip(java.lang.String name)

        int index = name.lastIndexOf('_");
        if (index != -1) {
            return name.substring(0, index);
        }
        return null;