Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java
38918 views
/*1* Copyright (c) 2012, 2015, 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.security.AccessController;28import java.text.spi.BreakIteratorProvider;29import java.text.spi.CollatorProvider;30import java.text.spi.DateFormatProvider;31import java.text.spi.DateFormatSymbolsProvider;32import java.text.spi.DecimalFormatSymbolsProvider;33import java.text.spi.NumberFormatProvider;34import java.util.ArrayList;35import java.util.Collections;36import java.util.List;37import java.util.Locale;38import java.util.ResourceBundle;39import java.util.Set;40import java.util.concurrent.ConcurrentHashMap;41import java.util.concurrent.ConcurrentMap;42import java.util.spi.CalendarDataProvider;43import java.util.spi.CalendarNameProvider;44import java.util.spi.CurrencyNameProvider;45import java.util.spi.LocaleNameProvider;46import java.util.spi.LocaleServiceProvider;47import java.util.spi.TimeZoneNameProvider;48import sun.util.cldr.CLDRLocaleProviderAdapter;49import sun.util.spi.CalendarProvider;5051/**52* The LocaleProviderAdapter abstract class.53*54* @author Naoto Sato55* @author Masayoshi Okutsu56*/57public abstract class LocaleProviderAdapter {58/**59* Adapter type.60*/61public static enum Type {62JRE("sun.util.resources", "sun.text.resources"),63CLDR("sun.util.resources.cldr", "sun.text.resources.cldr"),64SPI,65HOST,66FALLBACK("sun.util.resources", "sun.text.resources");6768private final String UTIL_RESOURCES_PACKAGE;69private final String TEXT_RESOURCES_PACKAGE;7071private Type() {72this(null, null);73}7475private Type(String util, String text) {76UTIL_RESOURCES_PACKAGE = util;77TEXT_RESOURCES_PACKAGE = text;78}7980public String getUtilResourcesPackage() {81return UTIL_RESOURCES_PACKAGE;82}8384public String getTextResourcesPackage() {85return TEXT_RESOURCES_PACKAGE;86}87}8889/**90* LocaleProviderAdapter preference list. The default list is intended91* to behave the same manner in JDK7.92*/93private static final List<Type> adapterPreference;9495/**96* JRE Locale Data Adapter instance97*/98private static LocaleProviderAdapter jreLocaleProviderAdapter = new JRELocaleProviderAdapter();99100/**101* SPI Locale Data Adapter instance102*/103private static LocaleProviderAdapter spiLocaleProviderAdapter = new SPILocaleProviderAdapter();104105/**106* CLDR Locale Data Adapter instance, if any.107*/108private static LocaleProviderAdapter cldrLocaleProviderAdapter = null;109110/**111* HOST Locale Data Adapter instance, if any.112*/113private static LocaleProviderAdapter hostLocaleProviderAdapter = null;114115/**116* FALLBACK Locale Data Adapter instance. It's basically the same with JRE, but only kicks117* in for the root locale.118*/119private static LocaleProviderAdapter fallbackLocaleProviderAdapter = null;120121/**122* Default fallback adapter type, which should return something meaningful in any case.123* This is either JRE or FALLBACK.124*/125static LocaleProviderAdapter.Type defaultLocaleProviderAdapter = null;126127/**128* Adapter lookup cache.129*/130private static ConcurrentMap<Class<? extends LocaleServiceProvider>, ConcurrentMap<Locale, LocaleProviderAdapter>>131adapterCache = new ConcurrentHashMap<>();132133static {134String order = AccessController.doPrivileged(135new sun.security.action.GetPropertyAction("java.locale.providers"));136List<Type> typeList = new ArrayList<>();137138// Check user specified adapter preference139if (order != null && order.length() != 0) {140String[] types = order.split(",");141for (String type : types) {142try {143Type aType = Type.valueOf(type.trim().toUpperCase(Locale.ROOT));144145// load adapter if necessary146switch (aType) {147case CLDR:148if (cldrLocaleProviderAdapter == null) {149cldrLocaleProviderAdapter = new CLDRLocaleProviderAdapter();150}151break;152case HOST:153if (hostLocaleProviderAdapter == null) {154hostLocaleProviderAdapter = new HostLocaleProviderAdapter();155}156break;157}158if (!typeList.contains(aType)) {159typeList.add(aType);160}161} catch (IllegalArgumentException | UnsupportedOperationException e) {162// could be caused by the user specifying wrong163// provider name or format in the system property164LocaleServiceProviderPool.config(LocaleProviderAdapter.class, e.toString());165}166}167}168169if (!typeList.isEmpty()) {170if (!typeList.contains(Type.JRE)) {171// Append FALLBACK as the last resort.172fallbackLocaleProviderAdapter = new FallbackLocaleProviderAdapter();173typeList.add(Type.FALLBACK);174defaultLocaleProviderAdapter = Type.FALLBACK;175} else {176defaultLocaleProviderAdapter = Type.JRE;177}178} else {179// Default preference list180typeList.add(Type.JRE);181typeList.add(Type.SPI);182defaultLocaleProviderAdapter = Type.JRE;183}184185adapterPreference = Collections.unmodifiableList(typeList);186}187188/**189* Returns the singleton instance for each adapter type190*/191public static LocaleProviderAdapter forType(Type type) {192switch (type) {193case JRE:194return jreLocaleProviderAdapter;195case CLDR:196return cldrLocaleProviderAdapter;197case SPI:198return spiLocaleProviderAdapter;199case HOST:200return hostLocaleProviderAdapter;201case FALLBACK:202return fallbackLocaleProviderAdapter;203default:204throw new InternalError("unknown locale data adapter type");205}206}207208public static LocaleProviderAdapter forJRE() {209return jreLocaleProviderAdapter;210}211212public static LocaleProviderAdapter getResourceBundleBased() {213for (Type type : getAdapterPreference()) {214if (type == Type.JRE || type == Type.CLDR || type == Type.FALLBACK) {215return forType(type);216}217}218// Shouldn't happen.219throw new InternalError();220}221/**222* Returns the preference order of LocaleProviderAdapter.Type223*/224public static List<Type> getAdapterPreference() {225return adapterPreference;226}227228/**229* Returns a LocaleProviderAdapter for the given locale service provider that230* best matches the given locale. This method returns the LocaleProviderAdapter231* for JRE if none is found for the given locale.232*233* @param providerClass the class for the locale service provider234* @param locale the desired locale.235* @return a LocaleProviderAdapter236*/237public static LocaleProviderAdapter getAdapter(Class<? extends LocaleServiceProvider> providerClass,238Locale locale) {239LocaleProviderAdapter adapter;240241// cache lookup242ConcurrentMap<Locale, LocaleProviderAdapter> adapterMap = adapterCache.get(providerClass);243if (adapterMap != null) {244if ((adapter = adapterMap.get(locale)) != null) {245return adapter;246}247} else {248adapterMap = new ConcurrentHashMap<>();249adapterCache.putIfAbsent(providerClass, adapterMap);250}251252// Fast look-up for the given locale253adapter = findAdapter(providerClass, locale);254if (adapter != null) {255adapterMap.putIfAbsent(locale, adapter);256return adapter;257}258259// Try finding an adapter in the normal candidate locales path of the given locale.260List<Locale> lookupLocales = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT)261.getCandidateLocales("", locale);262for (Locale loc : lookupLocales) {263if (loc.equals(locale)) {264// We've already done with this loc.265continue;266}267adapter = findAdapter(providerClass, loc);268if (adapter != null) {269adapterMap.putIfAbsent(locale, adapter);270return adapter;271}272}273274// returns the adapter for FALLBACK as the last resort275adapterMap.putIfAbsent(locale, fallbackLocaleProviderAdapter);276return fallbackLocaleProviderAdapter;277}278279private static LocaleProviderAdapter findAdapter(Class<? extends LocaleServiceProvider> providerClass,280Locale locale) {281for (Type type : getAdapterPreference()) {282LocaleProviderAdapter adapter = forType(type);283LocaleServiceProvider provider = adapter.getLocaleServiceProvider(providerClass);284if (provider != null) {285if (provider.isSupportedLocale(locale)) {286return adapter;287}288}289}290return null;291}292293/**294* A utility method for implementing the default LocaleServiceProvider.isSupportedLocale295* for the JRE, CLDR, and FALLBACK adapters.296*/297public static boolean isSupportedLocale(Locale locale, LocaleProviderAdapter.Type type, Set<String> langtags) {298assert type == Type.JRE || type == Type.CLDR || type == Type.FALLBACK;299if (Locale.ROOT.equals(locale)) {300return true;301}302303if (type == Type.FALLBACK) {304// no other locales except ROOT are supported for FALLBACK305return false;306}307308locale = locale.stripExtensions();309if (langtags.contains(locale.toLanguageTag())) {310return true;311}312if (type == Type.JRE) {313String oldname = locale.toString().replace('_', '-');314return langtags.contains(oldname) ||315"ja-JP-JP".equals(oldname) ||316"th-TH-TH".equals(oldname) ||317"no-NO-NY".equals(oldname);318}319return false;320}321322public static Locale[] toLocaleArray(Set<String> tags) {323Locale[] locs = new Locale[tags.size() + 1];324int index = 0;325locs[index++] = Locale.ROOT;326for (String tag : tags) {327switch (tag) {328case "ja-JP-JP":329locs[index++] = JRELocaleConstants.JA_JP_JP;330break;331case "th-TH-TH":332locs[index++] = JRELocaleConstants.TH_TH_TH;333break;334default:335locs[index++] = Locale.forLanguageTag(tag);336break;337}338}339return locs;340}341342/**343* Returns the type of this LocaleProviderAdapter344*/345public abstract LocaleProviderAdapter.Type getAdapterType();346347/**348* Getter method for Locale Service Providers.349*/350public abstract <P extends LocaleServiceProvider> P getLocaleServiceProvider(Class<P> c);351352/**353* Returns a BreakIteratorProvider for this LocaleProviderAdapter, or null if no354* BreakIteratorProvider is available.355*356* @return a BreakIteratorProvider357*/358public abstract BreakIteratorProvider getBreakIteratorProvider();359360/**361* Returns a ollatorProvider for this LocaleProviderAdapter, or null if no362* ollatorProvider is available.363*364* @return a ollatorProvider365*/366public abstract CollatorProvider getCollatorProvider();367368/**369* Returns a DateFormatProvider for this LocaleProviderAdapter, or null if no370* DateFormatProvider is available.371*372* @return a DateFormatProvider373*/374public abstract DateFormatProvider getDateFormatProvider();375376/**377* Returns a DateFormatSymbolsProvider for this LocaleProviderAdapter, or null if no378* DateFormatSymbolsProvider is available.379*380* @return a DateFormatSymbolsProvider381*/382public abstract DateFormatSymbolsProvider getDateFormatSymbolsProvider();383384/**385* Returns a DecimalFormatSymbolsProvider for this LocaleProviderAdapter, or null if no386* DecimalFormatSymbolsProvider is available.387*388* @return a DecimalFormatSymbolsProvider389*/390public abstract DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider();391392/**393* Returns a NumberFormatProvider for this LocaleProviderAdapter, or null if no394* NumberFormatProvider is available.395*396* @return a NumberFormatProvider397*/398public abstract NumberFormatProvider getNumberFormatProvider();399400/*401* Getter methods for java.util.spi.* providers402*/403404/**405* Returns a CurrencyNameProvider for this LocaleProviderAdapter, or null if no406* CurrencyNameProvider is available.407*408* @return a CurrencyNameProvider409*/410public abstract CurrencyNameProvider getCurrencyNameProvider();411412/**413* Returns a LocaleNameProvider for this LocaleProviderAdapter, or null if no414* LocaleNameProvider is available.415*416* @return a LocaleNameProvider417*/418public abstract LocaleNameProvider getLocaleNameProvider();419420/**421* Returns a TimeZoneNameProvider for this LocaleProviderAdapter, or null if no422* TimeZoneNameProvider is available.423*424* @return a TimeZoneNameProvider425*/426public abstract TimeZoneNameProvider getTimeZoneNameProvider();427428/**429* Returns a CalendarDataProvider for this LocaleProviderAdapter, or null if no430* CalendarDataProvider is available.431*432* @return a CalendarDataProvider433*/434public abstract CalendarDataProvider getCalendarDataProvider();435436/**437* Returns a CalendarNameProvider for this LocaleProviderAdapter, or null if no438* CalendarNameProvider is available.439*440* @return a CalendarNameProvider441*/442public abstract CalendarNameProvider getCalendarNameProvider();443444/**445* Returns a CalendarProvider for this LocaleProviderAdapter, or null if no446* CalendarProvider is available.447*448* @return a CalendarProvider449*/450public abstract CalendarProvider getCalendarProvider();451452public abstract LocaleResources getLocaleResources(Locale locale);453454public abstract Locale[] getAvailableLocales();455}456457458