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;
+ }
+ }
}