From bb45e5754bf3d3e4f3a05d05cdc80044fbda4232 Mon Sep 17 00:00:00 2001 From: naoto Date: Mon, 14 Jan 2013 11:09:53 -0800 Subject: [PATCH] 7162007: Clean up i18n related caches Reviewed-by: okutsu, ohair --- make/java/java/FILES_java.gmk | 1 + .../classes/java/text/DateFormatSymbols.java | 8 +- .../classes/java/text/DecimalFormat.java | 30 +- .../java/text/DecimalFormatSymbols.java | 60 +--- src/share/classes/java/text/NumberFormat.java | 1 - src/share/classes/java/util/Locale.java | 38 +- src/share/classes/java/util/TimeZone.java | 27 +- .../resources/zh/CollationData_zh_HK.java | 3 +- .../text/resources/zh/FormatData_zh_HK.java | 4 +- .../provider/AuxLocaleProviderAdapter.java | 6 - .../provider/BreakIteratorProviderImpl.java | 16 +- .../provider/CalendarDataProviderImpl.java | 18 +- .../provider/CalendarNameProviderImpl.java | 35 +- .../locale/provider/CollatorProviderImpl.java | 11 +- .../provider/CurrencyNameProviderImpl.java | 8 +- .../provider/JRELocaleProviderAdapter.java | 3 +- .../provider/LocaleNameProviderImpl.java | 8 +- .../provider/LocaleProviderAdapter.java | 29 +- .../util/locale/provider/LocaleResources.java | 324 ++++++++++++++++-- .../provider/ResourceBundleBasedAdapter.java | 37 ++ .../provider/TimeZoneNameProviderImpl.java | 34 +- .../locale/provider/TimeZoneNameUtility.java | 50 ++- .../sun/util/resources/LocaleData.java | 8 + .../resources/zh/CurrencyNames_zh_HK.java | 3 +- .../resources/zh/CurrencyNames_zh_SG.java | 3 +- .../util/resources/zh/LocaleNames_zh_HK.java | 3 +- .../resources/zh/TimeZoneNames_zh_HK.java | 3 +- .../BreakIteratorProviderTest.java | 3 +- .../PluggableLocale/CollatorProviderTest.java | 2 +- .../CurrencyNameProviderTest.java | 2 +- .../DateFormatProviderTest.java | 2 +- .../DateFormatSymbolsProviderTest.java | 2 +- .../DecimalFormatSymbolsProviderTest.java | 10 +- .../LocaleNameProviderTest.java | 2 +- .../NumberFormatProviderTest.java | 6 +- .../TimeZoneNameProviderTest.java | 2 +- 36 files changed, 491 insertions(+), 311 deletions(-) create mode 100644 src/share/classes/sun/util/locale/provider/ResourceBundleBasedAdapter.java diff --git a/make/java/java/FILES_java.gmk b/make/java/java/FILES_java.gmk index f6affbf98..28894f24a 100644 --- a/make/java/java/FILES_java.gmk +++ b/make/java/java/FILES_java.gmk @@ -227,6 +227,7 @@ JAVA_JAVA_java = \ sun/util/locale/provider/LocaleResources.java \ sun/util/locale/provider/NumberFormatProviderImpl.java \ sun/util/locale/provider/RuleBasedBreakIterator.java \ + sun/util/locale/provider/ResourceBundleBasedAdapter.java \ sun/util/locale/provider/SPILocaleProviderAdapter.java \ sun/util/locale/provider/TimeZoneNameProviderImpl.java \ sun/util/locale/provider/TimeZoneNameUtility.java \ diff --git a/src/share/classes/java/text/DateFormatSymbols.java b/src/share/classes/java/text/DateFormatSymbols.java index bde39a66e..b4c380d2c 100644 --- a/src/share/classes/java/text/DateFormatSymbols.java +++ b/src/share/classes/java/text/DateFormatSymbols.java @@ -52,6 +52,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.LocaleServiceProviderPool; +import sun.util.locale.provider.ResourceBundleBasedAdapter; import sun.util.locale.provider.TimeZoneNameUtility; /** @@ -680,13 +681,10 @@ public class DateFormatSymbols implements Serializable, Cloneable { // Initialize the fields from the ResourceBundle for locale. LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DateFormatSymbolsProvider.class, locale); // Avoid any potential recursions - switch (adapter.getAdapterType()) { - case HOST: - case SPI: + if (!(adapter instanceof ResourceBundleBasedAdapter)) { adapter = LocaleProviderAdapter.getResourceBundleBased(); - break; } - ResourceBundle resource = adapter.getLocaleData().getDateFormatData(locale); + ResourceBundle resource = ((ResourceBundleBasedAdapter)adapter).getLocaleData().getDateFormatData(locale); // JRE and CLDR use different keys // JRE: Eras, short.Eras and narrow.Eras diff --git a/src/share/classes/java/text/DecimalFormat.java b/src/share/classes/java/text/DecimalFormat.java index 6d19bedcb..38c930372 100644 --- a/src/share/classes/java/text/DecimalFormat.java +++ b/src/share/classes/java/text/DecimalFormat.java @@ -54,6 +54,7 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.ResourceBundleBasedAdapter; /** * DecimalFormat is a concrete subclass of @@ -394,28 +395,17 @@ public class DecimalFormat extends NumberFormat { * @see java.text.NumberFormat#getPercentInstance */ public DecimalFormat() { + // Get the pattern for the default locale. Locale def = Locale.getDefault(Locale.Category.FORMAT); - // try to get the pattern from the cache - String pattern = cachedLocaleData.get(def); - if (pattern == null) { /* cache miss */ - // Get the pattern for the default locale. - LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(NumberFormatProvider.class, def); - switch (adapter.getAdapterType()) { - case HOST: - case SPI: - adapter = LocaleProviderAdapter.getResourceBundleBased(); - break; - } - ResourceBundle rb = adapter.getLocaleData().getNumberFormatData(def); - String[] all = rb.getStringArray("NumberPatterns"); - pattern = all[0]; - /* update cache */ - cachedLocaleData.putIfAbsent(def, pattern); + LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(NumberFormatProvider.class, def); + if (!(adapter instanceof ResourceBundleBasedAdapter)) { + adapter = LocaleProviderAdapter.getResourceBundleBased(); } + String[] all = adapter.getLocaleResources(def).getNumberPatterns(); // Always applyPattern after the symbols are set this.symbols = DecimalFormatSymbols.getInstance(def); - applyPattern(pattern, false); + applyPattern(all[0], false); } @@ -4154,10 +4144,4 @@ public class DecimalFormat extends NumberFormat { // Proclaim JDK 1.1 serial compatibility. static final long serialVersionUID = 864413376551465018L; - - /** - * Cache to hold the NumberPattern of a Locale. - */ - private static final ConcurrentMap cachedLocaleData - = new ConcurrentHashMap<>(3); } diff --git a/src/share/classes/java/text/DecimalFormatSymbols.java b/src/share/classes/java/text/DecimalFormatSymbols.java index 81ab956a4..9274208fe 100644 --- a/src/share/classes/java/text/DecimalFormatSymbols.java +++ b/src/share/classes/java/text/DecimalFormatSymbols.java @@ -52,6 +52,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.LocaleServiceProviderPool; +import sun.util.locale.provider.ResourceBundleBasedAdapter; /** * This class represents the set of symbols (such as the decimal separator, @@ -542,48 +543,13 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { private void initialize( Locale locale ) { this.locale = locale; - // get resource bundle data - try the cache first - boolean needCacheUpdate = false; - Object[] data = cachedLocaleData.get(locale); - if (data == null) { /* cache miss */ - LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale); - // Avoid potential recursions - switch (adapter.getAdapterType()) { - case HOST: - case SPI: - adapter = LocaleProviderAdapter.getResourceBundleBased(); - break; - } - ResourceBundle rb = adapter.getLocaleData().getNumberFormatData(locale); - data = new Object[3]; - - // NumberElements look up. First, try the Unicode extension - String numElemKey; - String numberType = locale.getUnicodeLocaleType("nu"); - if (numberType != null) { - numElemKey = numberType + ".NumberElements"; - if (rb.containsKey(numElemKey)) { - data[0] = rb.getStringArray(numElemKey); - } - } - - // Next, try DefaultNumberingSystem value - if (data[0] == null && rb.containsKey("DefaultNumberingSystem")) { - numElemKey = rb.getString("DefaultNumberingSystem") + ".NumberElements"; - if (rb.containsKey(numElemKey)) { - data[0] = rb.getStringArray(numElemKey); - } - } - - // Last resort. No need to check the availability. - // Just let it throw MissingResourceException when needed. - if (data[0] == null) { - data[0] = rb.getStringArray("NumberElements"); - } - - needCacheUpdate = true; + // get resource bundle data + LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale); + // Avoid potential recursions + if (!(adapter instanceof ResourceBundleBasedAdapter)) { + adapter = LocaleProviderAdapter.getResourceBundleBased(); } - + Object[] data = adapter.getLocaleResources(locale).getDecimalFormatSymbolsData(); String[] numberElements = (String[]) data[0]; decimalSeparator = numberElements[0].charAt(0); @@ -618,7 +584,6 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { currencySymbol = currency.getSymbol(locale); data[1] = intlCurrencySymbol; data[2] = currencySymbol; - needCacheUpdate = true; } } else { // default values @@ -633,10 +598,6 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { // standard decimal separator for all locales that we support. // If that changes, add a new entry to NumberElements. monetarySeparator = decimalSeparator; - - if (needCacheUpdate) { - cachedLocaleData.putIfAbsent(locale, data); - } } /** @@ -850,11 +811,4 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { * @since JDK 1.1.6 */ private int serialVersionOnStream = currentSerialVersion; - - /** - * cache to hold the NumberElements and the Currency - * of a Locale. - */ - private static final ConcurrentMap cachedLocaleData - = new ConcurrentHashMap<>(3); } diff --git a/src/share/classes/java/text/NumberFormat.java b/src/share/classes/java/text/NumberFormat.java index e155b81b6..eaed665e5 100644 --- a/src/share/classes/java/text/NumberFormat.java +++ b/src/share/classes/java/text/NumberFormat.java @@ -56,7 +56,6 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.spi.LocaleServiceProvider; import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.LocaleServiceProviderPool; -import sun.util.resources.LocaleData; /** * NumberFormat is the abstract base class for all number diff --git a/src/share/classes/java/util/Locale.java b/src/share/classes/java/util/Locale.java index 9d469e466..198148206 100644 --- a/src/share/classes/java/util/Locale.java +++ b/src/share/classes/java/util/Locale.java @@ -50,7 +50,6 @@ import java.text.MessageFormat; import java.util.spi.LocaleNameProvider; import sun.security.action.GetPropertyAction; -import sun.util.locale.provider.LocaleServiceProviderPool; import sun.util.locale.BaseLocale; import sun.util.locale.InternalLocaleBuilder; import sun.util.locale.LanguageTag; @@ -61,7 +60,9 @@ import sun.util.locale.LocaleSyntaxException; import sun.util.locale.LocaleUtils; import sun.util.locale.ParseStatus; import sun.util.locale.provider.LocaleProviderAdapter; -import sun.util.resources.OpenListResourceBundle; +import sun.util.locale.provider.LocaleResources; +import sun.util.locale.provider.LocaleServiceProviderPool; +import sun.util.locale.provider.ResourceBundleBasedAdapter; /** * A Locale object represents a specific geographical, political, @@ -1779,20 +1780,15 @@ public final class Locale implements Cloneable, Serializable { if (baseLocale.getVariant().length() == 0) return ""; - OpenListResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getLocaleNames(inLocale); + LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(inLocale); - String names[] = getDisplayVariantArray(bundle, inLocale); + String names[] = getDisplayVariantArray(inLocale); // Get the localized patterns for formatting a list, and use // them to format the list. - String listPattern = null; - String listCompositionPattern = null; - try { - listPattern = bundle.getString("ListPattern"); - listCompositionPattern = bundle.getString("ListCompositionPattern"); - } catch (MissingResourceException e) { - } - return formatList(names, listPattern, listCompositionPattern); + return formatList(names, + lr.getLocaleName("ListPattern"), + lr.getLocaleName("ListCompositionPattern")); } /** @@ -1837,23 +1833,17 @@ public final class Locale implements Cloneable, Serializable { * @throws NullPointerException if inLocale is null */ public String getDisplayName(Locale inLocale) { - OpenListResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getLocaleNames(inLocale); + LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(inLocale); String languageName = getDisplayLanguage(inLocale); String scriptName = getDisplayScript(inLocale); String countryName = getDisplayCountry(inLocale); - String[] variantNames = getDisplayVariantArray(bundle, inLocale); + String[] variantNames = getDisplayVariantArray(inLocale); // Get the localized patterns for formatting a display name. - String displayNamePattern = null; - String listPattern = null; - String listCompositionPattern = null; - try { - displayNamePattern = bundle.getString("DisplayNamePattern"); - listPattern = bundle.getString("ListPattern"); - listCompositionPattern = bundle.getString("ListCompositionPattern"); - } catch (MissingResourceException e) { - } + String displayNamePattern = lr.getLocaleName("DisplayNamePattern"); + String listPattern = lr.getLocaleName("ListPattern"); + String listCompositionPattern = lr.getLocaleName("ListCompositionPattern"); // The display name consists of a main name, followed by qualifiers. // Typically, the format is "MainName (Qualifier, Qualifier)" but this @@ -2005,7 +1995,7 @@ public final class Locale implements Cloneable, Serializable { * @param bundle the ResourceBundle to use to get the display names * @return an array of display names, possible of zero length. */ - private String[] getDisplayVariantArray(OpenListResourceBundle bundle, Locale inLocale) { + private String[] getDisplayVariantArray(Locale inLocale) { // Split the variant name into tokens separated by '_'. StringTokenizer tokenizer = new StringTokenizer(baseLocale.getVariant(), "_"); String[] names = new String[tokenizer.countTokens()]; diff --git a/src/share/classes/java/util/TimeZone.java b/src/share/classes/java/util/TimeZone.java index 9d9fbcc8f..d79e201ce 100644 --- a/src/share/classes/java/util/TimeZone.java +++ b/src/share/classes/java/util/TimeZone.java @@ -430,32 +430,7 @@ abstract public class TimeZone implements Serializable, Cloneable { } private static String[] getDisplayNames(String id, Locale locale) { - Map>> displayNames = DisplayNames.CACHE; - - SoftReference> ref = displayNames.get(id); - if (ref != null) { - Map perLocale = ref.get(); - if (perLocale != null) { - String[] names = perLocale.get(locale); - if (names != null) { - return names; - } - names = TimeZoneNameUtility.retrieveDisplayNames(id, locale); - if (names != null) { - perLocale.put(locale, names); - } - return names; - } - } - - String[] names = TimeZoneNameUtility.retrieveDisplayNames(id, locale); - if (names != null) { - Map perLocale = new ConcurrentHashMap<>(); - perLocale.put(locale, names); - ref = new SoftReference<>(perLocale); - displayNames.put(id, ref); - } - return names; + return TimeZoneNameUtility.retrieveDisplayNames(id, locale); } /** diff --git a/src/share/classes/sun/text/resources/zh/CollationData_zh_HK.java b/src/share/classes/sun/text/resources/zh/CollationData_zh_HK.java index c8eeba7e1..6cf5b0dd6 100644 --- a/src/share/classes/sun/text/resources/zh/CollationData_zh_HK.java +++ b/src/share/classes/sun/text/resources/zh/CollationData_zh_HK.java @@ -47,12 +47,13 @@ import java.util.ListResourceBundle; import java.util.Locale; import java.util.ResourceBundle; import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.ResourceBundleBasedAdapter; public class CollationData_zh_HK extends ListResourceBundle { // reparent to zh_TW for traditional Chinese collation sequence public CollationData_zh_HK() { - ResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getCollationData(Locale.TAIWAN); + ResourceBundle bundle = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getCollationData(Locale.TAIWAN); setParent(bundle); } diff --git a/src/share/classes/sun/text/resources/zh/FormatData_zh_HK.java b/src/share/classes/sun/text/resources/zh/FormatData_zh_HK.java index 9e2fd3383..23c3f6e43 100644 --- a/src/share/classes/sun/text/resources/zh/FormatData_zh_HK.java +++ b/src/share/classes/sun/text/resources/zh/FormatData_zh_HK.java @@ -44,12 +44,14 @@ import java.util.ListResourceBundle; import java.util.Locale; import java.util.ResourceBundle; import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.ResourceBundleBasedAdapter; public class FormatData_zh_HK extends ListResourceBundle { // reparent to zh_TW for traditional Chinese names public FormatData_zh_HK() { - ResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getDateFormatData(Locale.TAIWAN); + ResourceBundle bundle = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()) + .getLocaleData().getDateFormatData(Locale.TAIWAN); setParent(bundle); } diff --git a/src/share/classes/sun/util/locale/provider/AuxLocaleProviderAdapter.java b/src/share/classes/sun/util/locale/provider/AuxLocaleProviderAdapter.java index a68a8ba95..78edef1b7 100644 --- a/src/share/classes/sun/util/locale/provider/AuxLocaleProviderAdapter.java +++ b/src/share/classes/sun/util/locale/provider/AuxLocaleProviderAdapter.java @@ -43,7 +43,6 @@ import java.util.spi.CurrencyNameProvider; import java.util.spi.LocaleNameProvider; import java.util.spi.LocaleServiceProvider; import java.util.spi.TimeZoneNameProvider; -import sun.util.resources.LocaleData; /** * An abstract parent class for the @@ -146,11 +145,6 @@ public abstract class AuxLocaleProviderAdapter extends LocaleProviderAdapter { return null; } - @Override - public LocaleData getLocaleData() { - return null; - } - private static Locale[] availableLocales = null; @Override diff --git a/src/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java b/src/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java index 35a8a7c1f..1a611a087 100644 --- a/src/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java +++ b/src/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java @@ -25,12 +25,12 @@ package sun.util.locale.provider; +import java.io.IOException; import java.text.BreakIterator; import java.text.spi.BreakIteratorProvider; import java.util.Locale; -import java.util.ResourceBundle; +import java.util.MissingResourceException; import java.util.Set; -import sun.util.resources.LocaleData; /** * Concrete implementation of the {@link java.text.spi.BreakIteratorProvider @@ -159,24 +159,22 @@ public class BreakIteratorProviderImpl extends BreakIteratorProvider throw new NullPointerException(); } - ResourceBundle bundle = LocaleData.getBundle( - LocaleProviderAdapter.Type.JRE.getTextResourcesPackage() + ".BreakIteratorInfo", locale); - String[] classNames = bundle.getStringArray("BreakIteratorClasses"); - - String dataFile = bundle.getString(dataName); + LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(locale); + String[] classNames = (String[]) lr.getBreakIteratorInfo("BreakIteratorClasses"); + String dataFile = (String) lr.getBreakIteratorInfo(dataName); try { switch (classNames[type]) { case "RuleBasedBreakIterator": return new RuleBasedBreakIterator(dataFile); case "DictionaryBasedBreakIterator": - String dictionaryFile = bundle.getString(dictionaryName); + String dictionaryFile = (String) lr.getBreakIteratorInfo(dictionaryName); return new DictionaryBasedBreakIterator(dataFile, dictionaryFile); default: throw new IllegalArgumentException("Invalid break iterator class \"" + classNames[type] + "\""); } - } catch (Exception e) { + } catch (IOException | MissingResourceException | IllegalArgumentException e) { throw new InternalError(e.toString(), e); } } diff --git a/src/share/classes/sun/util/locale/provider/CalendarDataProviderImpl.java b/src/share/classes/sun/util/locale/provider/CalendarDataProviderImpl.java index 16d08b3cb..136889fbd 100644 --- a/src/share/classes/sun/util/locale/provider/CalendarDataProviderImpl.java +++ b/src/share/classes/sun/util/locale/provider/CalendarDataProviderImpl.java @@ -24,10 +24,7 @@ */ package sun.util.locale.provider; -import java.util.Calendar; -import static java.util.Calendar.*; import java.util.Locale; -import java.util.ResourceBundle; import java.util.Set; import java.util.spi.CalendarDataProvider; @@ -49,12 +46,14 @@ public class CalendarDataProviderImpl extends CalendarDataProvider implements Av @Override public int getFirstDayOfWeek(Locale locale) { - return getIntData(CalendarDataUtility.FIRST_DAY_OF_WEEK, locale); + return LocaleProviderAdapter.forType(type).getLocaleResources(locale) + .getCalendarData(CalendarDataUtility.FIRST_DAY_OF_WEEK); } @Override public int getMinimalDaysInFirstWeek(Locale locale) { - return getIntData(CalendarDataUtility.MINIMAL_DAYS_IN_FIRST_WEEK, locale); + return LocaleProviderAdapter.forType(type).getLocaleResources(locale) + .getCalendarData(CalendarDataUtility.MINIMAL_DAYS_IN_FIRST_WEEK); } @Override @@ -66,13 +65,4 @@ public class CalendarDataProviderImpl extends CalendarDataProvider implements Av public Set getAvailableLanguageTags() { return langtags; } - - private int getIntData(String key, Locale locale) { - ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getCalendarData(locale); - if (rb.containsKey(key)) { - String firstday = rb.getString(key); - return Integer.parseInt(firstday); - } - return 0; - } } diff --git a/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java b/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java index 20be38607..3fe97ddf7 100644 --- a/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java +++ b/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java @@ -28,7 +28,6 @@ import static java.util.Calendar.*; import java.util.Comparator; import java.util.Locale; import java.util.Map; -import java.util.ResourceBundle; import java.util.Set; import java.util.TreeMap; import java.util.spi.CalendarNameProvider; @@ -54,22 +53,19 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av String name = null; String key = getResourceKey(calendarType, field, style); if (key != null) { - ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getDateFormatData(locale); - if (rb.containsKey(key)) { - String[] strings = rb.getStringArray(key); - if (strings.length > 0) { - if (field == DAY_OF_WEEK || field == YEAR) { - --value; - } - name = strings[value]; - // If name is empty in standalone, try its `format' style. - if (name.length() == 0 - && (style == SHORT_STANDALONE || style == LONG_STANDALONE - || style == NARROW_STANDALONE)) { - name = getDisplayName(calendarType, field, value, - getBaseStyle(style), - locale); - } + String[] strings = LocaleProviderAdapter.forType(type).getLocaleResources(locale).getCalendarNames(key); + if (strings != null && strings.length > 0) { + if (field == DAY_OF_WEEK || field == YEAR) { + --value; + } + name = strings[value]; + // If name is empty in standalone, try its `format' style. + if (name.length() == 0 + && (style == SHORT_STANDALONE || style == LONG_STANDALONE + || style == NARROW_STANDALONE)) { + name = getDisplayName(calendarType, field, value, + getBaseStyle(style), + locale); } } } @@ -100,9 +96,8 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av String key = getResourceKey(calendarType, field, style); Map map = new TreeMap<>(LengthBasedComparator.INSTANCE); if (key != null) { - ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getDateFormatData(locale); - if (rb.containsKey(key)) { - String[] strings = rb.getStringArray(key); + String[] strings = LocaleProviderAdapter.forType(type).getLocaleResources(locale).getCalendarNames(key); + if (strings != null) { if (!hasDuplicates(strings)) { if (field == YEAR) { if (strings.length > 0) { diff --git a/src/share/classes/sun/util/locale/provider/CollatorProviderImpl.java b/src/share/classes/sun/util/locale/provider/CollatorProviderImpl.java index ba9ba7be6..3f997cf9b 100644 --- a/src/share/classes/sun/util/locale/provider/CollatorProviderImpl.java +++ b/src/share/classes/sun/util/locale/provider/CollatorProviderImpl.java @@ -45,8 +45,6 @@ import java.text.ParseException; import java.text.RuleBasedCollator; import java.text.spi.CollatorProvider; import java.util.Locale; -import java.util.MissingResourceException; -import java.util.ResourceBundle; import java.util.Set; /** @@ -102,14 +100,7 @@ public class CollatorProviderImpl extends CollatorProvider implements AvailableL // Load the resource of the desired locale from resource // manager. - String colString = ""; - try { - ResourceBundle resource = LocaleProviderAdapter.forType(type).getLocaleData().getCollationData(locale); - - colString = resource.getString("Rule"); - } catch (MissingResourceException e) { - // Use default values - } + String colString = LocaleProviderAdapter.forType(type).getLocaleResources(locale).getCollationData(); try { result = new RuleBasedCollator(CollationRules.DEFAULTRULES + diff --git a/src/share/classes/sun/util/locale/provider/CurrencyNameProviderImpl.java b/src/share/classes/sun/util/locale/provider/CurrencyNameProviderImpl.java index cfa805fdd..6e368bca8 100644 --- a/src/share/classes/sun/util/locale/provider/CurrencyNameProviderImpl.java +++ b/src/share/classes/sun/util/locale/provider/CurrencyNameProviderImpl.java @@ -26,7 +26,6 @@ package sun.util.locale.provider; import java.util.Locale; -import java.util.ResourceBundle; import java.util.Set; import java.util.spi.CurrencyNameProvider; @@ -120,11 +119,6 @@ public class CurrencyNameProviderImpl extends CurrencyNameProvider throw new NullPointerException(); } - ResourceBundle bundle = LocaleProviderAdapter.forType(type).getLocaleData().getCurrencyNames(locale); - if (bundle.containsKey(key)) { - return bundle.getString(key); - } - - return null; + return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getCurrencyName(key); } } diff --git a/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java b/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java index 9f86f7a35..cd33bc214 100644 --- a/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java +++ b/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java @@ -54,7 +54,7 @@ import sun.util.resources.LocaleData; * @author Naoto Sato * @author Masayoshi Okutsu */ -public class JRELocaleProviderAdapter extends LocaleProviderAdapter { +public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements ResourceBundleBasedAdapter { private static final String LOCALE_DATA_JAR_NAME = "localedata.jar"; @@ -296,6 +296,7 @@ public class JRELocaleProviderAdapter extends LocaleProviderAdapter { return lr; } + // ResourceBundleBasedAdapter method implementation @Override public LocaleData getLocaleData() { if (localeData == null) { diff --git a/src/share/classes/sun/util/locale/provider/LocaleNameProviderImpl.java b/src/share/classes/sun/util/locale/provider/LocaleNameProviderImpl.java index 952078fd5..16f71b115 100644 --- a/src/share/classes/sun/util/locale/provider/LocaleNameProviderImpl.java +++ b/src/share/classes/sun/util/locale/provider/LocaleNameProviderImpl.java @@ -26,7 +26,6 @@ package sun.util.locale.provider; import java.util.Locale; -import java.util.ResourceBundle; import java.util.Set; import java.util.spi.LocaleNameProvider; @@ -174,12 +173,7 @@ public class LocaleNameProviderImpl extends LocaleNameProvider implements Availa throw new NullPointerException(); } - ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getLocaleNames(locale); - if (rb.containsKey(key)) { - return rb.getString(key); - } - - return null; + return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getLocaleName(key); } @Override diff --git a/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java b/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java index 17f5c0999..2f12f6540 100644 --- a/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java +++ b/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java @@ -37,6 +37,8 @@ import java.util.List; import java.util.Locale; import java.util.ResourceBundle; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.spi.CalendarDataProvider; import java.util.spi.CalendarNameProvider; import java.util.spi.CurrencyNameProvider; @@ -44,7 +46,6 @@ import java.util.spi.LocaleNameProvider; import java.util.spi.LocaleServiceProvider; import java.util.spi.TimeZoneNameProvider; import sun.util.cldr.CLDRLocaleProviderAdapter; -import sun.util.resources.LocaleData; /** * The LocaleProviderAdapter abstract class. @@ -119,6 +120,12 @@ public abstract class LocaleProviderAdapter { */ private static LocaleProviderAdapter fallbackLocaleProviderAdapter = null; + /** + * Adapter lookup cache. + */ + private static ConcurrentMap, ConcurrentMap> + adapterCache = new ConcurrentHashMap<>(); + static { String order = AccessController.doPrivileged( new sun.security.action.GetPropertyAction("java.locale.providers")); @@ -210,9 +217,23 @@ public abstract class LocaleProviderAdapter { */ public static LocaleProviderAdapter getAdapter(Class providerClass, Locale locale) { + LocaleProviderAdapter adapter; + + // cache lookup + ConcurrentMap adapterMap = adapterCache.get(providerClass); + if (adapterMap != null) { + if ((adapter = adapterMap.get(locale)) != null) { + return adapter; + } + } else { + adapterMap = new ConcurrentHashMap<>(); + adapterCache.putIfAbsent(providerClass, adapterMap); + } + // Fast look-up for the given locale - LocaleProviderAdapter adapter = findAdapter(providerClass, locale); + adapter = findAdapter(providerClass, locale); if (adapter != null) { + adapterMap.putIfAbsent(locale, adapter); return adapter; } @@ -226,11 +247,13 @@ public abstract class LocaleProviderAdapter { } adapter = findAdapter(providerClass, loc); if (adapter != null) { + adapterMap.putIfAbsent(locale, adapter); return adapter; } } // returns the adapter for FALLBACK as the last resort + adapterMap.putIfAbsent(locale, fallbackLocaleProviderAdapter); return fallbackLocaleProviderAdapter; } @@ -398,7 +421,5 @@ public abstract class LocaleProviderAdapter { public abstract LocaleResources getLocaleResources(Locale locale); - public abstract LocaleData getLocaleData(); - public abstract Locale[] getAvailableLocales(); } diff --git a/src/share/classes/sun/util/locale/provider/LocaleResources.java b/src/share/classes/sun/util/locale/provider/LocaleResources.java index ff389f61b..fa7d49967 100644 --- a/src/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/src/share/classes/sun/util/locale/provider/LocaleResources.java @@ -40,43 +40,295 @@ package sun.util.locale.provider; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; import java.text.MessageFormat; import java.util.Calendar; +import java.util.LinkedHashSet; import java.util.Locale; +import java.util.Map; import java.util.ResourceBundle; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import sun.util.calendar.ZoneInfo; +import sun.util.resources.LocaleData; +import sun.util.resources.OpenListResourceBundle; import sun.util.resources.TimeZoneNamesBundle; /** - * Central accessor to locale-dependent resources. + * Central accessor to locale-dependent resources for JRE/CLDR provider adapters. * * @author Masayoshi Okutsu + * @author Naoto Sato */ public class LocaleResources { - private final LocaleProviderAdapter adapter; private final Locale locale; + private final LocaleData localeData; + private final LocaleProviderAdapter.Type type; // Resource cache - private ConcurrentMap cache = new ConcurrentHashMap<>(); + private ConcurrentMap cache = new ConcurrentHashMap<>(); + private ReferenceQueue referenceQueue = new ReferenceQueue<>(); + // cache key prefixes + private static final String BREAK_ITERATOR_INFO = "BII."; + private static final String CALENDAR_DATA = "CALD."; + private static final String COLLATION_DATA_CACHEKEY = "COLD"; + private static final String DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY = "DFSD"; + private static final String CURRENCY_NAMES = "CN."; + private static final String LOCALE_NAMES = "LN."; + private static final String TIME_ZONE_NAMES = "TZN."; + private static final String ZONE_IDS_CACHEKEY = "ZID"; + private static final String CALENDAR_NAMES = "CALN."; + private static final String NUMBER_PATTERNS_CACHEKEY = "NP"; + private static final String DATE_TIME_PATTERN = "DTP."; - LocaleResources(LocaleProviderAdapter adapter, Locale locale) { - this.adapter = adapter; + // null singleton cache value + private static final Object NULLOBJECT = new Object(); + + LocaleResources(ResourceBundleBasedAdapter adapter, Locale locale) { this.locale = locale; + this.localeData = adapter.getLocaleData(); + type = ((LocaleProviderAdapter)adapter).getAdapterType(); + } + + private void removeEmptyReferences() { + Object ref; + while ((ref = referenceQueue.poll()) != null) { + cache.remove(((ResourceReference)ref).getCacheKey()); + } + } + + Object getBreakIteratorInfo(String key) { + Object biInfo; + String cacheKey = BREAK_ITERATOR_INFO + key; + + removeEmptyReferences(); + ResourceReference data = cache.get(cacheKey); + if (data == null || ((biInfo = data.get()) == null)) { + biInfo = localeData.getBreakIteratorInfo(locale).getObject(key); + cache.put(cacheKey, new ResourceReference(cacheKey, biInfo, referenceQueue)); + } + + return biInfo; + } + + int getCalendarData(String key) { + Integer caldata; + String cacheKey = CALENDAR_DATA + key; + + removeEmptyReferences(); + + ResourceReference data = cache.get(cacheKey); + if (data == null || ((caldata = (Integer) data.get()) == null)) { + ResourceBundle rb = localeData.getCalendarData(locale); + if (rb.containsKey(key)) { + caldata = Integer.parseInt(rb.getString(key)); + } else { + caldata = 0; + } + + cache.put(cacheKey, + new ResourceReference(cacheKey, (Object) caldata, referenceQueue)); + } + + return caldata; } - public TimeZoneNamesBundle getTimeZoneNames() { - TimeZoneNamesBundle tznames = (TimeZoneNamesBundle) cache.get("TimeZoneNames"); - if (tznames == null) { - tznames = adapter.getLocaleData().getTimeZoneNames(locale); - TimeZoneNamesBundle tznb = (TimeZoneNamesBundle) cache.putIfAbsent("TimeZoneNames", tznames); - if (tznb != null) { - tznames = tznb; + public String getCollationData() { + String key = "Rule"; + String coldata = ""; + + removeEmptyReferences(); + ResourceReference data = cache.get(COLLATION_DATA_CACHEKEY); + if (data == null || ((coldata = (String) data.get()) == null)) { + ResourceBundle rb = localeData.getCollationData(locale); + if (rb.containsKey(key)) { + coldata = rb.getString(key); } + cache.put(COLLATION_DATA_CACHEKEY, + new ResourceReference(COLLATION_DATA_CACHEKEY, (Object) coldata, referenceQueue)); } - return tznames; + + return coldata; + } + + public Object[] getDecimalFormatSymbolsData() { + Object[] dfsdata; + + removeEmptyReferences(); + ResourceReference data = cache.get(DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY); + if (data == null || ((dfsdata = (Object[]) data.get()) == null)) { + // Note that only dfsdata[0] is prepared here in this method. Other + // elements are provided by the caller, yet they are cached here. + ResourceBundle rb = localeData.getNumberFormatData(locale); + dfsdata = new Object[3]; + + // NumberElements look up. First, try the Unicode extension + String numElemKey; + String numberType = locale.getUnicodeLocaleType("nu"); + if (numberType != null) { + numElemKey = numberType + ".NumberElements"; + if (rb.containsKey(numElemKey)) { + dfsdata[0] = rb.getStringArray(numElemKey); + } + } + + // Next, try DefaultNumberingSystem value + if (dfsdata[0] == null && rb.containsKey("DefaultNumberingSystem")) { + numElemKey = rb.getString("DefaultNumberingSystem") + ".NumberElements"; + if (rb.containsKey(numElemKey)) { + dfsdata[0] = rb.getStringArray(numElemKey); + } + } + + // Last resort. No need to check the availability. + // Just let it throw MissingResourceException when needed. + if (dfsdata[0] == null) { + dfsdata[0] = rb.getStringArray("NumberElements"); + } + + cache.put(DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY, + new ResourceReference(DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY, (Object) dfsdata, referenceQueue)); + } + + return dfsdata; + } + + public String getCurrencyName(String key) { + Object currencyName = null; + String cacheKey = CURRENCY_NAMES + key; + + removeEmptyReferences(); + ResourceReference data = cache.get(cacheKey); + + if (data != null && ((currencyName = data.get()) != null)) { + if (currencyName.equals(NULLOBJECT)) { + currencyName = null; + } + + return (String) currencyName; + } + + OpenListResourceBundle olrb = localeData.getCurrencyNames(locale); + + if (olrb.containsKey(key)) { + currencyName = olrb.getObject(key); + cache.put(cacheKey, + new ResourceReference(cacheKey, currencyName, referenceQueue)); + } + + return (String) currencyName; + } + + public String getLocaleName(String key) { + Object localeName = null; + String cacheKey = LOCALE_NAMES + key; + + removeEmptyReferences(); + ResourceReference data = cache.get(cacheKey); + + if (data != null && ((localeName = data.get()) != null)) { + if (localeName.equals(NULLOBJECT)) { + localeName = null; + } + + return (String) localeName; + } + + OpenListResourceBundle olrb = localeData.getLocaleNames(locale); + + if (olrb.containsKey(key)) { + localeName = olrb.getObject(key); + cache.put(cacheKey, + new ResourceReference(cacheKey, localeName, referenceQueue)); + } + + return (String) localeName; + } + + String[] getTimeZoneNames(String key, int size) { + String[] names = null; + String cacheKey = TIME_ZONE_NAMES + key; + + removeEmptyReferences(); + ResourceReference data = cache.get(cacheKey); + + if (data == null || ((names = (String[]) data.get()) == null)) { + TimeZoneNamesBundle tznb = localeData.getTimeZoneNames(locale); + if (tznb.containsKey(key)) { + names = tznb.getStringArray(key, size); + cache.put(cacheKey, + new ResourceReference(cacheKey, (Object) names, referenceQueue)); + } + } + + return names; + } + + @SuppressWarnings("unchecked") + Set getZoneIDs() { + Set zoneIDs = null; + + removeEmptyReferences(); + ResourceReference data = cache.get(ZONE_IDS_CACHEKEY); + if (data == null || ((zoneIDs = (Set) data.get()) == null)) { + TimeZoneNamesBundle rb = localeData.getTimeZoneNames(locale); + zoneIDs = rb.keySet(); + cache.put(ZONE_IDS_CACHEKEY, + new ResourceReference(ZONE_IDS_CACHEKEY, (Object) zoneIDs, referenceQueue)); + } + + return zoneIDs; + } + + // zoneStrings are cached separately in TimeZoneNameUtility. + String[][] getZoneStrings() { + TimeZoneNamesBundle rb = localeData.getTimeZoneNames(locale); + Set keyset = getZoneIDs(); + // Use a LinkedHashSet to preseve the order + Set value = new LinkedHashSet<>(); + for (String key : keyset) { + value.add(rb.getStringArray(key)); + } + + // Add aliases data for CLDR + if (type == LocaleProviderAdapter.Type.CLDR) { + // Note: TimeZoneNamesBundle creates a String[] on each getStringArray call. + Map aliases = ZoneInfo.getAliasTable(); + for (String alias : aliases.keySet()) { + if (!keyset.contains(alias)) { + String tzid = aliases.get(alias); + if (keyset.contains(tzid)) { + String[] val = rb.getStringArray(tzid); + val[0] = alias; + value.add(val); + } + } + } + } + return value.toArray(new String[0][]); + } + + String[] getCalendarNames(String key) { + String[] names = null; + String cacheKey = CALENDAR_NAMES + key; + + removeEmptyReferences(); + ResourceReference data = cache.get(cacheKey); + + if (data == null || ((names = (String[]) data.get()) == null)) { + ResourceBundle rb = localeData.getDateFormatData(locale); + if (rb.containsKey(key)) { + names = rb.getStringArray(key); + cache.put(cacheKey, + new ResourceReference(cacheKey, (Object) names, referenceQueue)); + } + } + + return names; } public String getDateTimePattern(int timeStyle, int dateStyle, Calendar cal) { @@ -120,32 +372,54 @@ public class LocaleResources { } public String[] getNumberPatterns() { - /* try the cache first */ - String[] numberPatterns = (String[]) cache.get("NumberPatterns"); - if (numberPatterns == null) { /* cache miss */ - ResourceBundle resource = adapter.getLocaleData().getNumberFormatData(locale); + String[] numberPatterns = null; + + removeEmptyReferences(); + ResourceReference data = cache.get(NUMBER_PATTERNS_CACHEKEY); + + if (data == null || ((numberPatterns = (String[]) data.get()) == null)) { + ResourceBundle resource = localeData.getNumberFormatData(locale); numberPatterns = resource.getStringArray("NumberPatterns"); - /* update cache */ - cache.put("NumberPatterns", numberPatterns); + cache.put(NUMBER_PATTERNS_CACHEKEY, + new ResourceReference(NUMBER_PATTERNS_CACHEKEY, (Object) numberPatterns, referenceQueue)); } + return numberPatterns; } private String getDateTimePattern(String key, int styleIndex, String calendarType) { String resourceKey = "gregory".equals(calendarType) ? key : calendarType + "." + key; - /* try the cache first */ - String[] patterns = (String[]) cache.get(resourceKey); - if (patterns == null) { /* cache miss */ - ResourceBundle r = adapter.getLocaleData().getDateFormatData(locale); + String cacheKey = DATE_TIME_PATTERN + resourceKey; + String[] patterns = null; + + removeEmptyReferences(); + ResourceReference data = cache.get(cacheKey); + + if (data == null || ((patterns = (String[]) data.get()) == null)) { + ResourceBundle r = localeData.getDateFormatData(locale); if (r.containsKey(resourceKey)) { patterns = r.getStringArray(resourceKey); } else { assert !resourceKey.equals(key); patterns = r.getStringArray(key); } - /* update cache */ - cache.putIfAbsent(resourceKey, patterns); + cache.put(cacheKey, + new ResourceReference(cacheKey, (Object) patterns, referenceQueue)); } + return patterns[styleIndex]; } + + private static class ResourceReference extends SoftReference { + private final String cacheKey; + + ResourceReference(String cacheKey, Object o, ReferenceQueue q) { + super(o, q); + this.cacheKey = cacheKey; + } + + String getCacheKey() { + return cacheKey; + } + } } diff --git a/src/share/classes/sun/util/locale/provider/ResourceBundleBasedAdapter.java b/src/share/classes/sun/util/locale/provider/ResourceBundleBasedAdapter.java new file mode 100644 index 000000000..7046c2e0a --- /dev/null +++ b/src/share/classes/sun/util/locale/provider/ResourceBundleBasedAdapter.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.util.locale.provider; + +import sun.util.resources.LocaleData; + +/** + * Accessor for LocaleData + * + * @author Naoto Sato + */ +public interface ResourceBundleBasedAdapter { + public LocaleData getLocaleData(); +} diff --git a/src/share/classes/sun/util/locale/provider/TimeZoneNameProviderImpl.java b/src/share/classes/sun/util/locale/provider/TimeZoneNameProviderImpl.java index 28fd7af5a..96cb5ef7b 100644 --- a/src/share/classes/sun/util/locale/provider/TimeZoneNameProviderImpl.java +++ b/src/share/classes/sun/util/locale/provider/TimeZoneNameProviderImpl.java @@ -25,14 +25,10 @@ package sun.util.locale.provider; -import java.util.LinkedHashSet; import java.util.Locale; -import java.util.Map; import java.util.Set; import java.util.TimeZone; import java.util.spi.TimeZoneNameProvider; -import sun.util.calendar.ZoneInfo; -import sun.util.resources.TimeZoneNamesBundle; /** * Concrete implementation of the @@ -123,9 +119,7 @@ public class TimeZoneNameProviderImpl extends TimeZoneNameProvider { if (id == null || locale == null) { throw new NullPointerException(); } - LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type); - TimeZoneNamesBundle rb = adapter.getLocaleResources(locale).getTimeZoneNames(); - return rb.containsKey(id) ? rb.getStringArray(id, n) : null; + return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getTimeZoneNames(id, n); } /** @@ -136,30 +130,6 @@ public class TimeZoneNameProviderImpl extends TimeZoneNameProvider { * @return an array of time zone names arrays */ String[][] getZoneStrings(Locale locale) { - LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type); - TimeZoneNamesBundle rb = adapter.getLocaleResources(locale).getTimeZoneNames(); - Set keyset = rb.keySet(); - // Use a LinkedHashSet to preseve the order - Set value = new LinkedHashSet<>(); - for (String key : keyset) { - value.add(rb.getStringArray(key)); - } - - // Add aliases data for CLDR - if (type == LocaleProviderAdapter.Type.CLDR) { - // Note: TimeZoneNamesBundle creates a String[] on each getStringArray call. - Map aliases = ZoneInfo.getAliasTable(); - for (String alias : aliases.keySet()) { - if (!keyset.contains(alias)) { - String tzid = aliases.get(alias); - if (keyset.contains(tzid)) { - String[] val = rb.getStringArray(tzid); - val[0] = alias; - value.add(val); - } - } - } - } - return value.toArray(new String[0][]); + return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getZoneStrings(); } } diff --git a/src/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java b/src/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java index a8e09a0d6..8c279c1d9 100644 --- a/src/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java +++ b/src/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java @@ -30,11 +30,10 @@ import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.spi.TimeZoneNameProvider; import sun.util.calendar.ZoneInfo; -import sun.util.resources.OpenListResourceBundle; -import sun.util.resources.TimeZoneNamesBundle; /** * Utility class that deals with the localized time zone names @@ -45,15 +44,17 @@ import sun.util.resources.TimeZoneNamesBundle; public final class TimeZoneNameUtility { /** - * cache to hold time zone resource bundles. Keyed by Locale + * cache to hold time zone localized strings. Keyed by Locale */ - private static ConcurrentHashMap> cachedBundles = + private static ConcurrentHashMap> cachedZoneData = new ConcurrentHashMap<>(); /** - * cache to hold time zone localized strings. Keyed by Locale + * Cache for managing display names per timezone per locale + * The structure is: + * Map(key=id, value=SoftReference(Map(key=locale, value=displaynames))) */ - private static ConcurrentHashMap> cachedZoneData = + private static final Map>> cachedDisplayNames = new ConcurrentHashMap<>(); /** @@ -82,9 +83,9 @@ public final class TimeZoneNameUtility { } // Performs per-ID retrieval. + Set zoneIDs = LocaleProviderAdapter.forJRE().getLocaleResources(locale).getZoneIDs(); List zones = new LinkedList<>(); - OpenListResourceBundle rb = getBundle(locale); - for (String key : rb.keySet()) { + for (String key : zoneIDs) { String[] names = retrieveDisplayNamesImpl(key, locale); if (names != null) { zones.add(names); @@ -137,20 +138,31 @@ public final class TimeZoneNameUtility { private static String[] retrieveDisplayNamesImpl(String id, Locale locale) { LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class); - return pool.getLocalizedObject(TimeZoneNameArrayGetter.INSTANCE, locale, id); - } - private static TimeZoneNamesBundle getBundle(Locale locale) { - TimeZoneNamesBundle rb; - SoftReference data = cachedBundles.get(locale); - - if (data == null || ((rb = data.get()) == null)) { - rb = LocaleProviderAdapter.forJRE().getLocaleData().getTimeZoneNames(locale); - data = new SoftReference<>(rb); - cachedBundles.put(locale, data); + SoftReference> ref = cachedDisplayNames.get(id); + if (ref != null) { + Map perLocale = ref.get(); + if (perLocale != null) { + String[] names = perLocale.get(locale); + if (names != null) { + return names; + } + names = pool.getLocalizedObject(TimeZoneNameArrayGetter.INSTANCE, locale, id); + if (names != null) { + perLocale.put(locale, names); + } + return names; + } } - return rb; + String[] names = pool.getLocalizedObject(TimeZoneNameArrayGetter.INSTANCE, locale, id); + if (names != null) { + Map perLocale = new ConcurrentHashMap<>(); + perLocale.put(locale, names); + ref = new SoftReference<>(perLocale); + cachedDisplayNames.put(id, ref); + } + return names; } /** diff --git a/src/share/classes/sun/util/resources/LocaleData.java b/src/share/classes/sun/util/resources/LocaleData.java index 9a7a7c401..fd9ab9e4a 100644 --- a/src/share/classes/sun/util/resources/LocaleData.java +++ b/src/share/classes/sun/util/resources/LocaleData.java @@ -98,6 +98,14 @@ public class LocaleData { return (TimeZoneNamesBundle) getBundle(type.getUtilResourcesPackage() + ".TimeZoneNames", locale); } + /** + * Gets a break iterator info resource bundle, using privileges + * to allow accessing a sun.* package. + */ + public ResourceBundle getBreakIteratorInfo(Locale locale) { + return getBundle(type.getTextResourcesPackage() + ".BreakIteratorInfo", locale); + } + /** * Gets a collation data resource bundle, using privileges * to allow accessing a sun.* package. diff --git a/src/share/classes/sun/util/resources/zh/CurrencyNames_zh_HK.java b/src/share/classes/sun/util/resources/zh/CurrencyNames_zh_HK.java index 950e9ba3a..d3fae4bb9 100644 --- a/src/share/classes/sun/util/resources/zh/CurrencyNames_zh_HK.java +++ b/src/share/classes/sun/util/resources/zh/CurrencyNames_zh_HK.java @@ -80,13 +80,14 @@ package sun.util.resources.zh; import java.util.Locale; import java.util.ResourceBundle; import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.ResourceBundleBasedAdapter; import sun.util.resources.OpenListResourceBundle; public final class CurrencyNames_zh_HK extends OpenListResourceBundle { // reparent to zh_TW for traditional Chinese names public CurrencyNames_zh_HK() { - ResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getCurrencyNames(Locale.TAIWAN); + ResourceBundle bundle = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getCurrencyNames(Locale.TAIWAN); setParent(bundle); } diff --git a/src/share/classes/sun/util/resources/zh/CurrencyNames_zh_SG.java b/src/share/classes/sun/util/resources/zh/CurrencyNames_zh_SG.java index b796db257..16778ffde 100644 --- a/src/share/classes/sun/util/resources/zh/CurrencyNames_zh_SG.java +++ b/src/share/classes/sun/util/resources/zh/CurrencyNames_zh_SG.java @@ -28,13 +28,14 @@ package sun.util.resources.zh; import java.util.Locale; import java.util.ResourceBundle; import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.ResourceBundleBasedAdapter; import sun.util.resources.OpenListResourceBundle; public final class CurrencyNames_zh_SG extends OpenListResourceBundle { // reparent to zh_CN for simplified Chinese names public CurrencyNames_zh_SG() { - ResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getCurrencyNames(Locale.CHINA); + ResourceBundle bundle = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getCurrencyNames(Locale.CHINA); setParent(bundle); } diff --git a/src/share/classes/sun/util/resources/zh/LocaleNames_zh_HK.java b/src/share/classes/sun/util/resources/zh/LocaleNames_zh_HK.java index fe48363c5..6609a3fdb 100644 --- a/src/share/classes/sun/util/resources/zh/LocaleNames_zh_HK.java +++ b/src/share/classes/sun/util/resources/zh/LocaleNames_zh_HK.java @@ -28,13 +28,14 @@ package sun.util.resources.zh; import java.util.Locale; import java.util.ResourceBundle; import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.ResourceBundleBasedAdapter; import sun.util.resources.OpenListResourceBundle; public final class LocaleNames_zh_HK extends OpenListResourceBundle { // reparent to zh_TW for traditional Chinese names public LocaleNames_zh_HK() { - ResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getLocaleNames(Locale.TAIWAN); + ResourceBundle bundle = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getLocaleNames(Locale.TAIWAN); setParent(bundle); } diff --git a/src/share/classes/sun/util/resources/zh/TimeZoneNames_zh_HK.java b/src/share/classes/sun/util/resources/zh/TimeZoneNames_zh_HK.java index 603be5fb2..9694c70b3 100644 --- a/src/share/classes/sun/util/resources/zh/TimeZoneNames_zh_HK.java +++ b/src/share/classes/sun/util/resources/zh/TimeZoneNames_zh_HK.java @@ -41,13 +41,14 @@ package sun.util.resources.zh; import java.util.Locale; import java.util.ResourceBundle; import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.ResourceBundleBasedAdapter; import sun.util.resources.TimeZoneNamesBundle; public final class TimeZoneNames_zh_HK extends TimeZoneNamesBundle { // reparent to zh_TW for traditional Chinese names public TimeZoneNames_zh_HK() { - ResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getTimeZoneNames(Locale.TAIWAN); + ResourceBundle bundle = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getTimeZoneNames(Locale.TAIWAN); setParent(bundle); } diff --git a/test/java/util/PluggableLocale/BreakIteratorProviderTest.java b/test/java/util/PluggableLocale/BreakIteratorProviderTest.java index 160f9fbcb..31ef767ef 100644 --- a/test/java/util/PluggableLocale/BreakIteratorProviderTest.java +++ b/test/java/util/PluggableLocale/BreakIteratorProviderTest.java @@ -67,8 +67,7 @@ public class BreakIteratorProviderTest extends ProviderTest { for (Locale target: availloc) { // pure JRE implementation - ResourceBundle rb = LocaleProviderAdapter.forJRE().getLocaleData().getBundle( - "sun.text.resources.BreakIteratorInfo", target); + ResourceBundle rb = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getBreakIteratorInfo(target); String[] classNames = rb.getStringArray("BreakIteratorClasses"); boolean jreSupportsLocale = jreimplloc.contains(target); diff --git a/test/java/util/PluggableLocale/CollatorProviderTest.java b/test/java/util/PluggableLocale/CollatorProviderTest.java index 718f1658e..c82f6e4c8 100644 --- a/test/java/util/PluggableLocale/CollatorProviderTest.java +++ b/test/java/util/PluggableLocale/CollatorProviderTest.java @@ -67,7 +67,7 @@ public class CollatorProviderTest extends ProviderTest { for (String tag : ((AvailableLanguageTags)LocaleProviderAdapter.forJRE().getCollatorProvider()).getAvailableLanguageTags()) { jreimplloc.add(Locale.forLanguageTag(tag)); } - ResourceBundle rb = LocaleProviderAdapter.forJRE().getLocaleData().getCollationData(target); + ResourceBundle rb = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getCollationData(target); boolean jreSupportsLocale = jreimplloc.contains(target); // result object diff --git a/test/java/util/PluggableLocale/CurrencyNameProviderTest.java b/test/java/util/PluggableLocale/CurrencyNameProviderTest.java index ebffc3f4f..b4cfaae38 100644 --- a/test/java/util/PluggableLocale/CurrencyNameProviderTest.java +++ b/test/java/util/PluggableLocale/CurrencyNameProviderTest.java @@ -58,7 +58,7 @@ public class CurrencyNameProviderTest extends ProviderTest { for (Locale target: availloc) { // pure JRE implementation - OpenListResourceBundle rb = (OpenListResourceBundle)LocaleProviderAdapter.forJRE().getLocaleData().getCurrencyNames(target); + OpenListResourceBundle rb = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getCurrencyNames(target); boolean jreSupportsTarget = jreimplloc.contains(target); for (Locale test: testloc) { diff --git a/test/java/util/PluggableLocale/DateFormatProviderTest.java b/test/java/util/PluggableLocale/DateFormatProviderTest.java index d49b25b6a..31ced5884 100644 --- a/test/java/util/PluggableLocale/DateFormatProviderTest.java +++ b/test/java/util/PluggableLocale/DateFormatProviderTest.java @@ -84,7 +84,7 @@ public class DateFormatProviderTest extends ProviderTest { break; } // pure JRE implementation - ResourceBundle rb = LocaleProviderAdapter.forJRE().getLocaleData().getDateFormatData(target); + ResourceBundle rb = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getDateFormatData(target); boolean jreSupportsLocale = jreimplloc.contains(target); // JRE string arrays diff --git a/test/java/util/PluggableLocale/DateFormatSymbolsProviderTest.java b/test/java/util/PluggableLocale/DateFormatSymbolsProviderTest.java index ef07f7e3f..f7a89b032 100644 --- a/test/java/util/PluggableLocale/DateFormatSymbolsProviderTest.java +++ b/test/java/util/PluggableLocale/DateFormatSymbolsProviderTest.java @@ -62,7 +62,7 @@ public class DateFormatSymbolsProviderTest extends ProviderTest { for (Locale target: availloc) { // pure JRE implementation - ResourceBundle rb = LocaleProviderAdapter.forJRE().getLocaleData().getDateFormatData(target); + ResourceBundle rb = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getDateFormatData(target); boolean jreSupportsLocale = jreimplloc.contains(target); // JRE string arrays diff --git a/test/java/util/PluggableLocale/DecimalFormatSymbolsProviderTest.java b/test/java/util/PluggableLocale/DecimalFormatSymbolsProviderTest.java index 7d25542d6..6753590ed 100644 --- a/test/java/util/PluggableLocale/DecimalFormatSymbolsProviderTest.java +++ b/test/java/util/PluggableLocale/DecimalFormatSymbolsProviderTest.java @@ -61,17 +61,15 @@ public class DecimalFormatSymbolsProviderTest extends ProviderTest { for (Locale target: availloc) { // pure JRE implementation - ResourceBundle rb = LocaleProviderAdapter.forJRE().getLocaleData().getNumberFormatData(target); + Object[] data = LocaleProviderAdapter.forJRE().getLocaleResources(target).getDecimalFormatSymbolsData(); boolean jreSupportsLocale = jreimplloc.contains(target); // JRE string arrays String[] jres = new String[2]; if (jreSupportsLocale) { - try { - String[] tmp = rb.getStringArray("NumberElements"); - jres[0] = tmp[9]; // infinity - jres[1] = tmp[10]; // NaN - } catch (MissingResourceException mre) {} + String[] tmp = (String[]) data[0]; + jres[0] = tmp[9]; // infinity + jres[1] = tmp[10]; // NaN } // result object diff --git a/test/java/util/PluggableLocale/LocaleNameProviderTest.java b/test/java/util/PluggableLocale/LocaleNameProviderTest.java index c82fab0a5..c7ec9dcd4 100644 --- a/test/java/util/PluggableLocale/LocaleNameProviderTest.java +++ b/test/java/util/PluggableLocale/LocaleNameProviderTest.java @@ -49,7 +49,7 @@ public class LocaleNameProviderTest extends ProviderTest { for (Locale target: availloc) { // pure JRE implementation - OpenListResourceBundle rb = LocaleProviderAdapter.forJRE().getLocaleData().getLocaleNames(target); + OpenListResourceBundle rb = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getLocaleNames(target); boolean jreSupportsTarget = jreimplloc.contains(target); for (Locale test: testloc) { diff --git a/test/java/util/PluggableLocale/NumberFormatProviderTest.java b/test/java/util/PluggableLocale/NumberFormatProviderTest.java index 13f63fd70..ecb45ad7c 100644 --- a/test/java/util/PluggableLocale/NumberFormatProviderTest.java +++ b/test/java/util/PluggableLocale/NumberFormatProviderTest.java @@ -63,16 +63,12 @@ public class NumberFormatProviderTest extends ProviderTest { void objectValidityTest() { for (Locale target: availloc) { - // pure JRE implementation - ResourceBundle rb = LocaleProviderAdapter.forJRE().getLocaleData().getNumberFormatData(target); boolean jreSupportsLocale = jreimplloc.contains(target); // JRE string arrays String[] jreNumberPatterns = null; if (jreSupportsLocale) { - try { - jreNumberPatterns = rb.getStringArray("NumberPatterns"); - } catch (MissingResourceException mre) {} + jreNumberPatterns = LocaleProviderAdapter.forJRE().getLocaleResources(target).getNumberPatterns(); } // result object diff --git a/test/java/util/PluggableLocale/TimeZoneNameProviderTest.java b/test/java/util/PluggableLocale/TimeZoneNameProviderTest.java index 7ed2fc114..29be59a64 100644 --- a/test/java/util/PluggableLocale/TimeZoneNameProviderTest.java +++ b/test/java/util/PluggableLocale/TimeZoneNameProviderTest.java @@ -52,7 +52,7 @@ public class TimeZoneNameProviderTest extends ProviderTest { for (Locale target: available) { // pure JRE implementation - OpenListResourceBundle rb = LocaleProviderAdapter.forJRE().getLocaleData().getTimeZoneNames(target); + OpenListResourceBundle rb = ((ResourceBundleBasedAdapter)LocaleProviderAdapter.forJRE()).getLocaleData().getTimeZoneNames(target); boolean jreSupportsTarget = jreimplloc.contains(target); for (String id: ids) { -- GitLab