ICU-7434 switch UResourceBundle.BUNDLE_CACHE from SimpleCache to SoftCache, move/split BUNDLE_CACHE into impl subclasses to avoid protected @internal hacks

X-SVN-Rev: 38751
This commit is contained in:
Markus Scherer 2016-05-18 20:29:26 +00:00
parent 1824b6f66c
commit 37701877e3
3 changed files with 169 additions and 280 deletions

View file

@ -78,6 +78,19 @@ public class ICUResourceBundle extends UResourceBundle {
WholeBundle wholeBundle;
private ICUResourceBundle container;
/** Loader for bundle instances, for caching. */
private static abstract class Loader {
abstract ICUResourceBundle load();
}
private static CacheBase<String, ICUResourceBundle, Loader> BUNDLE_CACHE =
new SoftCache<String, ICUResourceBundle, Loader>() {
@Override
protected ICUResourceBundle createInstance(String unusedKey, Loader loader) {
return loader.load();
}
};
/**
* Returns a functionally equivalent locale, considering keywords as well, for the specified keyword.
* @param baseName resource specifier
@ -139,7 +152,7 @@ public class ICUResourceBundle extends UResourceBundle {
// Ignore error and continue search.
}
if (defLoc == null) {
r = (ICUResourceBundle) r.getParent();
r = r.getParent();
defDepth++;
}
} while ((r != null) && (defLoc == null));
@ -165,7 +178,7 @@ public class ICUResourceBundle extends UResourceBundle {
// Ignore error,
}
if (fullBase == null) {
r = (ICUResourceBundle) r.getParent();
r = r.getParent();
resDepth++;
}
} while ((r != null) && (fullBase == null));
@ -182,14 +195,14 @@ public class ICUResourceBundle extends UResourceBundle {
do {
try {
ICUResourceBundle irb = (ICUResourceBundle)r.get(resName);
UResourceBundle urb = irb.get(kwVal);
ICUResourceBundle urb = (ICUResourceBundle)irb.get(kwVal);
// if we didn't fail before this..
fullBase = r.getULocale();
// If the fetched item (urb) is in a different locale than our outer locale (r/fullBase)
// then we are in a 'fallback' situation. treat as a missing resource situation.
if(!fullBase.toString().equals(urb.getLocale().toString())) {
if(!fullBase.getBaseName().equals(urb.getULocale().getBaseName())) {
fullBase = null; // fallback condition. Loop and try again.
}
@ -204,7 +217,7 @@ public class ICUResourceBundle extends UResourceBundle {
// Ignore error, continue search.
}
if (fullBase == null) {
r = (ICUResourceBundle) r.getParent();
r = r.getParent();
resDepth++;
}
} while ((r != null) && (fullBase == null));
@ -221,7 +234,7 @@ public class ICUResourceBundle extends UResourceBundle {
&& resDepth <= defDepth) { // default was set in same locale or child
return fullBase; // Keyword value is default - no keyword needed in locale
} else {
return new ULocale(fullBase.toString() + "@" + keyword + "=" + kwVal);
return new ULocale(fullBase.getBaseName() + "@" + keyword + "=" + kwVal);
}
}
@ -848,7 +861,7 @@ public class ICUResourceBundle extends UResourceBundle {
base = sub;
}
// Try the parent bundle of the last-found resource.
ICUResourceBundle nextBase = (ICUResourceBundle)base.getParent();
ICUResourceBundle nextBase = base.getParent();
if (nextBase == null) {
return null;
}
@ -961,7 +974,7 @@ public class ICUResourceBundle extends UResourceBundle {
}
}
// Try the parent bundle of the last-found resource.
ICUResourceBundle nextBase = (ICUResourceBundle)base.getParent();
ICUResourceBundle nextBase = base.getParent();
if (nextBase == null) {
return null;
}
@ -1100,37 +1113,34 @@ public class ICUResourceBundle extends UResourceBundle {
};
// This method is for super class's instantiateBundle method
public static UResourceBundle getBundleInstance(String baseName, String localeID,
ClassLoader root, boolean disableFallback){
UResourceBundle b = instantiateBundle(baseName, localeID, root,
disableFallback ? OpenType.DIRECT : OpenType.LOCALE_DEFAULT_ROOT);
if(b==null){
throw new MissingResourceException("Could not find the bundle "+ baseName+"/"+ localeID+".res","","");
}
return b;
}
protected static UResourceBundle instantiateBundle(String baseName, String localeID,
ClassLoader root, boolean disableFallback){
return instantiateBundle(baseName, localeID, root,
public static ICUResourceBundle getBundleInstance(String baseName, String localeID,
ClassLoader root, boolean disableFallback) {
return getBundleInstance(baseName, localeID, root,
disableFallback ? OpenType.DIRECT : OpenType.LOCALE_DEFAULT_ROOT);
}
public static UResourceBundle getBundleInstance(
public static ICUResourceBundle getBundleInstance(
String baseName, ULocale locale, OpenType openType) {
if (locale == null) {
locale = ULocale.getDefault();
}
return getBundleInstance(baseName, locale.toString(),
return getBundleInstance(baseName, locale.getBaseName(),
ICUResourceBundle.ICU_DATA_CLASS_LOADER, openType);
}
public static UResourceBundle getBundleInstance(String baseName, String localeID,
public static ICUResourceBundle getBundleInstance(String baseName, String localeID,
ClassLoader root, OpenType openType) {
if (baseName == null) {
baseName = ICUData.ICU_BASE_NAME;
}
UResourceBundle b = instantiateBundle(baseName, localeID, root, openType);
localeID = ULocale.getBaseName(localeID);
ICUResourceBundle b;
if (openType == OpenType.LOCALE_DEFAULT_ROOT) {
b = instantiateBundle(baseName, localeID, ULocale.getDefault().getBaseName(),
root, openType);
} else {
b = instantiateBundle(baseName, localeID, null, root, openType);
}
if(b==null){
throw new MissingResourceException(
"Could not find the bundle "+ baseName+"/"+ localeID+".res","","");
@ -1138,33 +1148,35 @@ public class ICUResourceBundle extends UResourceBundle {
return b;
}
// recursively build bundle
private synchronized static UResourceBundle instantiateBundle(String baseName, String localeID,
ClassLoader root, OpenType openType) {
ULocale defaultLocale = ULocale.getDefault();
String localeName = localeID;
if(localeName.indexOf('@')>=0){
localeName = ULocale.getBaseName(localeID);
}
String fullName = ICUResourceBundleReader.getFullName(baseName, localeName);
ICUResourceBundle b = (ICUResourceBundle)loadFromCache(fullName, defaultLocale);
private static boolean localeIDStartsWithLangSubtag(String localeID, String lang) {
return localeID.startsWith(lang) &&
(localeID.length() == lang.length() || localeID.charAt(lang.length()) == '_');
}
// here we assume that java type resource bundle organization
// is required then the base name contains '.' else
// the resource organization is of ICU type
// so clients can instantiate resources of the type
// com.mycompany.data.MyLocaleElements_en.res and
// com.mycompany.data.MyLocaleElements.res
//
final String rootLocale = (baseName.indexOf('.')==-1) ? "root" : "";
final String defaultID = defaultLocale.getBaseName();
if(localeName.equals("")){
localeName = rootLocale;
}
if(DEBUG) System.out.println("Creating "+fullName+ " currently b is "+b);
if (b == null) {
b = ICUResourceBundle.createBundle(baseName, localeName, root);
private static ICUResourceBundle instantiateBundle(
final String baseName, final String localeID, final String defaultID,
final ClassLoader root, final OpenType openType) {
assert localeID.indexOf('@') < 0;
assert defaultID == null || defaultID.indexOf('@') < 0;
final String fullName = ICUResourceBundleReader.getFullName(baseName, localeID);
char openTypeChar = (char)('0' + openType.ordinal());
String cacheKey = openType != OpenType.LOCALE_DEFAULT_ROOT ?
fullName + '#' + openTypeChar :
fullName + '#' + openTypeChar + '#' + defaultID;
return BUNDLE_CACHE.getInstance(cacheKey, new Loader() {
@Override
public ICUResourceBundle load() {
if(DEBUG) System.out.println("Creating "+fullName);
// here we assume that java type resource bundle organization
// is required then the base name contains '.' else
// the resource organization is of ICU type
// so clients can instantiate resources of the type
// com.mycompany.data.MyLocaleElements_en.res and
// com.mycompany.data.MyLocaleElements.res
//
final String rootLocale = (baseName.indexOf('.')==-1) ? "root" : "";
String localeName = localeID.isEmpty() ? rootLocale : localeID;
ICUResourceBundle b = ICUResourceBundle.createBundle(baseName, localeName, root);
if(DEBUG)System.out.println("The bundle created is: "+b+" and openType="+openType+" and bundle.getNoFallback="+(b!=null && b.getNoFallback()));
if (openType == OpenType.DIRECT || (b != null && b.getNoFallback())) {
@ -1179,7 +1191,7 @@ public class ICUResourceBundle extends UResourceBundle {
// for a bundle that does not have nofallback.
// Are the relevant test cases just disabled?
// Do item aliases not get followed via "direct" loading?
return addToCache(fullName, defaultLocale, b);
return b;
}
// fallback to locale ID parent
@ -1188,13 +1200,13 @@ public class ICUResourceBundle extends UResourceBundle {
if (i != -1) {
// Chop off the last underscore and the subtag after that.
String temp = localeName.substring(0, i);
b = (ICUResourceBundle)instantiateBundle(baseName, temp, root, openType);
b = instantiateBundle(baseName, temp, defaultID, root, openType);
}else{
// No underscore, only a base language subtag.
if(openType == OpenType.LOCALE_DEFAULT_ROOT &&
!defaultLocale.getLanguage().equals(localeName)) {
!localeIDStartsWithLangSubtag(defaultID, localeName)) {
// Go to the default locale before root.
b = (ICUResourceBundle)instantiateBundle(baseName, defaultID, root, openType);
b = instantiateBundle(baseName, defaultID, defaultID, root, openType);
} else if(openType != OpenType.LOCALE_ONLY && !rootLocale.isEmpty()) {
// Ultimately go to root.
b = ICUResourceBundle.createBundle(baseName, rootLocale, root);
@ -1205,32 +1217,31 @@ public class ICUResourceBundle extends UResourceBundle {
localeName = b.getLocaleID();
int i = localeName.lastIndexOf('_');
b = (ICUResourceBundle)addToCache(fullName, defaultLocale, b);
// TODO: C++ uresbund.cpp also checks for %%ParentIsRoot. Why not Java?
String parentLocaleName = ((ICUResourceBundleImpl.ResourceTable)b).findString("%%Parent");
if (parentLocaleName != null) {
parent = instantiateBundle(baseName, parentLocaleName, root, openType);
parent = instantiateBundle(baseName, parentLocaleName, defaultID, root, openType);
} else if (i != -1) {
parent = instantiateBundle(baseName, localeName.substring(0, i), root, openType);
parent = instantiateBundle(baseName, localeName.substring(0, i), defaultID, root, openType);
} else if (!localeName.equals(rootLocale)){
parent = instantiateBundle(baseName, rootLocale, root, true);
parent = instantiateBundle(baseName, rootLocale, defaultID, root, openType);
}
if (!b.equals(parent)){
b.setParent(parent);
}
}
}
return b;
return b;
}});
}
UResourceBundle get(String aKey, HashMap<String, String> aliasesVisited, UResourceBundle requested) {
ICUResourceBundle get(String aKey, HashMap<String, String> aliasesVisited, UResourceBundle requested) {
ICUResourceBundle obj = (ICUResourceBundle)handleGet(aKey, aliasesVisited, requested);
if (obj == null) {
obj = (ICUResourceBundle)getParent();
obj = getParent();
if (obj != null) {
//call the get method to recursively fetch the resource
obj = (ICUResourceBundle)obj.get(aKey, aliasesVisited, requested);
obj = obj.get(aKey, aliasesVisited, requested);
}
if (obj == null) {
String fullName = ICUResourceBundleReader.getFullName(getBaseName(), getLocaleID());
@ -1319,8 +1330,8 @@ public class ICUResourceBundle extends UResourceBundle {
return wholeBundle.localeID.isEmpty() || wholeBundle.localeID.equals("root");
}
public UResourceBundle getParent() {
return (UResourceBundle) parent;
public ICUResourceBundle getParent() {
return (ICUResourceBundle) parent;
}
protected void setParent(ResourceBundle parent) {
@ -1462,11 +1473,9 @@ public class ICUResourceBundle extends UResourceBundle {
}else{
if (locale == null) {
// {dlf} must use requestor's class loader to get resources from same jar
bundle = (ICUResourceBundle) getBundleInstance(bundleName, "",
loaderToUse, false);
bundle = getBundleInstance(bundleName, "", loaderToUse, false);
} else {
bundle = (ICUResourceBundle) getBundleInstance(bundleName, locale,
loaderToUse, false);
bundle = getBundleInstance(bundleName, locale, loaderToUse, false);
}
int numKeys;
@ -1488,7 +1497,7 @@ public class ICUResourceBundle extends UResourceBundle {
if (numKeys > 0) {
sub = bundle;
for (int i = 0; sub != null && i < numKeys; ++i) {
sub = (ICUResourceBundle)sub.get(keys[i], aliasesVisited, requested);
sub = sub.get(keys[i], aliasesVisited, requested);
}
}
}

View file

@ -24,12 +24,25 @@ import com.ibm.icu.util.UResourceBundle;
* @author ram
*
*/
public class ResourceBundleWrapper extends UResourceBundle {
public final class ResourceBundleWrapper extends UResourceBundle {
private ResourceBundle bundle = null;
private String localeID = null;
private String baseName = null;
private List<String> keys = null;
/** Loader for bundle instances, for caching. */
private static abstract class Loader {
abstract ResourceBundleWrapper load();
}
private static CacheBase<String, ResourceBundleWrapper, Loader> BUNDLE_CACHE =
new SoftCache<String, ResourceBundleWrapper, Loader>() {
@Override
protected ResourceBundleWrapper createInstance(String unusedKey, Loader loader) {
return loader.load();
}
};
private ResourceBundleWrapper(ResourceBundle bundle){
this.bundle=bundle;
}
@ -93,9 +106,18 @@ public class ResourceBundleWrapper extends UResourceBundle {
private static final boolean DEBUG = ICUDebug.enabled("resourceBundleWrapper");
// This method is for super class's instantiateBundle method
public static UResourceBundle getBundleInstance(String baseName, String localeID,
ClassLoader root, boolean disableFallback){
UResourceBundle b = instantiateBundle(baseName, localeID, root, disableFallback);
public static ResourceBundleWrapper getBundleInstance(String baseName, String localeID,
ClassLoader root, boolean disableFallback) {
if (root == null) {
root = ClassLoaderUtil.getClassLoader();
}
ResourceBundleWrapper b;
if (disableFallback) {
b = instantiateBundle(baseName, localeID, null, root, disableFallback);
} else {
b = instantiateBundle(baseName, localeID, ULocale.getDefault().getBaseName(),
root, disableFallback);
}
if(b==null){
String separator ="_";
if(baseName.indexOf('/')>=0){
@ -105,47 +127,43 @@ public class ResourceBundleWrapper extends UResourceBundle {
}
return b;
}
// recursively build bundle and override the super-class method
protected static synchronized UResourceBundle instantiateBundle(String baseName, String localeID,
ClassLoader root, boolean disableFallback) {
if (root == null) {
root = ClassLoaderUtil.getClassLoader();
}
final ClassLoader cl = root;
String name = baseName;
ULocale defaultLocale = ULocale.getDefault();
if (localeID.length() != 0) {
name = name + "_" + localeID;
}
ResourceBundleWrapper b = (ResourceBundleWrapper)loadFromCache(name, defaultLocale);
if(b==null){
private static boolean localeIDStartsWithLangSubtag(String localeID, String lang) {
return localeID.startsWith(lang) &&
(localeID.length() == lang.length() || localeID.charAt(lang.length()) == '_');
}
private static ResourceBundleWrapper instantiateBundle(
final String baseName, final String localeID, final String defaultID,
final ClassLoader root, final boolean disableFallback) {
final String name = localeID.isEmpty() ? baseName : baseName + '_' + localeID;
String cacheKey = disableFallback ? name : name + '#' + defaultID;
return BUNDLE_CACHE.getInstance(cacheKey, new Loader() {
@Override
public ResourceBundleWrapper load() {
ResourceBundleWrapper parent = null;
int i = localeID.lastIndexOf('_');
boolean loadFromProperties = false;
boolean parentIsRoot = false;
if (i != -1) {
String locName = localeID.substring(0, i);
parent = (ResourceBundleWrapper)loadFromCache(baseName+"_"+locName,defaultLocale);
if(parent == null){
parent = (ResourceBundleWrapper)instantiateBundle(baseName, locName , cl, disableFallback);
}
}else if(localeID.length()>0){
parent = (ResourceBundleWrapper)loadFromCache(baseName,defaultLocale);
if(parent==null){
parent = (ResourceBundleWrapper)instantiateBundle(baseName, "", cl, disableFallback);
}
parent = instantiateBundle(baseName, locName, defaultID, root, disableFallback);
}else if(!localeID.isEmpty()){
parent = instantiateBundle(baseName, "", defaultID, root, disableFallback);
parentIsRoot = true;
}
ResourceBundleWrapper b = null;
try {
Class<? extends ResourceBundle> cls = cl.loadClass(name).asSubclass(ResourceBundle.class);
Class<? extends ResourceBundle> cls =
root.loadClass(name).asSubclass(ResourceBundle.class);
ResourceBundle bx = cls.newInstance();
b = new ResourceBundleWrapper(bx);
if (parent != null) {
b.setParent(parent);
}
b.baseName=baseName;
b.localeID = localeID;
b.localeID = localeID;
} catch (ClassNotFoundException e) {
loadFromProperties = true;
} catch (NoClassDefFoundError e) {
@ -163,11 +181,7 @@ public class ResourceBundleWrapper extends UResourceBundle {
InputStream stream = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<InputStream>() {
public InputStream run() {
if (cl != null) {
return cl.getResourceAsStream(resName);
} else {
return ClassLoader.getSystemResourceAsStream(resName);
}
return root.getResourceAsStream(resName);
}
}
);
@ -191,22 +205,19 @@ public class ResourceBundleWrapper extends UResourceBundle {
}
}
}
// if a bogus locale is passed then the parent should be
// the default locale not the root locale!
if (b==null) {
String defaultName = defaultLocale.toString();
if (localeID.length()>0 && localeID.indexOf('_')< 0 && defaultName.indexOf(localeID) == -1) {
b = (ResourceBundleWrapper)loadFromCache(baseName+"_"+defaultName, defaultLocale);
if(b==null){
b = (ResourceBundleWrapper)instantiateBundle(baseName , defaultName, cl, disableFallback);
}
}
if (b == null && !disableFallback &&
!localeID.isEmpty() && localeID.indexOf('_') < 0 &&
!localeIDStartsWithLangSubtag(defaultID, localeID)) {
// localeID is only a language subtag, different from the default language.
b = instantiateBundle(baseName, defaultID, defaultID, root, disableFallback);
}
// if still could not find the bundle then return the parent
if(b==null){
if(b==null && (!parentIsRoot || !disableFallback)){
b=parent;
}
}
} catch (Exception e) {
if (DEBUG)
System.out.println("failure");
@ -214,15 +225,12 @@ public class ResourceBundleWrapper extends UResourceBundle {
System.out.println(e);
}
}
b = (ResourceBundleWrapper)addToCache(name, defaultLocale, b);
}
if(b!=null){
b.initKeysVector();
}else{
if(DEBUG)System.out.println("Returning null for "+baseName+"_"+localeID);
}
return b;
if(b!=null){
b.initKeysVector();
}else{
if(DEBUG)System.out.println("Returning null for "+baseName+"_"+localeID);
}
return b;
}});
}
}

View file

@ -19,12 +19,10 @@ import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import com.ibm.icu.impl.ICUCache;
import com.ibm.icu.impl.ICUData;
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_}
@ -98,7 +96,8 @@ 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 baseName string containing the name of the data package.
* If null the default ICU package name is used.
* @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
@ -113,7 +112,8 @@ public abstract class UResourceBundle extends ResourceBundle {
/**
* {@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 baseName string containing the name of the data package.
* If null the default ICU package name is used.
* @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
@ -130,7 +130,8 @@ public abstract class UResourceBundle extends ResourceBundle {
* {@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 baseName string containing the name of the data package.
* If null the default ICU package name is used.
* @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.
@ -167,15 +168,15 @@ public abstract class UResourceBundle extends ResourceBundle {
if (locale==null) {
locale = ULocale.getDefault();
}
return getBundleInstance(ICUData.ICU_BASE_NAME, locale.toString(),
return getBundleInstance(ICUData.ICU_BASE_NAME, locale.getBaseName(),
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.
* @param baseName string containing the name of the data package.
* If null the default ICU package name is used.
* @return a resource bundle for the given base name and default locale
* @stable ICU 3.0
*/
@ -184,15 +185,15 @@ public abstract class UResourceBundle extends ResourceBundle {
baseName = ICUData.ICU_BASE_NAME;
}
ULocale uloc = ULocale.getDefault();
return getBundleInstance(baseName, uloc.toString(), ICUResourceBundle.ICU_DATA_CLASS_LOADER,
return getBundleInstance(baseName, uloc.getBaseName(), 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 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
@ -205,8 +206,8 @@ public abstract class UResourceBundle extends ResourceBundle {
}
ULocale uloc = locale == null ? ULocale.getDefault() : ULocale.forLocale(locale);
return getBundleInstance(baseName, uloc.toString(), ICUResourceBundle.ICU_DATA_CLASS_LOADER,
false);
return getBundleInstance(baseName, uloc.getBaseName(),
ICUResourceBundle.ICU_DATA_CLASS_LOADER, false);
}
/**
@ -226,15 +227,15 @@ public abstract class UResourceBundle extends ResourceBundle {
if (locale == null) {
locale = ULocale.getDefault();
}
return getBundleInstance(baseName, locale.toString(),
return getBundleInstance(baseName, locale.getBaseName(),
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 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
@ -247,7 +248,7 @@ public abstract class UResourceBundle extends ResourceBundle {
baseName = ICUData.ICU_BASE_NAME;
}
ULocale uloc = locale == null ? ULocale.getDefault() : ULocale.forLocale(locale);
return getBundleInstance(baseName, uloc.toString(), loader, false);
return getBundleInstance(baseName, uloc.getBaseName(), loader, false);
}
/**
@ -272,7 +273,7 @@ public abstract class UResourceBundle extends ResourceBundle {
if (locale == null) {
locale = ULocale.getDefault();
}
return getBundleInstance(baseName, locale.toString(), loader, false);
return getBundleInstance(baseName, locale.getBaseName(), loader, false);
}
/**
@ -317,122 +318,6 @@ public abstract class UResourceBundle extends ResourceBundle {
return getULocale().toLocale();
}
// Cache for ResourceBundle instantiation
private static ICUCache<ResourceCacheKey, UResourceBundle> BUNDLE_CACHE =
new SimpleCache<ResourceCacheKey, UResourceBundle>();
/**
* 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.
*/
@Deprecated
protected static UResourceBundle addToCache(String fullName, ULocale defaultLocale, UResourceBundle b) {
synchronized(cacheKey){
cacheKey.setKeyValues(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.
*/
@Deprecated
protected static UResourceBundle loadFromCache(String fullName, ULocale defaultLocale) {
synchronized(cacheKey){
cacheKey.setKeyValues(fullName, defaultLocale);
return BUNDLE_CACHE.get(cacheKey);
}
}
/**
* Key used for cached resource bundles. The key checks
* the resource name and the default
* locale to determine if the resource is a match to the
* requested one. The default locale may be null, but the
* searchName 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 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;
}
}
return true;
} 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 ICUCloneNotSupportedException(e);
}
}
///CLOVER:ON
private synchronized void setKeyValues(String searchName, ULocale defaultLocale) {
this.searchName = searchName;
hashCodeCache = searchName.hashCode();
this.defaultLocale = defaultLocale;
if (defaultLocale != null) {
hashCodeCache ^= defaultLocale.hashCode();
}
}
/*private void clear() {
setKeyValues(null, "", null);
}*/
}
private static final ResourceCacheKey cacheKey = new ResourceCacheKey();
private enum RootType { MISSING, ICU, JAVA }
private static Map<String, RootType> ROOT_CACHE = new ConcurrentHashMap<String, RootType>();
@ -468,7 +353,8 @@ public abstract class UResourceBundle extends ResourceBundle {
/**
* {@icu} Loads a new resource bundle for the given base name, locale and class loader.
* Optionally will disable loading of fallback bundles.
* @param baseName the base name of the resource bundle, a fully qualified class name
* @param baseName string containing the name of the data package.
* If null the default ICU package name is used.
* @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 disables loading of fallback lookup chain
@ -479,26 +365,11 @@ public abstract class UResourceBundle extends ResourceBundle {
*/
protected static UResourceBundle instantiateBundle(String baseName, String localeName,
ClassLoader root, boolean disableFallback) {
UResourceBundle b = null;
RootType rootType = getRootType(baseName, root);
ULocale defaultLocale = ULocale.getDefault();
switch (rootType) {
case ICU:
if(disableFallback) {
String fullName = ICUResourceBundleReader.getFullName(baseName, localeName);
b = loadFromCache(fullName, defaultLocale);
if (b == null) {
b = ICUResourceBundle.getBundleInstance(baseName, localeName, root,
disableFallback);
}
} else {
b = ICUResourceBundle.getBundleInstance(baseName, localeName, root,
disableFallback);
}
return b;
return ICUResourceBundle.getBundleInstance(baseName, localeName, root, disableFallback);
case JAVA:
return ResourceBundleWrapper.getBundleInstance(baseName, localeName, root,
@ -506,6 +377,7 @@ public abstract class UResourceBundle extends ResourceBundle {
case MISSING:
default:
UResourceBundle b;
try{
b = ICUResourceBundle.getBundleInstance(baseName, localeName, root,
disableFallback);