com.ibm.icu.util.UResourceBundle Maven / Gradle / Ivy
Show all versions of icu4j Show documentation
/*
*******************************************************************************
* Copyright (C) 2004-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.util;
import java.lang.ref.SoftReference;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.TreeSet;
import com.ibm.icu.impl.ICUCache;
import com.ibm.icu.impl.ICUResourceBundle;
import com.ibm.icu.impl.ICUResourceBundleReader;
import com.ibm.icu.impl.ResourceBundleWrapper;
import com.ibm.icu.impl.SimpleCache;
/**
* {@icuenhanced java.util.ResourceBundle}.{@icu _usage_}
*
* A class representing a collection of resource information pertaining to a given
* locale. A resource bundle provides a way of accessing locale- specific information in a
* data file. You create a resource bundle that manages the resources for a given locale
* and then ask it for individual resources.
*
*
In ResourceBundle, an object is created and the sub-items are fetched using the
* getString and getObject methods. In UResourceBundle, each individual element of a
* resource is a resource by itself.
*
*
Resource bundles in ICU are currently defined using text files that conform to the
* following BNF
* definition. More on resource bundle concepts and syntax can be found in the Users Guide.
*
*
The packaging of ICU *.res files can be of two types
* ICU4C:
*
* root.res
* |
* --------
* | |
* fr.res en.res
* |
* --------
* | |
* fr_CA.res fr_FR.res
*
* JAVA/JDK:
*
* LocaleElements.res
* |
* -------------------
* | |
* LocaleElements_fr.res LocaleElements_en.res
* |
* ---------------------------
* | |
* LocaleElements_fr_CA.res LocaleElements_fr_FR.res
*
*
* Depending on the organization of your resources, the syntax to getBundleInstance will
* change. To open ICU style organization use:
*
*
* UResourceBundle bundle =
* UResourceBundle.getBundleInstance("com/mycompany/resources",
* "en_US", myClassLoader);
*
* To open Java/JDK style organization use:
*
* UResourceBundle bundle =
* UResourceBundle.getBundleInstance("com.mycompany.resources.LocaleElements",
* "en_US", myClassLoader);
*
*
* Please use pass a class loader for loading non-ICU resources. Java security does not
* allow loading of resources across jar files. You must provide your class loader
* to load the resources
*
* @stable ICU 3.0
* @author ram
*/
public abstract class UResourceBundle extends ResourceBundle {
/**
* {@icu} Creates a resource bundle using the specified base name and locale.
* ICU_DATA_CLASS is used as the default root.
* @param baseName the base name of the resource bundle, a fully qualified class name
* @param localeName the locale for which a resource bundle is desired
* @throws MissingResourceException If no resource bundle for the specified base name
* can be found
* @return a resource bundle for the given base name and locale
* @stable ICU 3.0
*/
public static UResourceBundle getBundleInstance(String baseName, String localeName){
return getBundleInstance(baseName, localeName, ICUResourceBundle.ICU_DATA_CLASS_LOADER,
false);
}
/**
* {@icu} Creates a resource bundle using the specified base name, locale, and class root.
*
* @param baseName the base name of the resource bundle, a fully qualified class name
* @param localeName the locale for which a resource bundle is desired
* @param root the class object from which to load the resource bundle
* @throws MissingResourceException If no resource bundle for the specified base name
* can be found
* @return a resource bundle for the given base name and locale
* @stable ICU 3.0
*/
public static UResourceBundle getBundleInstance(String baseName, String localeName,
ClassLoader root){
return getBundleInstance(baseName, localeName, root, false);
}
/**
* {@icu} Creates a resource bundle using the specified base name, locale, and class
* root.
*
* @param baseName the base name of the resource bundle, a fully qualified class name
* @param localeName the locale for which a resource bundle is desired
* @param root the class object from which to load the resource bundle
* @param disableFallback Option to disable locale inheritence.
* If true the fallback chain will not be built.
* @throws MissingResourceException
* if no resource bundle for the specified base name can be found
* @return a resource bundle for the given base name and locale
* @stable ICU 3.0
*
*/
protected static UResourceBundle getBundleInstance(String baseName, String localeName,
ClassLoader root, boolean disableFallback) {
return instantiateBundle(baseName, localeName, root, disableFallback);
}
/**
* {@icu} Sole constructor. (For invocation by subclass constructors, typically
* implicit.) This is public for compatibility with Java, whose compiler
* will generate public default constructors for an abstract class.
* @stable ICU 3.0
*/
public UResourceBundle() {
}
/**
* {@icu} Creates a UResourceBundle for the locale specified, from which users can extract
* resources by using their corresponding keys.
* @param locale specifies the locale for which we want to open the resource.
* If null the bundle for default locale is opened.
* @return a resource bundle for the given locale
* @stable ICU 3.0
*/
public static UResourceBundle getBundleInstance(ULocale locale) {
if (locale==null) {
locale = ULocale.getDefault();
}
return getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale.toString(),
ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);
}
/**
* {@icu} Creates a UResourceBundle for the default locale and specified base name,
* from which users can extract resources by using their corresponding keys.
* @param baseName specifies the locale for which we want to open the resource.
* If null the bundle for default locale is opened.
* @return a resource bundle for the given base name and default locale
* @stable ICU 3.0
*/
public static UResourceBundle getBundleInstance(String baseName) {
if (baseName == null) {
baseName = ICUResourceBundle.ICU_BASE_NAME;
}
ULocale uloc = ULocale.getDefault();
return getBundleInstance(baseName, uloc.toString(), ICUResourceBundle.ICU_DATA_CLASS_LOADER,
false);
}
/**
* {@icu} Creates a UResourceBundle for the specified locale and specified base name,
* from which users can extract resources by using their corresponding keys.
* @param baseName specifies the locale for which we want to open the resource.
* If null the bundle for default locale is opened.
* @param locale specifies the locale for which we want to open the resource.
* If null the bundle for default locale is opened.
* @return a resource bundle for the given base name and locale
* @stable ICU 3.0
*/
public static UResourceBundle getBundleInstance(String baseName, Locale locale) {
if (baseName == null) {
baseName = ICUResourceBundle.ICU_BASE_NAME;
}
ULocale uloc = locale == null ? ULocale.getDefault() : ULocale.forLocale(locale);
return getBundleInstance(baseName, uloc.toString(), ICUResourceBundle.ICU_DATA_CLASS_LOADER,
false);
}
/**
* {@icu} Creates a UResourceBundle, from which users can extract resources by using
* their corresponding keys.
* @param baseName string containing the name of the data package.
* If null the default ICU package name is used.
* @param locale specifies the locale for which we want to open the resource.
* If null the bundle for default locale is opened.
* @return a resource bundle for the given base name and locale
* @stable ICU 3.0
*/
public static UResourceBundle getBundleInstance(String baseName, ULocale locale) {
if (baseName == null) {
baseName = ICUResourceBundle.ICU_BASE_NAME;
}
if (locale == null) {
locale = ULocale.getDefault();
}
return getBundleInstance(baseName, locale.toString(),
ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);
}
/**
* {@icu} Creates a UResourceBundle for the specified locale and specified base name,
* from which users can extract resources by using their corresponding keys.
* @param baseName specifies the locale for which we want to open the resource.
* If null the bundle for default locale is opened.
* @param locale specifies the locale for which we want to open the resource.
* If null the bundle for default locale is opened.
* @param loader the loader to use
* @return a resource bundle for the given base name and locale
* @stable ICU 3.8
*/
public static UResourceBundle getBundleInstance(String baseName, Locale locale,
ClassLoader loader) {
if (baseName == null) {
baseName = ICUResourceBundle.ICU_BASE_NAME;
}
ULocale uloc = locale == null ? ULocale.getDefault() : ULocale.forLocale(locale);
return getBundleInstance(baseName, uloc.toString(), loader, false);
}
/**
* {@icu} Creates a UResourceBundle, from which users can extract resources by using
* their corresponding keys.
* Note: Please use this API for loading non-ICU resources. Java security does not
* allow loading of resources across jar files. You must provide your class loader
* to load the resources
* @param baseName string containing the name of the data package.
* If null the default ICU package name is used.
* @param locale specifies the locale for which we want to open the resource.
* If null the bundle for default locale is opened.
* @param loader the loader to use
* @return a resource bundle for the given base name and locale
* @stable ICU 3.8
*/
public static UResourceBundle getBundleInstance(String baseName, ULocale locale,
ClassLoader loader) {
if (baseName == null) {
baseName = ICUResourceBundle.ICU_BASE_NAME;
}
if (locale == null) {
locale = ULocale.getDefault();
}
return getBundleInstance(baseName, locale.toString(), loader, false);
}
/**
* {@icu} Returns the RFC 3066 conformant locale id of this resource bundle.
* This method can be used after a call to getBundleInstance() to
* determine whether the resource bundle returned really
* corresponds to the requested locale or is a fallback.
*
* @return the locale of this resource bundle
* @stable ICU 3.0
*/
public abstract ULocale getULocale();
/**
* {@icu} Returns the localeID
* @return The string representation of the localeID
* @stable ICU 3.0
*/
protected abstract String getLocaleID();
/**
* {@icu} Returns the base name of the resource bundle
* @return The string representation of the base name
* @stable ICU 3.0
*/
protected abstract String getBaseName();
/**
* {@icu} Returns the parent bundle
* @return The parent bundle
* @stable ICU 3.0
*/
protected abstract UResourceBundle getParent();
/**
* Returns the locale of this bundle
* @return the locale of this resource bundle
* @stable ICU 3.0
*/
public Locale getLocale(){
return getULocale().toLocale();
}
// Cache for ResourceBundle instantiation
private static ICUCache BUNDLE_CACHE =
new SimpleCache();
/**
* @internal
* @deprecated This API is ICU internal only.
*/
public static void resetBundleCache() {
/*
* A HACK!!!!!
* Currently if a resourcebundle with fallback turned ON is added to the cache
* and then a getBundleInstance() is called for a bundle with fallback turned OFF
* it will actually search the cache for any bundle of the same locale
* regaurdless of fallback status. This method has been created so that if
* The calling method KNOWS that instances of the other fallback state may be in the
* cache, the calling method may call this method to clear out the cache.
*
*/
//TODO figure a way around this method(see method comment)
BUNDLE_CACHE = new SimpleCache();
}
/**
* Method used by subclasses to add a resource bundle object to the managed
* cache. Works like a putIfAbsent(): If the cache already contains a matching
* bundle, that one will be retained and returned.
* @internal
* @deprecated This API is ICU internal only.
*/
protected static UResourceBundle addToCache(ClassLoader cl, String fullName,
ULocale defaultLocale, UResourceBundle b) {
synchronized(cacheKey){
cacheKey.setKeyValues(cl, fullName, defaultLocale);
UResourceBundle cachedBundle = BUNDLE_CACHE.get(cacheKey);
if (cachedBundle != null) {
return cachedBundle;
}
BUNDLE_CACHE.put((ResourceCacheKey)cacheKey.clone(), b);
return b;
}
}
/**
* Method used by sub classes to load a resource bundle object from the managed cache
* @internal
* @deprecated This API is ICU internal only.
*/
protected static UResourceBundle loadFromCache(ClassLoader cl, String fullName,
ULocale defaultLocale){
synchronized(cacheKey){
cacheKey.setKeyValues(cl, fullName, defaultLocale);
return BUNDLE_CACHE.get(cacheKey);
}
}
/**
* Key used for cached resource bundles. The key checks
* the resource name, the class root, and the default
* locale to determine if the resource is a match to the
* requested one. The root may be null, but the
* searchName and the default locale must have a non-null value.
* Note that the default locale may change over time, and
* lookup should always be based on the current default
* locale (if at all).
*/
private static final class ResourceCacheKey implements Cloneable {
private SoftReference loaderRef;
private String searchName;
private ULocale defaultLocale;
private int hashCodeCache;
///CLOVER:OFF
public boolean equals(Object other) {
if (other == null) {
return false;
}
if (this == other) {
return true;
}
try {
final ResourceCacheKey otherEntry = (ResourceCacheKey) other;
//quick check to see if they are not equal
if (hashCodeCache != otherEntry.hashCodeCache) {
return false;
}
//are the names the same?
if (!searchName.equals(otherEntry.searchName)) {
return false;
}
// are the default locales the same?
if (defaultLocale == null) {
if (otherEntry.defaultLocale != null) {
return false;
}
} else {
if (!defaultLocale.equals(otherEntry.defaultLocale)) {
return false;
}
}
//are refs (both non-null) or (both null)?
if (loaderRef == null) {
return otherEntry.loaderRef == null;
} else {
return (otherEntry.loaderRef != null)
&& (loaderRef.get() == otherEntry.loaderRef.get());
}
} catch (NullPointerException e) {
return false;
} catch (ClassCastException e) {
return false;
}
}
public int hashCode() {
return hashCodeCache;
}
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
//this should never happen
throw new IllegalStateException();
}
}
///CLOVER:ON
private synchronized void setKeyValues(ClassLoader root, String searchName,
ULocale defaultLocale) {
this.searchName = searchName;
hashCodeCache = searchName.hashCode();
this.defaultLocale = defaultLocale;
if (defaultLocale != null) {
hashCodeCache ^= defaultLocale.hashCode();
}
if (root == null) {
this.loaderRef = null;
} else {
loaderRef = new SoftReference(root);
hashCodeCache ^= root.hashCode();
}
}
/*private void clear() {
setKeyValues(null, "", null);
}*/
}
private static final ResourceCacheKey cacheKey = new ResourceCacheKey();
private static final int ROOT_MISSING = 0;
private static final int ROOT_ICU = 1;
private static final int ROOT_JAVA = 2;
private static SoftReference