|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.util.locale.provider; |
|
|
|
import java.text.spi.BreakIteratorProvider; |
|
import java.text.spi.CollatorProvider; |
|
import java.text.spi.DateFormatProvider; |
|
import java.text.spi.DateFormatSymbolsProvider; |
|
import java.text.spi.DecimalFormatSymbolsProvider; |
|
import java.text.spi.NumberFormatProvider; |
|
import java.util.ArrayList; |
|
import java.util.Collections; |
|
import java.util.List; |
|
import java.util.Locale; |
|
import java.util.Map; |
|
import java.util.ResourceBundle; |
|
import java.util.Set; |
|
import java.util.concurrent.ConcurrentHashMap; |
|
import java.util.concurrent.ConcurrentMap; |
|
import java.util.spi.CalendarDataProvider; |
|
import java.util.spi.CalendarNameProvider; |
|
import java.util.spi.CurrencyNameProvider; |
|
import java.util.spi.LocaleNameProvider; |
|
import java.util.spi.LocaleServiceProvider; |
|
import java.util.spi.TimeZoneNameProvider; |
|
import sun.security.action.GetPropertyAction; |
|
import sun.text.spi.JavaTimeDateTimePatternProvider; |
|
import sun.util.spi.CalendarProvider; |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract class LocaleProviderAdapter { |
|
|
|
|
|
*/ |
|
public static enum Type { |
|
JRE("sun.util.locale.provider.JRELocaleProviderAdapter", "sun.util.resources", "sun.text.resources"), |
|
CLDR("sun.util.cldr.CLDRLocaleProviderAdapter", "sun.util.resources.cldr", "sun.text.resources.cldr"), |
|
SPI("sun.util.locale.provider.SPILocaleProviderAdapter"), |
|
HOST("sun.util.locale.provider.HostLocaleProviderAdapter"), |
|
FALLBACK("sun.util.locale.provider.FallbackLocaleProviderAdapter", "sun.util.resources", "sun.text.resources"); |
|
|
|
private final String CLASSNAME; |
|
private final String UTIL_RESOURCES_PACKAGE; |
|
private final String TEXT_RESOURCES_PACKAGE; |
|
|
|
private Type(String className) { |
|
this(className, null, null); |
|
} |
|
|
|
private Type(String className, String util, String text) { |
|
CLASSNAME = className; |
|
UTIL_RESOURCES_PACKAGE = util; |
|
TEXT_RESOURCES_PACKAGE = text; |
|
} |
|
|
|
public String getAdapterClassName() { |
|
return CLASSNAME; |
|
} |
|
|
|
public String getUtilResourcesPackage() { |
|
return UTIL_RESOURCES_PACKAGE; |
|
} |
|
|
|
public String getTextResourcesPackage() { |
|
return TEXT_RESOURCES_PACKAGE; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static final List<Type> adapterPreference; |
|
|
|
|
|
|
|
*/ |
|
private static final Map<Type, LocaleProviderAdapter> adapterInstances = new ConcurrentHashMap<>(); |
|
|
|
|
|
|
|
|
|
*/ |
|
static volatile LocaleProviderAdapter.Type defaultLocaleProviderAdapter; |
|
|
|
|
|
|
|
*/ |
|
private static ConcurrentMap<Class<? extends LocaleServiceProvider>, ConcurrentMap<Locale, LocaleProviderAdapter>> |
|
adapterCache = new ConcurrentHashMap<>(); |
|
|
|
static { |
|
String order = GetPropertyAction.privilegedGetProperty("java.locale.providers"); |
|
List<Type> typeList = new ArrayList<>(); |
|
|
|
|
|
if (order != null && order.length() != 0) { |
|
String[] types = order.split(","); |
|
for (String type : types) { |
|
type = type.trim().toUpperCase(Locale.ROOT); |
|
if (type.equals("COMPAT")) { |
|
type = "JRE"; |
|
} |
|
try { |
|
Type aType = Type.valueOf(type.trim().toUpperCase(Locale.ROOT)); |
|
if (!typeList.contains(aType)) { |
|
typeList.add(aType); |
|
} |
|
} catch (IllegalArgumentException | UnsupportedOperationException e) { |
|
// could be caused by the user specifying wrong |
|
|
|
LocaleServiceProviderPool.config(LocaleProviderAdapter.class, e.toString()); |
|
} |
|
} |
|
} |
|
|
|
defaultLocaleProviderAdapter = Type.CLDR; |
|
if (!typeList.isEmpty()) { |
|
|
|
if (!(typeList.contains(Type.CLDR) || (typeList.contains(Type.JRE)))) { |
|
|
|
typeList.add(Type.FALLBACK); |
|
defaultLocaleProviderAdapter = Type.FALLBACK; |
|
} |
|
} else { |
|
|
|
typeList.add(Type.CLDR); |
|
typeList.add(Type.JRE); |
|
} |
|
adapterPreference = Collections.unmodifiableList(typeList); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static LocaleProviderAdapter forType(Type type) { |
|
switch (type) { |
|
case JRE: |
|
case CLDR: |
|
case SPI: |
|
case HOST: |
|
case FALLBACK: |
|
LocaleProviderAdapter adapter = null; |
|
LocaleProviderAdapter cached = adapterInstances.get(type); |
|
if (cached == null) { |
|
try { |
|
|
|
@SuppressWarnings("deprecation") |
|
Object tmp = Class.forName(type.getAdapterClassName()).newInstance(); |
|
adapter = (LocaleProviderAdapter)tmp; |
|
cached = adapterInstances.putIfAbsent(type, adapter); |
|
if (cached != null) { |
|
adapter = cached; |
|
} |
|
} catch (ClassNotFoundException | |
|
IllegalAccessException | |
|
InstantiationException | |
|
UnsupportedOperationException e) { |
|
LocaleServiceProviderPool.config(LocaleProviderAdapter.class, e.toString()); |
|
adapterInstances.putIfAbsent(type, NONEXISTENT_ADAPTER); |
|
if (defaultLocaleProviderAdapter == type) { |
|
defaultLocaleProviderAdapter = Type.FALLBACK; |
|
} |
|
} |
|
} else if (cached != NONEXISTENT_ADAPTER) { |
|
adapter = cached; |
|
} |
|
return adapter; |
|
default: |
|
throw new InternalError("unknown locale data adapter type"); |
|
} |
|
} |
|
|
|
public static LocaleProviderAdapter forJRE() { |
|
return forType(Type.JRE); |
|
} |
|
|
|
public static LocaleProviderAdapter getResourceBundleBased() { |
|
for (Type type : getAdapterPreference()) { |
|
if (type == Type.JRE || type == Type.CLDR || type == Type.FALLBACK) { |
|
LocaleProviderAdapter adapter = forType(type); |
|
if (adapter != null) { |
|
return adapter; |
|
} |
|
} |
|
} |
|
|
|
throw new InternalError(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static List<Type> getAdapterPreference() { |
|
return adapterPreference; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static LocaleProviderAdapter getAdapter(Class<? extends LocaleServiceProvider> providerClass, |
|
Locale locale) { |
|
LocaleProviderAdapter adapter; |
|
|
|
|
|
ConcurrentMap<Locale, LocaleProviderAdapter> adapterMap = adapterCache.get(providerClass); |
|
if (adapterMap != null) { |
|
if ((adapter = adapterMap.get(locale)) != null) { |
|
return adapter; |
|
} |
|
} else { |
|
adapterMap = new ConcurrentHashMap<>(); |
|
adapterCache.putIfAbsent(providerClass, adapterMap); |
|
} |
|
|
|
|
|
adapter = findAdapter(providerClass, locale); |
|
if (adapter != null) { |
|
adapterMap.putIfAbsent(locale, adapter); |
|
return adapter; |
|
} |
|
|
|
|
|
List<Locale> lookupLocales = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT) |
|
.getCandidateLocales("", locale); |
|
for (Locale loc : lookupLocales) { |
|
if (loc.equals(locale)) { |
|
|
|
continue; |
|
} |
|
adapter = findAdapter(providerClass, loc); |
|
if (adapter != null) { |
|
adapterMap.putIfAbsent(locale, adapter); |
|
return adapter; |
|
} |
|
} |
|
|
|
|
|
adapterMap.putIfAbsent(locale, forType(Type.FALLBACK)); |
|
return forType(Type.FALLBACK); |
|
} |
|
|
|
private static LocaleProviderAdapter findAdapter(Class<? extends LocaleServiceProvider> providerClass, |
|
Locale locale) { |
|
for (Type type : getAdapterPreference()) { |
|
LocaleProviderAdapter adapter = forType(type); |
|
if (adapter != null) { |
|
LocaleServiceProvider provider = adapter.getLocaleServiceProvider(providerClass); |
|
if (provider != null) { |
|
if (provider.isSupportedLocale(locale)) { |
|
return adapter; |
|
} |
|
} |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean isSupportedProviderLocale(Locale locale, Set<String> langtags) { |
|
LocaleProviderAdapter.Type type = getAdapterType(); |
|
assert type == Type.JRE || type == Type.CLDR || type == Type.FALLBACK; |
|
return false; |
|
} |
|
|
|
public static Locale[] toLocaleArray(Set<String> tags) { |
|
Locale[] locs = new Locale[tags.size() + 1]; |
|
int index = 0; |
|
locs[index++] = Locale.ROOT; |
|
for (String tag : tags) { |
|
switch (tag) { |
|
case "ja-JP-JP": |
|
locs[index++] = JRELocaleConstants.JA_JP_JP; |
|
break; |
|
case "th-TH-TH": |
|
locs[index++] = JRELocaleConstants.TH_TH_TH; |
|
break; |
|
default: |
|
locs[index++] = Locale.forLanguageTag(tag); |
|
break; |
|
} |
|
} |
|
return locs; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public abstract LocaleProviderAdapter.Type getAdapterType(); |
|
|
|
|
|
|
|
*/ |
|
public abstract <P extends LocaleServiceProvider> P getLocaleServiceProvider(Class<P> c); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract BreakIteratorProvider getBreakIteratorProvider(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract CollatorProvider getCollatorProvider(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract DateFormatProvider getDateFormatProvider(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract DateFormatSymbolsProvider getDateFormatSymbolsProvider(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract NumberFormatProvider getNumberFormatProvider(); |
|
|
|
/* |
|
* Getter methods for java.util.spi.* providers |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract CurrencyNameProvider getCurrencyNameProvider(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract LocaleNameProvider getLocaleNameProvider(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract TimeZoneNameProvider getTimeZoneNameProvider(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract CalendarDataProvider getCalendarDataProvider(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract CalendarNameProvider getCalendarNameProvider(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract CalendarProvider getCalendarProvider(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider(); |
|
|
|
public abstract LocaleResources getLocaleResources(Locale locale); |
|
|
|
public abstract Locale[] getAvailableLocales(); |
|
|
|
private static final LocaleProviderAdapter NONEXISTENT_ADAPTER = new NonExistentAdapter(); |
|
private static final class NonExistentAdapter extends FallbackLocaleProviderAdapter { |
|
@Override |
|
public LocaleProviderAdapter.Type getAdapterType() { |
|
return null; |
|
} |
|
|
|
private NonExistentAdapter() {}; |
|
} |
|
} |