17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/** 27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 3f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * Copyright (C) 2001-2015, International Business Machines Corporation and * 47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * others. All Rights Reserved. * 57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.impl; 87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Collections; 107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Locale; 117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Map; 127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Set; 137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ULocale; 157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class ICULocaleService extends ICUService { 177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private ULocale fallbackLocale; 187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String fallbackLocaleName; 197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Construct an ICULocaleService. 227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public ICULocaleService() { 247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Construct an ICULocaleService with a name (useful for debugging). 287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public ICULocaleService(String name) { 307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert super(name); 317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Convenience override for callers using locales. This calls 357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * get(ULocale, int, ULocale[]) with KIND_ANY for kind and null for 367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * actualReturn. 377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Object get(ULocale locale) { 397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return get(locale, LocaleKey.KIND_ANY, null); 407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Convenience override for callers using locales. This calls 447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * get(ULocale, int, ULocale[]) with a null actualReturn. 457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Object get(ULocale locale, int kind) { 477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return get(locale, kind, null); 487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Convenience override for callers using locales. This calls 527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * get(ULocale, int, ULocale[]) with KIND_ANY for kind. 537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Object get(ULocale locale, ULocale[] actualReturn) { 557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return get(locale, LocaleKey.KIND_ANY, actualReturn); 567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Convenience override for callers using locales. This uses 607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * createKey(ULocale.toString(), kind) to create a key, calls getKey, and then 617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * if actualReturn is not null, returns the actualResult from 627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * getKey (stripping any prefix) into a ULocale. 637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Object get(ULocale locale, int kind, ULocale[] actualReturn) { 657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Key key = createKey(locale, kind); 667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (actualReturn == null) { 677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getKey(key); 687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] temp = new String[1]; 717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object result = getKey(key, temp); 727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (result != null) { 737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int n = temp[0].indexOf("/"); 747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (n >= 0) { 757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert temp[0] = temp[0].substring(n+1); 767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert actualReturn[0] = new ULocale(temp[0]); 787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Convenience override for callers using locales. This calls 847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * registerObject(Object, ULocale, int kind, boolean visible) 857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * passing KIND_ANY for the kind, and true for the visibility. 867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Factory registerObject(Object obj, ULocale locale) { 887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return registerObject(obj, locale, LocaleKey.KIND_ANY, true); 897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Convenience override for callers using locales. This calls 937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * registerObject(Object, ULocale, int kind, boolean visible) 947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * passing KIND_ANY for the kind. 957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Factory registerObject(Object obj, ULocale locale, boolean visible) { 977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return registerObject(obj, locale, LocaleKey.KIND_ANY, visible); 987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Convenience function for callers using locales. This calls 1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * registerObject(Object, ULocale, int kind, boolean visible) 1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * passing true for the visibility. 1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Factory registerObject(Object obj, ULocale locale, int kind) { 1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return registerObject(obj, locale, kind, true); 1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Convenience function for callers using locales. This instantiates 1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * a SimpleLocaleKeyFactory, and registers the factory. 1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Factory registerObject(Object obj, ULocale locale, int kind, boolean visible) { 1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Factory factory = new SimpleLocaleKeyFactory(obj, locale, kind, visible); 1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return registerFactory(factory); 1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Convenience method for callers using locales. This returns the standard 1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Locale list, built from the Set of visible ids. 1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Locale[] getAvailableLocales() { 1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO make this wrap getAvailableULocales later 1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<String> visIDs = getVisibleIDs(); 1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Locale[] locales = new Locale[visIDs.size()]; 1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int n = 0; 1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String id : visIDs) { 1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Locale loc = LocaleUtility.getLocaleFromName(id); 1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert locales[n++] = loc; 1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return locales; 1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Convenience method for callers using locales. This returns the standard 1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ULocale list, built from the Set of visible ids. 1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public ULocale[] getAvailableULocales() { 1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<String> visIDs = getVisibleIDs(); 1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale[] locales = new ULocale[visIDs.size()]; 1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int n = 0; 1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String id : visIDs) { 1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert locales[n++] = new ULocale(id); 1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return locales; 1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A subclass of Key that implements a locale fallback mechanism. 1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The first locale to search for is the locale provided by the 1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * client, and the fallback locale to search for is the current 1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * default locale. If a prefix is present, the currentDescriptor 1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * includes it before the locale proper, separated by "/". This 1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * is the default key instantiated by ICULocaleService.</p> 1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Canonicalization adjusts the locale string so that the 1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * section before the first understore is in lower case, and the rest 1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * is in upper case, with no trailing underscores.</p> 1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static class LocaleKey extends ICUService.Key { 1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int kind; 1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int varstart; 1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String primaryID; 1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String fallbackID; 1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String currentID; 1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final int KIND_ANY = -1; 1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Create a LocaleKey with canonical primary and fallback IDs. 1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static LocaleKey createWithCanonicalFallback(String primaryID, String canonicalFallbackID) { 1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return createWithCanonicalFallback(primaryID, canonicalFallbackID, KIND_ANY); 1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Create a LocaleKey with canonical primary and fallback IDs. 1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static LocaleKey createWithCanonicalFallback(String primaryID, String canonicalFallbackID, int kind) { 1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (primaryID == null) { 1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String canonicalPrimaryID = ULocale.getName(primaryID); 1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new LocaleKey(primaryID, canonicalPrimaryID, canonicalFallbackID, kind); 1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Create a LocaleKey with canonical primary and fallback IDs. 1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static LocaleKey createWithCanonical(ULocale locale, String canonicalFallbackID, int kind) { 1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (locale == null) { 1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String canonicalPrimaryID = locale.getName(); 1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new LocaleKey(canonicalPrimaryID, canonicalPrimaryID, canonicalFallbackID, kind); 1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * PrimaryID is the user's requested locale string, 2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * canonicalPrimaryID is this string in canonical form, 2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * fallbackID is the current default locale's string in 2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * canonical form. 2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected LocaleKey(String primaryID, String canonicalPrimaryID, String canonicalFallbackID, int kind) { 2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert super(primaryID); 2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.kind = kind; 2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (canonicalPrimaryID == null || canonicalPrimaryID.equalsIgnoreCase("root")) { 2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.primaryID = ""; 2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.fallbackID = null; 2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int idx = canonicalPrimaryID.indexOf('@'); 2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (idx == 4 && canonicalPrimaryID.regionMatches(true, 0, "root", 0, 4)) { 2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.primaryID = canonicalPrimaryID.substring(4); 2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.varstart = 0; 2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.fallbackID = null; 2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.primaryID = canonicalPrimaryID; 2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.varstart = idx; 2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (canonicalFallbackID == null || this.primaryID.equals(canonicalFallbackID)) { 2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.fallbackID = ""; 2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.fallbackID = canonicalFallbackID; 2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.currentID = varstart == -1 ? this.primaryID : this.primaryID.substring(0, varstart); 2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return the prefix associated with the kind, or null if the kind is KIND_ANY. 2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String prefix() { 2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return kind == KIND_ANY ? null : Integer.toString(kind()); 2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return the kind code associated with this key. 2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int kind() { 2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return kind; 2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return the (canonical) original ID. 2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String canonicalID() { 2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return primaryID; 2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return the (canonical) current ID, or null if no current id. 2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String currentID() { 2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return currentID; 2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return the (canonical) current descriptor, or null if no current id. 2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Includes the keywords, whereas the ID does not include keywords. 2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String currentDescriptor() { 2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String result = currentID(); 2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (result != null) { 2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder buf = new StringBuilder(); // default capacity 16 is usually good enough 2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (kind != KIND_ANY) { 2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(prefix()); 2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append('/'); 2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(result); 2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (varstart != -1) { 2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(primaryID.substring(varstart, primaryID.length())); 2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result = buf.toString(); 2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Convenience method to return the locale corresponding to the (canonical) original ID. 2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public ULocale canonicalLocale() { 2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new ULocale(primaryID); 2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Convenience method to return the ulocale corresponding to the (canonical) currentID. 2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public ULocale currentLocale() { 2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (varstart == -1) { 2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new ULocale(currentID); 2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new ULocale(currentID + primaryID.substring(varstart)); 2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If the key has a fallback, modify the key and return true, 3017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * otherwise return false.</p> 3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>First falls back through the primary ID, then through 3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the fallbackID. The final fallback is "" (root) 3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * unless the primary id was "" (root), in which case 3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * there is no fallback. 3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean fallback() { 3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int x = currentID.lastIndexOf('_'); 3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (x != -1) { 3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (--x >= 0 && currentID.charAt(x) == '_') { // handle zh__PINYIN 3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert currentID = currentID.substring(0, x+1); 3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (fallbackID != null) { 3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert currentID = fallbackID; 3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (fallbackID.length() == 0) { 3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fallbackID = null; 3207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fallbackID = ""; 3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert currentID = null; 3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If a key created from id would eventually fallback to match the 3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * canonical ID of this key, return true. 3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isFallbackOf(String id) { 3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleUtility.isFallbackOf(canonicalID(), id); 3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A subclass of Factory that uses LocaleKeys. If 'visible' the 3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * factory reports its IDs. 3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static abstract class LocaleKeyFactory implements Factory { 3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected final String name; 3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected final boolean visible; 3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final boolean VISIBLE = true; 3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final boolean INVISIBLE = false; 3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Constructor used by subclasses. 3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected LocaleKeyFactory(boolean visible) { 3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.visible = visible; 3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.name = null; 3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Constructor used by subclasses. 3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected LocaleKeyFactory(boolean visible, String name) { 3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.visible = visible; 3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.name = name; 3637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Implement superclass abstract method. This checks the currentID of 3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the key against the supported IDs, and passes the canonicalLocale and 3687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * kind off to handleCreate (which subclasses must implement). 3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Object create(Key key, ICUService service) { 3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (handlesKey(key)) { 3727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LocaleKey lkey = (LocaleKey)key; 3737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int kind = lkey.kind(); 3747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale uloc = lkey.currentLocale(); 3767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return handleCreate(uloc, kind, service); 3777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 3787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // System.out.println("factory: " + this + " did not support id: " + key.currentID()); 3797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // System.out.println("supported ids: " + getSupportedIDs()); 3807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 3827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected boolean handlesKey(Key key) { 3857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (key != null) { 3867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String id = key.currentID(); 3877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<String> supported = getSupportedIDs(); 3887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return supported.contains(id); 3897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 3917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Override of superclass method. 3957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void updateVisibleIDs(Map<String, Factory> result) { 3977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<String> cache = getSupportedIDs(); 3987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String id : cache) { 3997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (visible) { 4007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.put(id, this); 4017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 4027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.remove(id); 4037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return a localized name for the locale represented by id. 4097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayName(String id, ULocale locale) { 4117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // assume if the user called this on us, we must have handled some fallback of this id 4127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (isSupportedID(id)) { 4137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (locale == null) { 4147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return id; 4157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale loc = new ULocale(id); 4177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return loc.getDisplayName(locale); 4187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 4197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // return null; 4207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ///CLOVER:OFF 4237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Utility method used by create(Key, ICUService). Subclasses can 4257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * implement this instead of create. 4267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected Object handleCreate(ULocale loc, int kind, ICUService service) { 4287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 4297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ///CLOVER:ON 4317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return true if this id is one the factory supports (visible or 4347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * otherwise). 4357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected boolean isSupportedID(String id) { 4377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getSupportedIDs().contains(id); 4387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return the set of ids that this factory supports (visible or 4427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * otherwise). This can be called often and might need to be 4437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * cached if it is expensive to create. 4447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected Set<String> getSupportedIDs() { 4467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return Collections.emptySet(); 4477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * For debugging. 4517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 4537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder buf = new StringBuilder(super.toString()); 4547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (name != null) { 4557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(", name: "); 4567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(name); 4577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(", visible: "); 4597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(visible); 4607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return buf.toString(); 4617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A LocaleKeyFactory that just returns a single object for a kind/locale. 4667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static class SimpleLocaleKeyFactory extends LocaleKeyFactory { 4687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final Object obj; 4697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final String id; 4707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final int kind; 4717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO: remove when we no longer need this 4737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public SimpleLocaleKeyFactory(Object obj, ULocale locale, int kind, boolean visible) { 4747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this(obj, locale, kind, visible, null); 4757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public SimpleLocaleKeyFactory(Object obj, ULocale locale, int kind, boolean visible, String name) { 4787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert super(visible, name); 4797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.obj = obj; 4817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.id = locale.getBaseName(); 4827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.kind = kind; 4837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the service object if kind/locale match. Service is not used. 4877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Object create(Key key, ICUService service) { 4897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!(key instanceof LocaleKey)) { 4907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 4917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LocaleKey lkey = (LocaleKey)key; 4947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (kind != LocaleKey.KIND_ANY && kind != lkey.kind()) { 4957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 4967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!id.equals(lkey.currentID())) { 4987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 4997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return obj; 5027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected boolean isSupportedID(String idToCheck) { 5057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this.id.equals(idToCheck); 5067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void updateVisibleIDs(Map<String, Factory> result) { 5097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (visible) { 5107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.put(id, this); 5117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 5127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.remove(id); 5137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 5177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder buf = new StringBuilder(super.toString()); 5187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(", id: "); 5197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(id); 5207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(", kind: "); 5217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(kind); 5227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return buf.toString(); 5237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A LocaleKeyFactory that creates a service based on the ICU locale data. 5287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a base class for most ICU factories. Subclasses instantiate it 5297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * with a constructor that takes a bundle name, which determines the supported 5307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * IDs. Subclasses then override handleCreate to create the actual service 5317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * object. The default implementation returns a resource bundle. 5327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static class ICUResourceBundleFactory extends LocaleKeyFactory { 5347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected final String bundleName; 5357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Convenience constructor that uses the main ICU bundle name. 5387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public ICUResourceBundleFactory() { 5407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this(ICUResourceBundle.ICU_BASE_NAME); 5417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A service factory based on ICU resource data in resources 5457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * with the given name. 5467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public ICUResourceBundleFactory(String bundleName) { 5487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert super(true); 5497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.bundleName = bundleName; 5517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return the supported IDs. This is the set of all locale names for the bundleName. 5557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected Set<String> getSupportedIDs() { 5577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return ICUResourceBundle.getFullLocaleNameSet(bundleName, loader()); 5587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Override of superclass method. 5627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void updateVisibleIDs(Map<String, Factory> result) { 5647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<String> visibleIDs = ICUResourceBundle.getAvailableLocaleNameSet(bundleName, loader()); // only visible ids 5657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String id : visibleIDs) { 5667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.put(id, this); 5677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Create the service. The default implementation returns the resource bundle 5727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * for the locale, ignoring kind, and service. 5737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected Object handleCreate(ULocale loc, int kind, ICUService service) { 5757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return ICUResourceBundle.getBundleInstance(bundleName, loc, loader()); 5767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected ClassLoader loader() { 579f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert return ClassLoaderUtil.getClassLoader(getClass()); 5807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 5837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return super.toString() + ", bundle: " + bundleName; 5847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return the name of the current fallback locale. If it has changed since this was 5897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * last accessed, the service cache is cleared. 5907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String validateFallbackLocale() { 5927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale loc = ULocale.getDefault(); 5937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (loc != fallbackLocale) { 5947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized (this) { 5957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (loc != fallbackLocale) { 5967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fallbackLocale = loc; 5977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fallbackLocaleName = loc.getBaseName(); 5987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert clearServiceCache(); 5997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return fallbackLocaleName; 6037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Key createKey(String id) { 6067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleKey.createWithCanonicalFallback(id, validateFallbackLocale()); 6077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Key createKey(String id, int kind) { 6107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleKey.createWithCanonicalFallback(id, validateFallbackLocale(), kind); 6117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Key createKey(ULocale l, int kind) { 6147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleKey.createWithCanonical(l, validateFallbackLocale(), kind); 6157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 617