Path: blob/master/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java
41161 views
/*1* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.util.locale.provider;2627import java.lang.ref.SoftReference;28import java.util.LinkedList;29import java.util.List;30import java.util.Locale;31import java.util.Map;32import java.util.Objects;33import java.util.Optional;34import java.util.Set;35import java.util.concurrent.ConcurrentHashMap;36import java.util.spi.TimeZoneNameProvider;37import sun.util.calendar.ZoneInfo;38import sun.util.cldr.CLDRLocaleProviderAdapter;39import static sun.util.locale.provider.LocaleProviderAdapter.Type;4041/**42* Utility class that deals with the localized time zone names43*44* @author Naoto Sato45* @author Masayoshi Okutsu46*/47public final class TimeZoneNameUtility {4849/**50* cache to hold time zone localized strings. Keyed by Locale51*/52private static final ConcurrentHashMap<Locale, SoftReference<String[][]>> cachedZoneData =53new ConcurrentHashMap<>();5455/**56* Cache for managing display names per timezone per locale57* The structure is:58* Map(key=id, value=SoftReference(Map(key=locale, value=displaynames)))59*/60private static final Map<String, SoftReference<Map<Locale, String[]>>> cachedDisplayNames =61new ConcurrentHashMap<>();6263/**64* get time zone localized strings. Enumerate all keys.65*/66public static String[][] getZoneStrings(Locale locale) {67String[][] zones;68SoftReference<String[][]> data = cachedZoneData.get(locale);6970if (data == null || ((zones = data.get()) == null)) {71zones = loadZoneStrings(locale);72data = new SoftReference<>(zones);73cachedZoneData.put(locale, data);74}7576return zones;77}7879private static String[][] loadZoneStrings(Locale locale) {80// If the provider is a TimeZoneNameProviderImpl, call its getZoneStrings81// in order to avoid per-ID retrieval.82LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(TimeZoneNameProvider.class, locale);83TimeZoneNameProvider provider = adapter.getTimeZoneNameProvider();84if (provider instanceof TimeZoneNameProviderImpl) {85String[][] zoneStrings = ((TimeZoneNameProviderImpl)provider).getZoneStrings(locale);8687if (zoneStrings.length == 0 && locale.equals(Locale.ROOT)) {88// Unlike other *Name provider, zoneStrings search won't do the fallback89// name search. If the ResourceBundle found for the root locale contains no90// zoneStrings, just use the one for English, assuming English bundle91// contains all the tzids and their names.92zoneStrings= getZoneStrings(Locale.ENGLISH);93}9495return zoneStrings;96}9798// Performs per-ID retrieval.99Set<String> zoneIDs = LocaleProviderAdapter.forJRE().getLocaleResources(locale).getZoneIDs();100List<String[]> zones = new LinkedList<>();101for (String key : zoneIDs) {102String[] names = retrieveDisplayNamesImpl(key, locale);103if (names != null) {104zones.add(names);105}106}107108String[][] zonesArray = new String[zones.size()][];109return zones.toArray(zonesArray);110}111112/**113* Retrieve display names for a time zone ID.114*/115public static String[] retrieveDisplayNames(String id, Locale locale) {116Objects.requireNonNull(id);117Objects.requireNonNull(locale);118119return retrieveDisplayNamesImpl(id, locale);120}121122/**123* Retrieves a generic time zone display name for a time zone ID.124*125* @param id time zone ID126* @param style TimeZone.LONG or TimeZone.SHORT127* @param locale desired Locale128* @return the requested generic time zone display name, or null if not found.129*/130public static String retrieveGenericDisplayName(String id, int style, Locale locale) {131String[] names = retrieveDisplayNamesImpl(id, locale);132if (Objects.nonNull(names)) {133return names[6 - style];134} else {135return null;136}137}138139/**140* Retrieves a standard or daylight-saving time name for the given time zone ID.141*142* @param id time zone ID143* @param daylight true for a daylight saving time name, or false for a standard time name144* @param style TimeZone.LONG or TimeZone.SHORT145* @param locale desired Locale146* @return the requested time zone name, or null if not found.147*/148public static String retrieveDisplayName(String id, boolean daylight, int style, Locale locale) {149String[] names = retrieveDisplayNamesImpl(id, locale);150if (Objects.nonNull(names)) {151return names[(daylight ? 4 : 2) - style];152} else {153return null;154}155}156157/**158* Converts the time zone id from LDML's 5-letter id to tzdb's id159*160* @param shortID time zone short ID defined in LDML161* @return the tzdb's time zone ID162*/163public static Optional<String> convertLDMLShortID(String shortID) {164return canonicalTZID(shortID);165}166167/**168* Returns the canonical ID for the given ID169*/170public static Optional<String> canonicalTZID(String id) {171return ((CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(Type.CLDR))172.canonicalTZID(id);173}174175private static String[] retrieveDisplayNamesImpl(String id, Locale locale) {176LocaleServiceProviderPool pool =177LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class);178String[] names;179Map<Locale, String[]> perLocale = null;180181SoftReference<Map<Locale, String[]>> ref = cachedDisplayNames.get(id);182if (Objects.nonNull(ref)) {183perLocale = ref.get();184if (Objects.nonNull(perLocale)) {185names = perLocale.get(locale);186if (Objects.nonNull(names)) {187return names;188}189}190}191192// build names array193names = new String[7];194names[0] = id;195for (int i = 1; i <= 6; i ++) {196names[i] = pool.getLocalizedObject(TimeZoneNameGetter.INSTANCE, locale,197i<5 ? (i<3 ? "std" : "dst") : "generic", i%2, id);198}199200if (Objects.isNull(perLocale)) {201perLocale = new ConcurrentHashMap<>();202}203perLocale.put(locale, names);204ref = new SoftReference<>(perLocale);205cachedDisplayNames.put(id, ref);206return names;207}208209210/**211* Obtains a localized time zone strings from a TimeZoneNameProvider212* implementation.213*/214private static class TimeZoneNameGetter215implements LocaleServiceProviderPool.LocalizedObjectGetter<TimeZoneNameProvider,216String> {217private static final TimeZoneNameGetter INSTANCE =218new TimeZoneNameGetter();219220@Override221public String getObject(TimeZoneNameProvider timeZoneNameProvider,222Locale locale,223String requestID,224Object... params) {225assert params.length == 2;226int style = (int) params[0];227String tzid = (String) params[1];228String value = getName(timeZoneNameProvider, locale, requestID, style, tzid);229if (value == null) {230Map<String, String> aliases = ZoneInfo.getAliasTable();231if (aliases != null) {232String canonicalID = aliases.get(tzid);233if (canonicalID != null) {234value = getName(timeZoneNameProvider, locale, requestID, style, canonicalID);235}236if (value == null) {237value = examineAliases(timeZoneNameProvider, locale, requestID,238canonicalID != null ? canonicalID : tzid, style, aliases);239}240}241}242243return value;244}245246private static String examineAliases(TimeZoneNameProvider tznp, Locale locale,247String requestID, String tzid, int style,248Map<String, String> aliases) {249for (Map.Entry<String, String> entry : aliases.entrySet()) {250if (entry.getValue().equals(tzid)) {251String alias = entry.getKey();252String name = getName(tznp, locale, requestID, style, alias);253if (name != null) {254return name;255}256name = examineAliases(tznp, locale, requestID, alias, style, aliases);257if (name != null) {258return name;259}260}261}262return null;263}264265private static String getName(TimeZoneNameProvider timeZoneNameProvider,266Locale locale, String requestID, int style, String tzid) {267String value = null;268switch (requestID) {269case "std":270value = timeZoneNameProvider.getDisplayName(tzid, false, style, locale);271break;272case "dst":273value = timeZoneNameProvider.getDisplayName(tzid, true, style, locale);274break;275case "generic":276value = timeZoneNameProvider.getGenericDisplayName(tzid, style, locale);277break;278}279return value;280}281}282283// No instantiation284private TimeZoneNameUtility() {285}286}287288289