/*
*******************************************************************************
- * Copyright (C) 2008-2010, International Business Machines Corporation and *
+ * Copyright (C) 2008-2013, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
import java.util.TreeMap;
import com.ibm.icu.text.PluralRules;
+import com.ibm.icu.text.PluralRules.PluralType;
import com.ibm.icu.util.ULocale;
import com.ibm.icu.util.UResourceBundle;
/**
* Loader for plural rules data.
*/
-public class PluralRulesLoader {
+public class PluralRulesLoader extends PluralRules.Factory {
private final Map<String, PluralRules> rulesIdToRules;
- private Map<String, String> localeIdToRulesId; // lazy init, use
- // getLocaleIdToRulesIdMap to
- // access
- private Map<String, ULocale> rulesIdToEquivalentULocale; // lazy init, use
- // getRulesIdToEquivalentULocaleMap
- // to access
+ // lazy init, use getLocaleIdToRulesIdMap to access
+ private Map<String, String> localeIdToCardinalRulesId;
+ private Map<String, String> localeIdToOrdinalRulesId;
+ private Map<String, ULocale> rulesIdToEquivalentULocale;
/**
* Access through singleton.
* Returns the locales for which we have plurals data. Utility for testing.
*/
public ULocale[] getAvailableULocales() {
- Set<String> keys = getLocaleIdToRulesIdMap().keySet();
+ Set<String> keys = getLocaleIdToRulesIdMap(PluralType.CARDINAL).keySet();
ULocale[] locales = new ULocale[keys.size()];
int n = 0;
for (Iterator<String> iter = keys.iterator(); iter.hasNext();) {
public ULocale getFunctionalEquivalent(ULocale locale, boolean[] isAvailable) {
if (isAvailable != null && isAvailable.length > 0) {
String localeId = ULocale.canonicalize(locale.getBaseName());
- Map<String, String> idMap = getLocaleIdToRulesIdMap();
+ Map<String, String> idMap = getLocaleIdToRulesIdMap(PluralType.CARDINAL);
isAvailable[0] = idMap.containsKey(localeId);
}
- String rulesId = getRulesIdForLocale(locale);
+ String rulesId = getRulesIdForLocale(locale, PluralType.CARDINAL);
if (rulesId == null || rulesId.trim().length() == 0) {
return ULocale.ROOT; // ultimate fallback
}
/**
* Returns the lazily-constructed map.
*/
- private Map<String, String> getLocaleIdToRulesIdMap() {
+ private Map<String, String> getLocaleIdToRulesIdMap(PluralType type) {
checkBuildRulesIdMaps();
- return localeIdToRulesId;
+ return (type == PluralType.CARDINAL) ? localeIdToCardinalRulesId : localeIdToOrdinalRulesId;
}
/**
* resource in plurals.res.
*/
private void checkBuildRulesIdMaps() {
- if (localeIdToRulesId == null) {
+ boolean haveMap;
+ synchronized (this) {
+ haveMap = localeIdToCardinalRulesId != null;
+ }
+ if (!haveMap) {
+ Map<String, String> tempLocaleIdToCardinalRulesId;
+ Map<String, String> tempLocaleIdToOrdinalRulesId;
+ Map<String, ULocale> tempRulesIdToEquivalentULocale;
try {
UResourceBundle pluralb = getPluralBundle();
+ // Read cardinal-number rules.
UResourceBundle localeb = pluralb.get("locales");
- localeIdToRulesId = new TreeMap<String, String>(); // sort for
- // convenience
- // of
- // getAvailableULocales
- rulesIdToEquivalentULocale = new HashMap<String, ULocale>(); // not
- // visible
+
+ // sort for convenience of getAvailableULocales
+ tempLocaleIdToCardinalRulesId = new TreeMap<String, String>();
+ // not visible
+ tempRulesIdToEquivalentULocale = new HashMap<String, ULocale>();
+
for (int i = 0; i < localeb.getSize(); ++i) {
UResourceBundle b = localeb.get(i);
String id = b.getKey();
String value = b.getString().intern();
- localeIdToRulesId.put(id, value);
+ tempLocaleIdToCardinalRulesId.put(id, value);
- if (!rulesIdToEquivalentULocale.containsKey(value)) {
- rulesIdToEquivalentULocale.put(value, new ULocale(id));
+ if (!tempRulesIdToEquivalentULocale.containsKey(value)) {
+ tempRulesIdToEquivalentULocale.put(value, new ULocale(id));
}
}
+
+ // Read ordinal-number rules.
+ localeb = pluralb.get("locales_ordinals");
+ tempLocaleIdToOrdinalRulesId = new TreeMap<String, String>();
+ for (int i = 0; i < localeb.getSize(); ++i) {
+ UResourceBundle b = localeb.get(i);
+ String id = b.getKey();
+ String value = b.getString().intern();
+ tempLocaleIdToOrdinalRulesId.put(id, value);
+ }
} catch (MissingResourceException e) {
- localeIdToRulesId = Collections.emptyMap(); // dummy so we don't
- // try again, can
- // read
- rulesIdToEquivalentULocale = Collections.emptyMap();
+ // dummy so we don't try again
+ tempLocaleIdToCardinalRulesId = Collections.emptyMap();
+ tempLocaleIdToOrdinalRulesId = Collections.emptyMap();
+ tempRulesIdToEquivalentULocale = Collections.emptyMap();
+ }
+
+ synchronized(this) {
+ if (localeIdToCardinalRulesId == null) {
+ localeIdToCardinalRulesId = tempLocaleIdToCardinalRulesId;
+ localeIdToOrdinalRulesId = tempLocaleIdToOrdinalRulesId;
+ rulesIdToEquivalentULocale = tempRulesIdToEquivalentULocale;
+ }
}
}
}
* rulesId, return null. The rulesId might be the empty string if the rule
* is the default rule.
*/
- public String getRulesIdForLocale(ULocale locale) {
- Map<String, String> idMap = getLocaleIdToRulesIdMap();
+ public String getRulesIdForLocale(ULocale locale, PluralType type) {
+ Map<String, String> idMap = getLocaleIdToRulesIdMap(type);
String localeId = ULocale.canonicalize(locale.getBaseName());
String rulesId = null;
while (null == (rulesId = idMap.get(localeId))) {
* return null.
*/
public PluralRules getRulesForRulesId(String rulesId) {
- PluralRules rules = rulesIdToRules.get(rulesId);
- if (rules == null) {
+ // synchronize on the map. release the lock temporarily while we build the rules.
+ PluralRules rules = null;
+ boolean hasRules; // Separate boolean because stored rules can be null.
+ synchronized (rulesIdToRules) {
+ hasRules = rulesIdToRules.containsKey(rulesId);
+ if (hasRules) {
+ rules = rulesIdToRules.get(rulesId); // can be null
+ }
+ }
+ if (!hasRules) {
try {
UResourceBundle pluralb = getPluralBundle();
UResourceBundle rulesb = pluralb.get("rules");
} catch (ParseException e) {
} catch (MissingResourceException e) {
}
- rulesIdToRules.put(rulesId, rules); // put even if null
+ synchronized (rulesIdToRules) {
+ if (rulesIdToRules.containsKey(rulesId)) {
+ rules = rulesIdToRules.get(rulesId);
+ } else {
+ rulesIdToRules.put(rulesId, rules); // can be null
+ }
+ }
}
return rules;
}
* Returns the plural rules for the the locale. If we don't have data,
* com.ibm.icu.text.PluralRules.DEFAULT is returned.
*/
- public PluralRules forLocale(ULocale locale) {
- String rulesId = getRulesIdForLocale(locale);
+ public PluralRules forLocale(ULocale locale, PluralRules.PluralType type) {
+ String rulesId = getRulesIdForLocale(locale, type);
if (rulesId == null || rulesId.trim().length() == 0) {
return PluralRules.DEFAULT;
}
* The only instance of the loader.
*/
public static final PluralRulesLoader loader = new PluralRulesLoader();
+
+ /* (non-Javadoc)
+ * @see com.ibm.icu.text.PluralRules.Factory#hasOverride(com.ibm.icu.util.ULocale)
+ */
+ @Override
+ public boolean hasOverride(ULocale locale) {
+ return false;
+ }
}