src/share/classes/sun/util/locale/provider/LocaleResources.java

Print this page
rev 6352 : imported patch 7162007

*** 38,86 **** * */ package sun.util.locale.provider; import java.text.MessageFormat; import java.util.Calendar; import java.util.Locale; import java.util.ResourceBundle; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import sun.util.resources.TimeZoneNamesBundle; /** ! * Central accessor to locale-dependent resources. * * @author Masayoshi Okutsu */ public class LocaleResources { - private final LocaleProviderAdapter adapter; private final Locale locale; // Resource cache ! private ConcurrentMap<String, Object> cache = new ConcurrentHashMap<>(); ! LocaleResources(LocaleProviderAdapter adapter, Locale locale) { ! this.adapter = adapter; this.locale = locale; } ! 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; } } ! return tznames; } public String getDateTimePattern(int timeStyle, int dateStyle, Calendar cal) { String pattern; if (cal == null) { cal = Calendar.getInstance(locale); --- 38,338 ---- * */ 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 for JRE/CLDR provider adapters. * * @author Masayoshi Okutsu + * @author Naoto Sato */ public class LocaleResources { private final Locale locale; + private final LocaleData localeData; + private final LocaleProviderAdapter.Type type; // Resource cache ! private ConcurrentMap<String, ResourceReference> cache = new ConcurrentHashMap<>(); ! private ReferenceQueue<Object> 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."; ! // 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 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 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<String> getZoneIDs() { + Set<String> zoneIDs = null; + + removeEmptyReferences(); + ResourceReference data = cache.get(ZONE_IDS_CACHEKEY); + if (data == null || ((zoneIDs = (Set<String>) 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<String> keyset = getZoneIDs(); + // Use a LinkedHashSet to preseve the order + Set<String[]> 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<String, String> 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) { String pattern; if (cal == null) { cal = Calendar.getInstance(locale);
*** 118,151 **** } return pattern; } public String[] getNumberPatterns() { ! /* try the cache first */ ! String[] numberPatterns = (String[]) cache.get("NumberPatterns"); ! if (numberPatterns == null) { /* cache miss */ ! ResourceBundle resource = adapter.getLocaleData().getNumberFormatData(locale); numberPatterns = resource.getStringArray("NumberPatterns"); ! /* update cache */ ! cache.put("NumberPatterns", numberPatterns); } 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); if (r.containsKey(resourceKey)) { patterns = r.getStringArray(resourceKey); } else { assert !resourceKey.equals(key); patterns = r.getStringArray(key); } ! /* update cache */ ! cache.putIfAbsent(resourceKey, patterns); } return patterns[styleIndex]; } } --- 370,425 ---- } return pattern; } public String[] getNumberPatterns() { ! 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"); ! 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; ! 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); } ! cache.put(cacheKey, ! new ResourceReference(cacheKey, (Object) patterns, referenceQueue)); } + return patterns[styleIndex]; } + + private static class ResourceReference extends SoftReference<Object> { + private final String cacheKey; + + ResourceReference(String cacheKey, Object o, ReferenceQueue<Object> q) { + super(o, q); + this.cacheKey = cacheKey; + } + + String getCacheKey() { + return cacheKey; + } + } }