Path: blob/master/src/java.base/share/classes/sun/util/locale/provider/SPILocaleProviderAdapter.java
41161 views
/*1* Copyright (c) 2012, 2021, 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.security.PrivilegedActionException;29import java.security.PrivilegedExceptionAction;30import java.text.BreakIterator;31import java.text.Collator;32import java.text.DateFormat;33import java.text.DateFormatSymbols;34import java.text.DecimalFormatSymbols;35import java.text.NumberFormat;36import java.text.spi.BreakIteratorProvider;37import java.text.spi.CollatorProvider;38import java.text.spi.DateFormatProvider;39import java.text.spi.DateFormatSymbolsProvider;40import java.text.spi.DecimalFormatSymbolsProvider;41import java.text.spi.NumberFormatProvider;42import java.util.Arrays;43import java.util.Locale;44import java.util.Map;45import java.util.ServiceConfigurationError;46import java.util.ServiceLoader;47import java.util.concurrent.ConcurrentHashMap;48import java.util.spi.CalendarDataProvider;49import java.util.spi.CalendarNameProvider;50import java.util.spi.CurrencyNameProvider;51import java.util.spi.LocaleNameProvider;52import java.util.spi.LocaleServiceProvider;53import java.util.spi.TimeZoneNameProvider;5455/**56* LocaleProviderAdapter implementation for the installed SPI implementations.57*58* @author Naoto Sato59* @author Masayoshi Okutsu60*/61public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter {6263/**64* Returns the type of this LocaleProviderAdapter65*/66@Override67public LocaleProviderAdapter.Type getAdapterType() {68return LocaleProviderAdapter.Type.SPI;69}7071@SuppressWarnings("removal")72@Override73protected <P extends LocaleServiceProvider> P findInstalledProvider(final Class<P> c) {74try {75return AccessController.doPrivileged(new PrivilegedExceptionAction<>() {76@Override77@SuppressWarnings(value={"unchecked", "deprecation"})78public P run() {79P delegate = null;8081for (LocaleServiceProvider provider :82ServiceLoader.load(c, ClassLoader.getSystemClassLoader())) {83if (delegate == null) {84try {85delegate =86(P) Class.forName(SPILocaleProviderAdapter.class.getCanonicalName() +87"$" +88c.getSimpleName() +89"Delegate")90.newInstance();91} catch (ClassNotFoundException |92InstantiationException |93IllegalAccessException e) {94throw new ServiceConfigurationError(95"SPI locale provider cannot be instantiated.", e);96}97}9899((Delegate)delegate).addImpl(provider);100}101return delegate;102}103});104} catch (PrivilegedActionException e) {105throw new ServiceConfigurationError(106"SPI locale provider cannot be instantiated.", e);107}108}109110/*111* Delegate interface. All the implementations have to have the class name112* following "<provider class name>Delegate" convention.113*/114private interface Delegate<P extends LocaleServiceProvider> {115default void addImpl(P impl) {116for (Locale l : impl.getAvailableLocales()) {117getDelegateMap().putIfAbsent(l, impl);118}119}120121/*122* Obtain the real SPI implementation, using locale fallback123*/124default P getImpl(Locale locale) {125for (Locale l : LocaleServiceProviderPool.getLookupLocales(locale.stripExtensions())) {126P ret = getDelegateMap().get(l);127if (ret != null) {128return ret;129}130}131return null;132}133134Map<Locale, P> getDelegateMap();135136default Locale[] getAvailableLocalesDelegate() {137return getDelegateMap().keySet().toArray(new Locale[0]);138}139140default boolean isSupportedLocaleDelegate(Locale locale) {141Map<Locale, P> map = getDelegateMap();142Locale override = CalendarDataUtility.findRegionOverride(locale);143144// First, call the method with extensions (if any)145P impl = map.get(override);146if (impl != null) {147return impl.isSupportedLocale(override);148} else {149// The default behavior150Locale overrideNoExt = override.stripExtensions();151impl = map.get(overrideNoExt);152if (impl != null) {153return Arrays.stream(impl.getAvailableLocales())154.anyMatch(overrideNoExt::equals);155}156}157158return false;159}160}161162/*163* Delegates for the actual SPI implementations.164*/165static class BreakIteratorProviderDelegate extends BreakIteratorProvider166implements Delegate<BreakIteratorProvider> {167private final Map<Locale, BreakIteratorProvider> map = new ConcurrentHashMap<>();168169@Override170public Map<Locale, BreakIteratorProvider> getDelegateMap() {171return map;172}173174@Override175public Locale[] getAvailableLocales() {176return getAvailableLocalesDelegate();177}178179@Override180public boolean isSupportedLocale(Locale locale) {181return isSupportedLocaleDelegate(locale);182}183184@Override185public BreakIterator getWordInstance(Locale locale) {186locale = CalendarDataUtility.findRegionOverride(locale);187BreakIteratorProvider bip = getImpl(locale);188return bip.getWordInstance(locale);189}190191@Override192public BreakIterator getLineInstance(Locale locale) {193locale = CalendarDataUtility.findRegionOverride(locale);194BreakIteratorProvider bip = getImpl(locale);195return bip.getLineInstance(locale);196}197198@Override199public BreakIterator getCharacterInstance(Locale locale) {200locale = CalendarDataUtility.findRegionOverride(locale);201BreakIteratorProvider bip = getImpl(locale);202return bip.getCharacterInstance(locale);203}204205@Override206public BreakIterator getSentenceInstance(Locale locale) {207locale = CalendarDataUtility.findRegionOverride(locale);208BreakIteratorProvider bip = getImpl(locale);209return bip.getSentenceInstance(locale);210}211212}213214static class CollatorProviderDelegate extends CollatorProvider implements Delegate<CollatorProvider> {215private final Map<Locale, CollatorProvider> map = new ConcurrentHashMap<>();216217@Override218public Map<Locale, CollatorProvider> getDelegateMap() {219return map;220}221222@Override223public Locale[] getAvailableLocales() {224return getAvailableLocalesDelegate();225}226227@Override228public boolean isSupportedLocale(Locale locale) {229return isSupportedLocaleDelegate(locale);230}231232@Override233public Collator getInstance(Locale locale) {234locale = CalendarDataUtility.findRegionOverride(locale);235CollatorProvider cp = getImpl(locale);236return cp.getInstance(locale);237}238}239240static class DateFormatProviderDelegate extends DateFormatProvider241implements Delegate<DateFormatProvider> {242private final Map<Locale, DateFormatProvider> map = new ConcurrentHashMap<>();243244@Override245public Map<Locale, DateFormatProvider> getDelegateMap() {246return map;247}248249@Override250public Locale[] getAvailableLocales() {251return getAvailableLocalesDelegate();252}253254@Override255public boolean isSupportedLocale(Locale locale) {256return isSupportedLocaleDelegate(locale);257}258259@Override260public DateFormat getTimeInstance(int style, Locale locale) {261locale = CalendarDataUtility.findRegionOverride(locale);262DateFormatProvider dfp = getImpl(locale);263return dfp.getTimeInstance(style, locale);264}265266@Override267public DateFormat getDateInstance(int style, Locale locale) {268locale = CalendarDataUtility.findRegionOverride(locale);269DateFormatProvider dfp = getImpl(locale);270return dfp.getDateInstance(style, locale);271}272273@Override274public DateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale locale) {275locale = CalendarDataUtility.findRegionOverride(locale);276DateFormatProvider dfp = getImpl(locale);277return dfp.getDateTimeInstance(dateStyle, timeStyle, locale);278}279}280281static class DateFormatSymbolsProviderDelegate extends DateFormatSymbolsProvider282implements Delegate<DateFormatSymbolsProvider> {283private final Map<Locale, DateFormatSymbolsProvider> map = new ConcurrentHashMap<>();284285@Override286public Map<Locale, DateFormatSymbolsProvider> getDelegateMap() {287return map;288}289290@Override291public Locale[] getAvailableLocales() {292return getAvailableLocalesDelegate();293}294295@Override296public boolean isSupportedLocale(Locale locale) {297return isSupportedLocaleDelegate(locale);298}299300@Override301public DateFormatSymbols getInstance(Locale locale) {302locale = CalendarDataUtility.findRegionOverride(locale);303DateFormatSymbolsProvider dfsp = getImpl(locale);304return dfsp.getInstance(locale);305}306}307308static class DecimalFormatSymbolsProviderDelegate extends DecimalFormatSymbolsProvider309implements Delegate<DecimalFormatSymbolsProvider> {310private final Map<Locale, DecimalFormatSymbolsProvider> map = new ConcurrentHashMap<>();311312@Override313public Map<Locale, DecimalFormatSymbolsProvider> getDelegateMap() {314return map;315}316317@Override318public Locale[] getAvailableLocales() {319return getAvailableLocalesDelegate();320}321322@Override323public boolean isSupportedLocale(Locale locale) {324return isSupportedLocaleDelegate(locale);325}326327@Override328public DecimalFormatSymbols getInstance(Locale locale) {329locale = CalendarDataUtility.findRegionOverride(locale);330DecimalFormatSymbolsProvider dfsp = getImpl(locale);331return dfsp.getInstance(locale);332}333}334335static class NumberFormatProviderDelegate extends NumberFormatProvider336implements Delegate<NumberFormatProvider> {337private final Map<Locale, NumberFormatProvider> map = new ConcurrentHashMap<>();338339@Override340public Map<Locale, NumberFormatProvider> getDelegateMap() {341return map;342}343344@Override345public Locale[] getAvailableLocales() {346return getAvailableLocalesDelegate();347}348349@Override350public boolean isSupportedLocale(Locale locale) {351return isSupportedLocaleDelegate(locale);352}353354@Override355public NumberFormat getCurrencyInstance(Locale locale) {356locale = CalendarDataUtility.findRegionOverride(locale);357NumberFormatProvider nfp = getImpl(locale);358return nfp.getCurrencyInstance(locale);359}360361@Override362public NumberFormat getIntegerInstance(Locale locale) {363locale = CalendarDataUtility.findRegionOverride(locale);364NumberFormatProvider nfp = getImpl(locale);365return nfp.getIntegerInstance(locale);366}367368@Override369public NumberFormat getNumberInstance(Locale locale) {370locale = CalendarDataUtility.findRegionOverride(locale);371NumberFormatProvider nfp = getImpl(locale);372return nfp.getNumberInstance(locale);373}374375@Override376public NumberFormat getPercentInstance(Locale locale) {377locale = CalendarDataUtility.findRegionOverride(locale);378NumberFormatProvider nfp = getImpl(locale);379return nfp.getPercentInstance(locale);380}381382@Override383public NumberFormat getCompactNumberInstance(Locale locale,384NumberFormat.Style style) {385locale = CalendarDataUtility.findRegionOverride(locale);386NumberFormatProvider nfp = getImpl(locale);387return nfp.getCompactNumberInstance(locale, style);388}389}390391static class CalendarDataProviderDelegate extends CalendarDataProvider392implements Delegate<CalendarDataProvider> {393private final Map<Locale, CalendarDataProvider> map = new ConcurrentHashMap<>();394395@Override396public Map<Locale, CalendarDataProvider> getDelegateMap() {397return map;398}399400@Override401public Locale[] getAvailableLocales() {402return getAvailableLocalesDelegate();403}404405@Override406public boolean isSupportedLocale(Locale locale) {407return isSupportedLocaleDelegate(locale);408}409410@Override411public int getFirstDayOfWeek(Locale locale) {412locale = CalendarDataUtility.findRegionOverride(locale);413CalendarDataProvider cdp = getImpl(locale);414return cdp.getFirstDayOfWeek(locale);415}416417@Override418public int getMinimalDaysInFirstWeek(Locale locale) {419locale = CalendarDataUtility.findRegionOverride(locale);420CalendarDataProvider cdp = getImpl(locale);421return cdp.getMinimalDaysInFirstWeek(locale);422}423}424425static class CalendarNameProviderDelegate extends CalendarNameProvider426implements Delegate<CalendarNameProvider> {427private final Map<Locale, CalendarNameProvider> map = new ConcurrentHashMap<>();428429@Override430public Map<Locale, CalendarNameProvider> getDelegateMap() {431return map;432}433434@Override435public Locale[] getAvailableLocales() {436return getAvailableLocalesDelegate();437}438439@Override440public boolean isSupportedLocale(Locale locale) {441return isSupportedLocaleDelegate(locale);442}443444@Override445public String getDisplayName(String calendarType,446int field, int value,447int style, Locale locale) {448locale = CalendarDataUtility.findRegionOverride(locale);449CalendarNameProvider cdp = getImpl(locale);450return cdp.getDisplayName(calendarType, field, value, style, locale);451}452453@Override454public Map<String, Integer> getDisplayNames(String calendarType,455int field, int style,456Locale locale) {457locale = CalendarDataUtility.findRegionOverride(locale);458CalendarNameProvider cdp = getImpl(locale);459return cdp.getDisplayNames(calendarType, field, style, locale);460}461}462463static class CurrencyNameProviderDelegate extends CurrencyNameProvider464implements Delegate<CurrencyNameProvider> {465private final Map<Locale, CurrencyNameProvider> map = new ConcurrentHashMap<>();466467@Override468public Map<Locale, CurrencyNameProvider> getDelegateMap() {469return map;470}471472@Override473public Locale[] getAvailableLocales() {474return getAvailableLocalesDelegate();475}476477@Override478public boolean isSupportedLocale(Locale locale) {479return isSupportedLocaleDelegate(locale);480}481482@Override483public String getSymbol(String currencyCode, Locale locale) {484locale = CalendarDataUtility.findRegionOverride(locale);485CurrencyNameProvider cnp = getImpl(locale);486return cnp.getSymbol(currencyCode, locale);487}488489@Override490public String getDisplayName(String currencyCode, Locale locale) {491locale = CalendarDataUtility.findRegionOverride(locale);492CurrencyNameProvider cnp = getImpl(locale);493return cnp.getDisplayName(currencyCode, locale);494}495}496497static class LocaleNameProviderDelegate extends LocaleNameProvider498implements Delegate<LocaleNameProvider> {499private final Map<Locale, LocaleNameProvider> map = new ConcurrentHashMap<>();500501@Override502public Map<Locale, LocaleNameProvider> getDelegateMap() {503return map;504}505506@Override507public Locale[] getAvailableLocales() {508return getAvailableLocalesDelegate();509}510511@Override512public boolean isSupportedLocale(Locale locale) {513return isSupportedLocaleDelegate(locale);514}515516@Override517public String getDisplayLanguage(String languageCode, Locale locale) {518locale = CalendarDataUtility.findRegionOverride(locale);519LocaleNameProvider lnp = getImpl(locale);520return lnp.getDisplayLanguage(languageCode, locale);521}522523@Override524public String getDisplayScript(String scriptCode, Locale locale) {525locale = CalendarDataUtility.findRegionOverride(locale);526LocaleNameProvider lnp = getImpl(locale);527return lnp.getDisplayScript(scriptCode, locale);528}529530@Override531public String getDisplayCountry(String countryCode, Locale locale) {532locale = CalendarDataUtility.findRegionOverride(locale);533LocaleNameProvider lnp = getImpl(locale);534return lnp.getDisplayCountry(countryCode, locale);535}536537@Override538public String getDisplayVariant(String variant, Locale locale) {539locale = CalendarDataUtility.findRegionOverride(locale);540LocaleNameProvider lnp = getImpl(locale);541return lnp.getDisplayVariant(variant, locale);542}543544@Override545public String getDisplayUnicodeExtensionKey(String key, Locale locale) {546locale = CalendarDataUtility.findRegionOverride(locale);547LocaleNameProvider lnp = getImpl(locale);548return lnp.getDisplayUnicodeExtensionKey(key, locale);549}550551@Override552public String getDisplayUnicodeExtensionType(String extType, String key, Locale locale) {553locale = CalendarDataUtility.findRegionOverride(locale);554LocaleNameProvider lnp = getImpl(locale);555return lnp.getDisplayUnicodeExtensionType(extType, key, locale);556}557}558559static class TimeZoneNameProviderDelegate extends TimeZoneNameProvider560implements Delegate<TimeZoneNameProvider> {561private final Map<Locale, TimeZoneNameProvider> map = new ConcurrentHashMap<>();562563@Override564public Map<Locale, TimeZoneNameProvider> getDelegateMap() {565return map;566}567568@Override569public Locale[] getAvailableLocales() {570return getAvailableLocalesDelegate();571}572573@Override574public boolean isSupportedLocale(Locale locale) {575return isSupportedLocaleDelegate(locale);576}577578@Override579public String getDisplayName(String ID, boolean daylight, int style, Locale locale) {580locale = CalendarDataUtility.findRegionOverride(locale);581TimeZoneNameProvider tznp = getImpl(locale);582return tznp.getDisplayName(ID, daylight, style, locale);583}584585@Override586public String getGenericDisplayName(String ID, int style, Locale locale) {587locale = CalendarDataUtility.findRegionOverride(locale);588TimeZoneNameProvider tznp = getImpl(locale);589return tznp.getGenericDisplayName(ID, style, locale);590}591}592}593594595