17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/* 27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Copyright (C) 2011-2014, 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.io.IOException; 107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.ObjectInputStream; 117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.Serializable; 127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.lang.ref.WeakReference; 137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.text.MessageFormat; 147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Collection; 157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.EnumSet; 167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Iterator; 177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.LinkedList; 187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.MissingResourceException; 197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Set; 207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.concurrent.ConcurrentHashMap; 217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.TextTrieMap.ResultHandler; 237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.LocaleDisplayNames; 247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.TimeZoneFormat.TimeType; 257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.TimeZoneNames; 267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.TimeZoneNames.MatchInfo; 277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.TimeZoneNames.NameType; 287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.BasicTimeZone; 297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.Freezable; 307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.Output; 317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.TimeZone; 327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.TimeZone.SystemTimeZoneType; 337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.TimeZoneTransition; 347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ULocale; 357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/** 377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This class interact with TimeZoneNames and LocaleDisplayNames 387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * to format and parse time zone's generic display names. 397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * It is not recommended to use this class directly, instead 407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * use com.ibm.icu.text.TimeZoneFormat. 417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class TimeZoneGenericNames implements Serializable, Freezable<TimeZoneGenericNames> { 437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Note: This class implements Serializable, but we no longer serialize instance of 457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TimeZoneGenericNames in ICU 49. ICU 4.8 com.ibm.icu.text.TimeZoneFormat used to 467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // serialize TimeZoneGenericNames field. TimeZoneFormat no longer read TimeZoneGenericNames 477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // field, we have to keep TimeZoneGenericNames Serializable. Otherwise it fails to read 487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // (unused) TimeZoneGenericNames serialized data. 497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final long serialVersionUID = 2729910342063468417L; 517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Generic name type enum 547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public enum GenericNameType { 567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LOCATION ("LONG", "SHORT"), 577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LONG (), 587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert SHORT (); 597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] _fallbackTypeOf; 617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert GenericNameType(String... fallbackTypeOf) { 627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _fallbackTypeOf = fallbackTypeOf; 637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isFallbackTypeOf(GenericNameType type) { 667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String typeStr = type.toString(); 677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String t : _fallbackTypeOf) { 687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (t.equals(typeStr)) { 697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Format pattern enum used for composing location and partial location names 787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public enum Pattern { 807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // The format pattern such as "{0} Time", where {0} is the country or city. 817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert REGION_FORMAT("regionFormat", "({0})"), 827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Note: FALLBACK_REGION_FORMAT is no longer used since ICU 50/CLDR 22.1 847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // The format pattern such as "{1} Time ({0})", where {1} is the country and {0} is a city. 857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //FALLBACK_REGION_FORMAT("fallbackRegionFormat", "{1} ({0})"), 867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // The format pattern such as "{1} ({0})", where {1} is the metazone, and {0} is the country or city. 887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FALLBACK_FORMAT("fallbackFormat", "{1} ({0})"); 897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String _key; 917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String _defaultVal; 927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Pattern(String key, String defaultVal) { 947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _key = key; 957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _defaultVal = defaultVal; 967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String key() { 997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return _key; 1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String defaultValue() { 1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return _defaultVal; 1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private ULocale _locale; 1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private TimeZoneNames _tznames; 1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient volatile boolean _frozen; 1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient String _region; 1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient WeakReference<LocaleDisplayNames> _localeDisplayNamesRef; 1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient MessageFormat[] _patternFormatters; 1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient ConcurrentHashMap<String, String> _genericLocationNamesMap; 1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient ConcurrentHashMap<String, String> _genericPartialLocationNamesMap; 1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient TextTrieMap<NameInfo> _gnamesTrie; 1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient boolean _gnamesTrieFullyLoaded; 1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Cache GENERIC_NAMES_CACHE = new Cache(); 1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Window size used for DST check for a zone in a metazone (about a half year) 1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final long DST_CHECK_RANGE = 184L*(24*60*60*1000); 1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final NameType[] GENERIC_NON_LOCATION_TYPES = 1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {NameType.LONG_GENERIC, NameType.SHORT_GENERIC}; 1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Constructs a <code>TimeZoneGenericNames</code> with the given locale 1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and the <code>TimeZoneNames</code>. 1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale the locale 1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param tznames the TimeZoneNames 1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public TimeZoneGenericNames(ULocale locale, TimeZoneNames tznames) { 1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _locale = locale; 1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _tznames = tznames; 1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert init(); 1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Private method initializing the instance of <code>TimeZoneGenericName</code>. 1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This method should be called from a constructor and readObject. 1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void init() { 1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (_tznames == null) { 1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _tznames = TimeZoneNames.getInstance(_locale); 1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _genericLocationNamesMap = new ConcurrentHashMap<String, String>(); 1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _genericPartialLocationNamesMap = new ConcurrentHashMap<String, String>(); 1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _gnamesTrie = new TextTrieMap<NameInfo>(true); 1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _gnamesTrieFullyLoaded = false; 1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Preload zone strings for the default time zone 1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeZone tz = TimeZone.getDefault(); 1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String tzCanonicalID = ZoneMeta.getCanonicalCLDRID(tz); 1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tzCanonicalID != null) { 1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert loadStrings(tzCanonicalID); 1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Constructs a <code>TimeZoneGenericNames</code> with the given locale. 1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This constructor is private and called from {@link #getInstance(ULocale)}. 1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale the locale 1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private TimeZoneGenericNames(ULocale locale) { 1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this(locale, null); 1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The factory method of <code>TimeZoneGenericNames</code>. This static method 1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * returns a frozen instance of cached <code>TimeZoneGenericNames</code>. 1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale the locale 1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return A frozen <code>TimeZoneGenericNames</code>. 1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static TimeZoneGenericNames getInstance(ULocale locale) { 1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String key = locale.getBaseName(); 1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return GENERIC_NAMES_CACHE.getInstance(key, locale); 1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the display name of the time zone for the given name type 1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * at the given date, or null if the display name is not available. 1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param tz the time zone 1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param type the generic name type - see {@link GenericNameType} 1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param date the date 1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the display name of the time zone for the given name type 1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * at the given date, or null. 1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayName(TimeZone tz, GenericNameType type, long date) { 1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String name = null; 1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String tzCanonicalID = null; 1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch (type) { 1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case LOCATION: 1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tzCanonicalID = ZoneMeta.getCanonicalCLDRID(tz); 1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tzCanonicalID != null) { 2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert name = getGenericLocationName(tzCanonicalID); 2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case LONG: 2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case SHORT: 2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert name = formatGenericNonLocationName(tz, type, date); 2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (name == null) { 2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tzCanonicalID = ZoneMeta.getCanonicalCLDRID(tz); 2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tzCanonicalID != null) { 2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert name = getGenericLocationName(tzCanonicalID); 2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return name; 2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the generic location name for the given canonical time zone ID. 2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param canonicalTzID the canonical time zone ID 2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the generic location name for the given canonical time zone ID. 2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getGenericLocationName(String canonicalTzID) { 2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (canonicalTzID == null || canonicalTzID.length() == 0) { 2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String name = _genericLocationNamesMap.get(canonicalTzID); 2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (name != null) { 2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (name.length() == 0) { 2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // empty string to indicate the name is not available 2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return name; 2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Output<Boolean> isPrimary = new Output<Boolean>(); 2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String countryCode = ZoneMeta.getCanonicalCountry(canonicalTzID, isPrimary); 2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (countryCode != null) { 2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (isPrimary.value) { 2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // If this is only the single zone in the country, use the country name 2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String country = getLocaleDisplayNames().regionDisplayName(countryCode); 2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert name = formatPattern(Pattern.REGION_FORMAT, country); 2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // If there are multiple zones including this in the country, 2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // use the exemplar city name 2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // getExemplarLocationName should return non-empty String 2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if the time zone is associated with a location 2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String city = _tznames.getExemplarLocationName(canonicalTzID); 2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert name = formatPattern(Pattern.REGION_FORMAT, city); 2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (name == null) { 2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _genericLocationNamesMap.putIfAbsent(canonicalTzID.intern(), ""); 2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized (this) { // we have to sync the name map and the trie 2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert canonicalTzID = canonicalTzID.intern(); 2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String tmp = _genericLocationNamesMap.putIfAbsent(canonicalTzID, name.intern()); 2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tmp == null) { 2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Also put the name info the to trie 2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NameInfo info = new NameInfo(); 2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert info.tzID = canonicalTzID; 2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert info.type = GenericNameType.LOCATION; 2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _gnamesTrie.put(name, info); 2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert name = tmp; 2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return name; 2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Sets the pattern string for the pattern type. 2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Note: This method is designed for CLDR ST - not for common use. 2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param patType the pattern type 2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param patStr the pattern string 2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return this object. 2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public TimeZoneGenericNames setFormatPattern(Pattern patType, String patStr) { 2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (isFrozen()) { 2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new UnsupportedOperationException("Attempt to modify frozen object"); 2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Changing pattern will invalidates cached names 2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!_genericLocationNamesMap.isEmpty()) { 2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _genericLocationNamesMap = new ConcurrentHashMap<String, String>(); 2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!_genericPartialLocationNamesMap.isEmpty()) { 2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _genericPartialLocationNamesMap = new ConcurrentHashMap<String, String>(); 2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _gnamesTrie = null; 2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _gnamesTrieFullyLoaded = false; 2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (_patternFormatters == null) { 2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _patternFormatters = new MessageFormat[Pattern.values().length]; 2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _patternFormatters[patType.ordinal()] = new MessageFormat(patStr); 3007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 3017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Private method to get a generic string, with fallback logics involved, 3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * that is, 3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 1. If a generic non-location string is available for the zone, return it. 3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 2. If a generic non-location string is associated with a meta zone and 3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the zone never use daylight time around the given date, use the standard 3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * string (if available). 3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 3. If a generic non-location string is associated with a meta zone and 3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the offset at the given time is different from the preferred zone for the 3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * current locale, then return the generic partial location string (if available) 3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 4. If a generic non-location string is not available, use generic location 3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * string. 3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param tz the requested time zone 3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param date the date 3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param type the generic name type, either LONG or SHORT 3207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the name used for a generic name type, which could be the 3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * generic name, or the standard name (if the zone does not observes DST 3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * around the date), or the partial location name. 3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String formatGenericNonLocationName(TimeZone tz, GenericNameType type, long date) { 3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assert(type == GenericNameType.LONG || type == GenericNameType.SHORT); 3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String tzID = ZoneMeta.getCanonicalCLDRID(tz); 3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tzID == null) { 3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Try to get a name from time zone first 3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NameType nameType = (type == GenericNameType.LONG) ? NameType.LONG_GENERIC : NameType.SHORT_GENERIC; 3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String name = _tznames.getTimeZoneDisplayName(tzID, nameType); 3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (name != null) { 3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return name; 3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Try meta zone 3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String mzID = _tznames.getMetaZoneID(tzID, date); 3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (mzID != null) { 3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean useStandard = false; 3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] offsets = {0, 0}; 3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tz.getOffset(date, false, offsets); 3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (offsets[1] == 0) { 3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert useStandard = true; 3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Check if the zone actually uses daylight saving time around the time 3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tz instanceof BasicTimeZone) { 3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert BasicTimeZone btz = (BasicTimeZone)tz; 3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeZoneTransition before = btz.getPreviousTransition(date, true); 3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (before != null 3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && (date - before.getTime() < DST_CHECK_RANGE) 3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && before.getFrom().getDSTSavings() != 0) { 3567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert useStandard = false; 3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 3587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeZoneTransition after = btz.getNextTransition(date, false); 3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (after != null 3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && (after.getTime() - date < DST_CHECK_RANGE) 3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && after.getTo().getDSTSavings() != 0) { 3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert useStandard = false; 3637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // If not BasicTimeZone... only if the instance is not an ICU's implementation. 3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // We may get a wrong answer in edge case, but it should practically work OK. 3687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] tmpOffsets = new int[2]; 3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tz.getOffset(date - DST_CHECK_RANGE, false, tmpOffsets); 3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tmpOffsets[1] != 0) { 3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert useStandard = false; 3727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 3737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tz.getOffset(date + DST_CHECK_RANGE, false, tmpOffsets); 3747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tmpOffsets[1] != 0){ 3757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert useStandard = false; 3767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (useStandard) { 3817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NameType stdNameType = (nameType == NameType.LONG_GENERIC) ? 3827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NameType.LONG_STANDARD : NameType.SHORT_STANDARD; 3837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String stdName = _tznames.getDisplayName(tzID, stdNameType, date); 3847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (stdName != null) { 3857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert name = stdName; 3867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO: revisit this issue later 3887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // In CLDR, a same display name is used for both generic and standard 3897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // for some meta zones in some locales. This looks like a data bugs. 3907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // For now, we check if the standard name is different from its generic 3917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // name below. 3927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String mzGenericName = _tznames.getMetaZoneDisplayName(mzID, nameType); 3937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (stdName.equalsIgnoreCase(mzGenericName)) { 3947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert name = null; 3957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (name == null) { 4007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Get a name from meta zone 4017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String mzName = _tznames.getMetaZoneDisplayName(mzID, nameType); 4027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (mzName != null) { 4037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Check if we need to use a partial location format. 4047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This check is done by comparing offset with the meta zone's 4057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // golden zone at the given date. 4067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String goldenID = _tznames.getReferenceZoneID(mzID, getTargetRegion()); 4077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (goldenID != null && !goldenID.equals(tzID)) { 4087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeZone goldenZone = TimeZone.getFrozenTimeZone(goldenID); 4097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] offsets1 = {0, 0}; 4107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Check offset in the golden zone with wall time. 4127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // With getOffset(date, false, offsets1), 4137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // you may get incorrect results because of time overlap at DST->STD 4147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // transition. 4157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert goldenZone.getOffset(date + offsets[0] + offsets[1], true, offsets1); 4167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (offsets[0] != offsets1[0] || offsets[1] != offsets1[1]) { 4187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Now we need to use a partial location format. 4197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert name = getPartialLocationName(tzID, mzID, (nameType == NameType.LONG_GENERIC), mzName); 4207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 4217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert name = mzName; 4227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 4247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert name = mzName; 4257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return name; 4307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Private simple pattern formatter used for formatting generic location names 4347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and partial location names. We intentionally use JDK MessageFormat 4357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * for performance reason. 4367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 4377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param pat the message pattern enum 4387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param args the format argument(s) 4397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the formatted string 4407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private synchronized String formatPattern(Pattern pat, String... args) { 4427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (_patternFormatters == null) { 4437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _patternFormatters = new MessageFormat[Pattern.values().length]; 4447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int idx = pat.ordinal(); 4477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (_patternFormatters[idx] == null) { 4487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String patText; 4497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 4507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle bundle = (ICUResourceBundle) ICUResourceBundle.getBundleInstance( 4517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle.ICU_ZONE_BASE_NAME, _locale); 4527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert patText = bundle.getStringWithFallback("zoneStrings/" + pat.key()); 4537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (MissingResourceException e) { 4547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert patText = pat.defaultValue(); 4557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _patternFormatters[idx] = new MessageFormat(patText); 4587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return _patternFormatters[idx].format(args); 4607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Private method returning LocaleDisplayNames instance for the locale of this 4647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * instance. Because LocaleDisplayNames is only used for generic 4657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * location formant and partial location format, the LocaleDisplayNames 4667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * is instantiated lazily. 4677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 4687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the instance of LocaleDisplayNames for the locale of this object. 4697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private synchronized LocaleDisplayNames getLocaleDisplayNames() { 4717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LocaleDisplayNames locNames = null; 4727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (_localeDisplayNamesRef != null) { 4737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert locNames = _localeDisplayNamesRef.get(); 4747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (locNames == null) { 4767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert locNames = LocaleDisplayNames.getInstance(_locale); 4777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _localeDisplayNamesRef = new WeakReference<LocaleDisplayNames>(locNames); 4787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return locNames; 4807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private synchronized void loadStrings(String tzCanonicalID) { 4837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tzCanonicalID == null || tzCanonicalID.length() == 0) { 4847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return; 4857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // getGenericLocationName() formats a name and put it into the trie 4877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert getGenericLocationName(tzCanonicalID); 4887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Generic partial location format 4907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<String> mzIDs = _tznames.getAvailableMetaZoneIDs(tzCanonicalID); 4917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String mzID : mzIDs) { 4927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if this time zone is not the golden zone of the meta zone, 4937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // partial location name (such as "PT (Los Angeles)") might be 4947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // available. 4957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String goldenID = _tznames.getReferenceZoneID(mzID, getTargetRegion()); 4967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!tzCanonicalID.equals(goldenID)) { 4977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (NameType genNonLocType : GENERIC_NON_LOCATION_TYPES) { 4987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String mzGenName = _tznames.getMetaZoneDisplayName(mzID, genNonLocType); 4997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (mzGenName != null) { 5007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // getPartialLocationName() formats a name and put it into the trie 5017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert getPartialLocationName(tzCanonicalID, mzID, (genNonLocType == NameType.LONG_GENERIC), mzGenName); 5027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Private method returning the target region. The target regions is determined by 5107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the locale of this instance. When a generic name is coming from 5117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * a meta zone, this region is used for checking if the time zone 5127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * is a reference zone of the meta zone. 5137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 5147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the target region 5157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private synchronized String getTargetRegion() { 5177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (_region == null) { 5187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _region = _locale.getCountry(); 5197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (_region.length() == 0) { 5207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale tmp = ULocale.addLikelySubtags(_locale); 5217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _region = tmp.getCountry(); 5227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (_region.length() == 0) { 5237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _region = "001"; 5247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return _region; 5287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Private method for formatting partial location names. This format 5327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * is used when a generic name of a meta zone is available, but the given 5337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * time zone is not a reference zone (golden zone) of the meta zone. 5347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 5357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param tzID the canonical time zone ID 5367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param mzID the meta zone ID 5377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param isLong true when long generic name 5387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param mzDisplayName the meta zone generic display name 5397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the partial location format string 5407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String getPartialLocationName(String tzID, String mzID, boolean isLong, String mzDisplayName) { 5427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String letter = isLong ? "L" : "S"; 5437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String key = tzID + "&" + mzID + "#" + letter; 5447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String name = _genericPartialLocationNamesMap.get(key); 5457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (name != null) { 5467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return name; 5477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String location = null; 5497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String countryCode = ZoneMeta.getCanonicalCountry(tzID); 5507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (countryCode != null) { 5517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Is this the golden zone for the region? 5527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String regionalGolden = _tznames.getReferenceZoneID(mzID, countryCode); 5537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tzID.equals(regionalGolden)) { 5547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Use country name 5557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert location = getLocaleDisplayNames().regionDisplayName(countryCode); 5567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 5577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Otherwise, use exemplar city name 5587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert location = _tznames.getExemplarLocationName(tzID); 5597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 5617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert location = _tznames.getExemplarLocationName(tzID); 5627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (location == null) { 5637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This could happen when the time zone is not associated with a country, 5647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // and its ID is not hierarchical, for example, CST6CDT. 5657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // We use the canonical ID itself as the location for this case. 5667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert location = tzID; 5677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert name = formatPattern(Pattern.FALLBACK_FORMAT, location, mzDisplayName); 5707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized (this) { // we have to sync the name map and the trie 5717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String tmp = _genericPartialLocationNamesMap.putIfAbsent(key.intern(), name.intern()); 5727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tmp == null) { 5737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NameInfo info = new NameInfo(); 5747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert info.tzID = tzID.intern(); 5757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert info.type = isLong ? GenericNameType.LONG : GenericNameType.SHORT; 5767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _gnamesTrie.put(name, info); 5777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 5787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert name = tmp; 5797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return name; 5827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A private class used for storing the name information in the local trie. 5867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static class NameInfo { 5887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String tzID; 5897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert GenericNameType type; 5907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A class used for returning the name search result used by 5947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@link TimeZoneGenericNames#find(String, int, EnumSet)}. 5957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static class GenericMatchInfo { 5977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert GenericNameType nameType; 5987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String tzID; 5997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int matchLength; 6007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeType timeType = TimeType.UNKNOWN; 6017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public GenericNameType nameType() { 6037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return nameType; 6047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String tzID() { 6077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return tzID; 6087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public TimeType timeType() { 6117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return timeType; 6127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int matchLength() { 6157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return matchLength; 6167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A private class implementing the search callback interface in 6217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>TextTrieMap</code> for collecting match results. 6227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static class GenericNameSearchHandler implements ResultHandler<NameInfo> { 6247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private EnumSet<GenericNameType> _types; 6257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private Collection<GenericMatchInfo> _matches; 6267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int _maxMatchLen; 6277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert GenericNameSearchHandler(EnumSet<GenericNameType> types) { 6297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _types = types; 6307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* (non-Javadoc) 6337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.impl.TextTrieMap.ResultHandler#handlePrefixMatch(int, java.util.Iterator) 6347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean handlePrefixMatch(int matchLength, Iterator<NameInfo> values) { 6367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (values.hasNext()) { 6377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NameInfo info = values.next(); 6387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (_types != null && !_types.contains(info.type)) { 6397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 6407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert GenericMatchInfo matchInfo = new GenericMatchInfo(); 6427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert matchInfo.tzID = info.tzID; 6437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert matchInfo.nameType = info.type; 6447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert matchInfo.matchLength = matchLength; 6457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //matchInfo.timeType = TimeType.UNKNOWN; 6467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (_matches == null) { 6477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _matches = new LinkedList<GenericMatchInfo>(); 6487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _matches.add(matchInfo); 6507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (matchLength > _maxMatchLen) { 6517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _maxMatchLen = matchLength; 6527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 6557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the match results 6597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the match results 6607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Collection<GenericMatchInfo> getMatches() { 6627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return _matches; 6637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the maximum match length, or 0 if no match was found 6677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the maximum match length 6687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int getMaxMatchLen() { 6707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return _maxMatchLen; 6717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Resets the match results 6757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void resetResults() { 6777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _matches = null; 6787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _maxMatchLen = 0; 6797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the best match of time zone display name for the specified types in the 6847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * given text at the given offset. 6857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param text the text 6867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param start the start offset in the text 6877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param genericTypes the set of name types. 6887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the best matching name info. 6897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public GenericMatchInfo findBestMatch(String text, int start, EnumSet<GenericNameType> genericTypes) { 6917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (text == null || text.length() == 0 || start < 0 || start >= text.length()) { 6927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("bad input text or range"); 6937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert GenericMatchInfo bestMatch = null; 6957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Find matches in the TimeZoneNames first 6977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Collection<MatchInfo> tznamesMatches = findTimeZoneNames(text, start, genericTypes); 6987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tznamesMatches != null) { 6997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert MatchInfo longestMatch = null; 7007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (MatchInfo match : tznamesMatches) { 7017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (longestMatch == null || match.matchLength() > longestMatch.matchLength()) { 7027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert longestMatch = match; 7037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (longestMatch != null) { 7067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert bestMatch = createGenericMatchInfo(longestMatch); 7077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (bestMatch.matchLength() == (text.length() - start)) { 7087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Full match 7097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //return bestMatch; 7107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO Some time zone uses a same name for the long standard name 7127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // and the location name. When the match is a long standard name, 7137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // then we need to check if the name is same with the location name. 7147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This is probably a data error or a design bug. 7157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// if (bestMatch.nameType != GenericNameType.LONG || bestMatch.timeType != TimeType.STANDARD) { 7167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// return bestMatch; 7177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// } 7187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO The deprecation of commonlyUsed flag introduced the name 7207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // conflict not only for long standard names, but short standard names too. 7217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // These short names (found in zh_Hant) should be gone once we clean 7227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // up CLDR time zone display name data. Once the short name conflict 7237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // problem (with location name) is resolved, we should change the condition 7247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // below back to the original one above. -Yoshito (2011-09-14) 7257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (bestMatch.timeType != TimeType.STANDARD) { 7267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return bestMatch; 7277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Find matches in the local trie 7337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Collection<GenericMatchInfo> localMatches = findLocal(text, start, genericTypes); 7347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (localMatches != null) { 7357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (GenericMatchInfo match : localMatches) { 7367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO See the above TODO. We use match.matchLength() >= bestMatch.matcheLength() 7377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // for the reason described above. 7387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //if (bestMatch == null || match.matchLength() > bestMatch.matchLength()) { 7397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (bestMatch == null || match.matchLength() >= bestMatch.matchLength()) { 7407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert bestMatch = match; 7417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return bestMatch; 7467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a collection of time zone display name matches for the specified types in the 7507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * given text at the given offset. 7517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param text the text 7527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param start the start offset in the text 7537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param genericTypes the set of name types. 7547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return A collection of match info. 7557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Collection<GenericMatchInfo> find(String text, int start, EnumSet<GenericNameType> genericTypes) { 7577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (text == null || text.length() == 0 || start < 0 || start >= text.length()) { 7587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("bad input text or range"); 7597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Find matches in the local trie 7617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Collection<GenericMatchInfo> results = findLocal(text, start, genericTypes); 7627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Also find matches in the TimeZoneNames 7647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Collection<MatchInfo> tznamesMatches = findTimeZoneNames(text, start, genericTypes); 7657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tznamesMatches != null) { 7667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // transform matches and append them to local matches 7677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (MatchInfo match : tznamesMatches) { 7687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (results == null) { 7697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert results = new LinkedList<GenericMatchInfo>(); 7707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert results.add(createGenericMatchInfo(match)); 7727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return results; 7757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a <code>GenericMatchInfo</code> for the given <code>MatchInfo</code>. 7797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param matchInfo the MatchInfo 7807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return A GenericMatchInfo 7817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private GenericMatchInfo createGenericMatchInfo(MatchInfo matchInfo) { 7837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert GenericNameType nameType = null; 7847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeType timeType = TimeType.UNKNOWN; 7857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch (matchInfo.nameType()) { 7867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case LONG_STANDARD: 7877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert nameType = GenericNameType.LONG; 7887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert timeType = TimeType.STANDARD; 7897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 7907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case LONG_GENERIC: 7917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert nameType = GenericNameType.LONG; 7927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 7937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case SHORT_STANDARD: 7947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert nameType = GenericNameType.SHORT; 7957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert timeType = TimeType.STANDARD; 7967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 7977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case SHORT_GENERIC: 7987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert nameType = GenericNameType.SHORT; 7997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 8007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert default: 8017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Unexpected MatchInfo name type - " + matchInfo.nameType()); 8027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String tzID = matchInfo.tzID(); 8057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tzID == null) { 8067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String mzID = matchInfo.mzID(); 8077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assert(mzID != null); 8087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tzID = _tznames.getReferenceZoneID(mzID, getTargetRegion()); 8097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert assert(tzID != null); 8117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert GenericMatchInfo gmatch = new GenericMatchInfo(); 8137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert gmatch.nameType = nameType; 8147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert gmatch.tzID = tzID; 8157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert gmatch.matchLength = matchInfo.matchLength(); 8167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert gmatch.timeType = timeType; 8177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return gmatch; 8197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a collection of time zone display name matches for the specified types in the 8237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * given text at the given offset. This method only finds matches from the TimeZoneNames 8247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * used by this object. 8257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param text the text 8267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param start the start offset in the text 8277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param types the set of name types. 8287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return A collection of match info. 8297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private Collection<MatchInfo> findTimeZoneNames(String text, int start, EnumSet<GenericNameType> types) { 8317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Collection<MatchInfo> tznamesMatches = null; 8327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Check if the target name type is really in the TimeZoneNames 8347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert EnumSet<NameType> nameTypes = EnumSet.noneOf(NameType.class); 8357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (types.contains(GenericNameType.LONG)) { 8367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert nameTypes.add(NameType.LONG_GENERIC); 8377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert nameTypes.add(NameType.LONG_STANDARD); 8387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (types.contains(GenericNameType.SHORT)) { 8407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert nameTypes.add(NameType.SHORT_GENERIC); 8417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert nameTypes.add(NameType.SHORT_STANDARD); 8427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!nameTypes.isEmpty()) { 8457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Find matches in the TimeZoneNames 8467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tznamesMatches = _tznames.find(text, start, nameTypes); 8477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return tznamesMatches; 8497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a collection of time zone display name matches for the specified types in the 8537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * given text at the given offset. This method only finds matches from the local trie, 8547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * that contains 1) generic location names and 2) long/short generic partial location names, 8557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * used by this object. 8567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param text the text 8577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param start the start offset in the text 8587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param types the set of name types. 8597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return A collection of match info. 8607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private synchronized Collection<GenericMatchInfo> findLocal(String text, int start, EnumSet<GenericNameType> types) { 8627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert GenericNameSearchHandler handler = new GenericNameSearchHandler(types); 8637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _gnamesTrie.find(text, start, handler); 8647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (handler.getMaxMatchLen() == (text.length() - start) || _gnamesTrieFullyLoaded) { 8657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // perfect match 8667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return handler.getMatches(); 8677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // All names are not yet loaded into the local trie. 8707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Load all available names into the trie. This could be very heavy. 8717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<String> tzIDs = TimeZone.getAvailableIDs(SystemTimeZoneType.CANONICAL, null, null); 8737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String tzID : tzIDs) { 8747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert loadStrings(tzID); 8757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _gnamesTrieFullyLoaded = true; 8777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // now, try it again 8797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert handler.resetResults(); 8807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _gnamesTrie.find(text, start, handler); 8817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return handler.getMatches(); 8827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>TimeZoneGenericNames</code> cache implementation. 8867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static class Cache extends SoftCache<String, TimeZoneGenericNames, ULocale> { 8887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* (non-Javadoc) 8907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.impl.CacheBase#createInstance(java.lang.Object, java.lang.Object) 8917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 8937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected TimeZoneGenericNames createInstance(String key, ULocale data) { 8947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new TimeZoneGenericNames(data).freeze(); 8957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 9007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The custom deserialization method. 9017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This implementation only read locale used by the object. 9027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 9047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert in.defaultReadObject(); 9057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert init(); 9067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@inheritDoc} 9107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isFrozen() { 9127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return _frozen; 9137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@inheritDoc} 9177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public TimeZoneGenericNames freeze() { 9197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _frozen = true; 9207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 9217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@inheritDoc} 9257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public TimeZoneGenericNames cloneAsThawed() { 9277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeZoneGenericNames copy = null; 9287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 9297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert copy = (TimeZoneGenericNames)super.clone(); 9307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert copy._frozen = false; 9317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (Throwable t) { 9327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This should never happen 9337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return copy; 9357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 937