Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.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.io.File;28import java.security.AccessController;29import java.security.PrivilegedAction;30import java.text.spi.BreakIteratorProvider;31import java.text.spi.CollatorProvider;32import java.text.spi.DateFormatProvider;33import java.text.spi.DateFormatSymbolsProvider;34import java.text.spi.DecimalFormatSymbolsProvider;35import java.text.spi.NumberFormatProvider;36import java.util.Collections;37import java.util.HashSet;38import java.util.Locale;39import java.util.Set;40import java.util.StringTokenizer;41import java.util.concurrent.ConcurrentHashMap;42import java.util.concurrent.ConcurrentMap;43import java.util.spi.CalendarDataProvider;44import java.util.spi.CalendarNameProvider;45import java.util.spi.CurrencyNameProvider;46import java.util.spi.LocaleNameProvider;47import java.util.spi.LocaleServiceProvider;48import java.util.spi.TimeZoneNameProvider;49import sun.util.resources.LocaleData;50import sun.util.spi.CalendarProvider;5152/**53* LocaleProviderAdapter implementation for the legacy JRE locale data.54*55* @author Naoto Sato56* @author Masayoshi Okutsu57*/58public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements ResourceBundleBasedAdapter {5960private static final String LOCALE_DATA_JAR_NAME = "localedata.jar";6162private final ConcurrentMap<String, Set<String>> langtagSets63= new ConcurrentHashMap<>();6465private final ConcurrentMap<Locale, LocaleResources> localeResourcesMap66= new ConcurrentHashMap<>();6768// LocaleData specific to this LocaleProviderAdapter.69private volatile LocaleData localeData;7071/**72* Returns the type of this LocaleProviderAdapter73*/74@Override75public LocaleProviderAdapter.Type getAdapterType() {76return Type.JRE;77}7879/**80* Getter method for Locale Service Providers81*/82@Override83@SuppressWarnings("unchecked")84public <P extends LocaleServiceProvider> P getLocaleServiceProvider(Class<P> c) {85switch (c.getSimpleName()) {86case "BreakIteratorProvider":87return (P) getBreakIteratorProvider();88case "CollatorProvider":89return (P) getCollatorProvider();90case "DateFormatProvider":91return (P) getDateFormatProvider();92case "DateFormatSymbolsProvider":93return (P) getDateFormatSymbolsProvider();94case "DecimalFormatSymbolsProvider":95return (P) getDecimalFormatSymbolsProvider();96case "NumberFormatProvider":97return (P) getNumberFormatProvider();98case "CurrencyNameProvider":99return (P) getCurrencyNameProvider();100case "LocaleNameProvider":101return (P) getLocaleNameProvider();102case "TimeZoneNameProvider":103return (P) getTimeZoneNameProvider();104case "CalendarDataProvider":105return (P) getCalendarDataProvider();106case "CalendarNameProvider":107return (P) getCalendarNameProvider();108case "CalendarProvider":109return (P) getCalendarProvider();110default:111throw new InternalError("should not come down here");112}113}114115private volatile BreakIteratorProvider breakIteratorProvider = null;116private volatile CollatorProvider collatorProvider = null;117private volatile DateFormatProvider dateFormatProvider = null;118private volatile DateFormatSymbolsProvider dateFormatSymbolsProvider = null;119private volatile DecimalFormatSymbolsProvider decimalFormatSymbolsProvider = null;120private volatile NumberFormatProvider numberFormatProvider = null;121122private volatile CurrencyNameProvider currencyNameProvider = null;123private volatile LocaleNameProvider localeNameProvider = null;124private volatile TimeZoneNameProvider timeZoneNameProvider = null;125private volatile CalendarDataProvider calendarDataProvider = null;126private volatile CalendarNameProvider calendarNameProvider = null;127128private volatile CalendarProvider calendarProvider = null;129130/*131* Getter methods for java.text.spi.* providers132*/133@Override134public BreakIteratorProvider getBreakIteratorProvider() {135if (breakIteratorProvider == null) {136BreakIteratorProvider provider = new BreakIteratorProviderImpl(getAdapterType(),137getLanguageTagSet("FormatData"));138synchronized (this) {139if (breakIteratorProvider == null) {140breakIteratorProvider = provider;141}142}143}144return breakIteratorProvider;145}146147@Override148public CollatorProvider getCollatorProvider() {149if (collatorProvider == null) {150CollatorProvider provider = new CollatorProviderImpl(getAdapterType(),151getLanguageTagSet("CollationData"));152synchronized (this) {153if (collatorProvider == null) {154collatorProvider = provider;155}156}157}158return collatorProvider;159}160161@Override162public DateFormatProvider getDateFormatProvider() {163if (dateFormatProvider == null) {164DateFormatProvider provider = new DateFormatProviderImpl(getAdapterType(),165getLanguageTagSet("FormatData"));166synchronized (this) {167if (dateFormatProvider == null) {168dateFormatProvider = provider;169}170}171}172return dateFormatProvider;173}174175@Override176public DateFormatSymbolsProvider getDateFormatSymbolsProvider() {177if (dateFormatSymbolsProvider == null) {178DateFormatSymbolsProvider provider = new DateFormatSymbolsProviderImpl(getAdapterType(),179getLanguageTagSet("FormatData"));180synchronized (this) {181if (dateFormatSymbolsProvider == null) {182dateFormatSymbolsProvider = provider;183}184}185}186return dateFormatSymbolsProvider;187}188189@Override190public DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider() {191if (decimalFormatSymbolsProvider == null) {192DecimalFormatSymbolsProvider provider = new DecimalFormatSymbolsProviderImpl(getAdapterType(), getLanguageTagSet("FormatData"));193synchronized (this) {194if (decimalFormatSymbolsProvider == null) {195decimalFormatSymbolsProvider = provider;196}197}198}199return decimalFormatSymbolsProvider;200}201202@Override203public NumberFormatProvider getNumberFormatProvider() {204if (numberFormatProvider == null) {205NumberFormatProvider provider = new NumberFormatProviderImpl(getAdapterType(),206getLanguageTagSet("FormatData"));207synchronized (this) {208if (numberFormatProvider == null) {209numberFormatProvider = provider;210}211}212}213return numberFormatProvider;214}215216/**217* Getter methods for java.util.spi.* providers218*/219@Override220public CurrencyNameProvider getCurrencyNameProvider() {221if (currencyNameProvider == null) {222CurrencyNameProvider provider = new CurrencyNameProviderImpl(getAdapterType(),223getLanguageTagSet("CurrencyNames"));224synchronized (this) {225if (currencyNameProvider == null) {226currencyNameProvider = provider;227}228}229}230return currencyNameProvider;231}232233@Override234public LocaleNameProvider getLocaleNameProvider() {235if (localeNameProvider == null) {236LocaleNameProvider provider = new LocaleNameProviderImpl(getAdapterType(),237getLanguageTagSet("LocaleNames"));238synchronized (this) {239if (localeNameProvider == null) {240localeNameProvider = provider;241}242}243}244return localeNameProvider;245}246247@Override248public TimeZoneNameProvider getTimeZoneNameProvider() {249if (timeZoneNameProvider == null) {250TimeZoneNameProvider provider = new TimeZoneNameProviderImpl(getAdapterType(),251getLanguageTagSet("TimeZoneNames"));252synchronized (this) {253if (timeZoneNameProvider == null) {254timeZoneNameProvider = provider;255}256}257}258return timeZoneNameProvider;259}260261@Override262public CalendarDataProvider getCalendarDataProvider() {263if (calendarDataProvider == null) {264CalendarDataProvider provider;265provider = new CalendarDataProviderImpl(getAdapterType(),266getLanguageTagSet("CalendarData"));267synchronized (this) {268if (calendarDataProvider == null) {269calendarDataProvider = provider;270}271}272}273return calendarDataProvider;274}275276@Override277public CalendarNameProvider getCalendarNameProvider() {278if (calendarNameProvider == null) {279CalendarNameProvider provider;280provider = new CalendarNameProviderImpl(getAdapterType(),281getLanguageTagSet("FormatData"));282synchronized (this) {283if (calendarNameProvider == null) {284calendarNameProvider = provider;285}286}287}288return calendarNameProvider;289}290291/**292* Getter methods for sun.util.spi.* providers293*/294@Override295public CalendarProvider getCalendarProvider() {296if (calendarProvider == null) {297CalendarProvider provider = new CalendarProviderImpl(getAdapterType(),298getLanguageTagSet("CalendarData"));299synchronized (this) {300if (calendarProvider == null) {301calendarProvider = provider;302}303}304}305return calendarProvider;306}307308@Override309public LocaleResources getLocaleResources(Locale locale) {310LocaleResources lr = localeResourcesMap.get(locale);311if (lr == null) {312lr = new LocaleResources(this, locale);313LocaleResources lrc = localeResourcesMap.putIfAbsent(locale, lr);314if (lrc != null) {315lr = lrc;316}317}318return lr;319}320321// ResourceBundleBasedAdapter method implementation322@Override323public LocaleData getLocaleData() {324if (localeData == null) {325synchronized (this) {326if (localeData == null) {327localeData = new LocaleData(getAdapterType());328}329}330}331return localeData;332}333334/**335* Returns a list of the installed locales. Currently, this simply returns336* the list of locales for which a sun.text.resources.FormatData bundle337* exists. This bundle family happens to be the one with the broadest338* locale coverage in the JRE.339*/340@Override341public Locale[] getAvailableLocales() {342return AvailableJRELocales.localeList.clone();343}344345public Set<String> getLanguageTagSet(String category) {346Set<String> tagset = langtagSets.get(category);347if (tagset == null) {348tagset = createLanguageTagSet(category);349Set<String> ts = langtagSets.putIfAbsent(category, tagset);350if (ts != null) {351tagset = ts;352}353}354return tagset;355}356357protected Set<String> createLanguageTagSet(String category) {358String supportedLocaleString = LocaleDataMetaInfo.getSupportedLocaleString(category);359if (supportedLocaleString == null) {360return Collections.emptySet();361}362Set<String> tagset = new HashSet<>();363StringTokenizer tokens = new StringTokenizer(supportedLocaleString);364while (tokens.hasMoreTokens()) {365String token = tokens.nextToken();366if (token.equals("|")) {367if (isNonENLangSupported()) {368continue;369}370break;371}372tagset.add(token);373}374375return tagset;376}377378/**379* Lazy load available locales.380*/381private static class AvailableJRELocales {382private static final Locale[] localeList = createAvailableLocales();383private AvailableJRELocales() {384}385}386387private static Locale[] createAvailableLocales() {388/*389* Gets the locale string list from LocaleDataMetaInfo class and then390* contructs the Locale array and a set of language tags based on the391* locale string returned above.392*/393String supportedLocaleString = LocaleDataMetaInfo.getSupportedLocaleString("AvailableLocales");394395if (supportedLocaleString.length() == 0) {396throw new InternalError("No available locales for JRE");397}398399/*400* Look for "|" and construct a new locale string list.401*/402int barIndex = supportedLocaleString.indexOf('|');403StringTokenizer localeStringTokenizer;404if (isNonENLangSupported()) {405localeStringTokenizer = new StringTokenizer(supportedLocaleString.substring(0, barIndex)406+ supportedLocaleString.substring(barIndex + 1));407} else {408localeStringTokenizer = new StringTokenizer(supportedLocaleString.substring(0, barIndex));409}410411int length = localeStringTokenizer.countTokens();412Locale[] locales = new Locale[length + 1];413locales[0] = Locale.ROOT;414for (int i = 1; i <= length; i++) {415String currentToken = localeStringTokenizer.nextToken();416switch (currentToken) {417case "ja-JP-JP":418locales[i] = JRELocaleConstants.JA_JP_JP;419break;420case "no-NO-NY":421locales[i] = JRELocaleConstants.NO_NO_NY;422break;423case "th-TH-TH":424locales[i] = JRELocaleConstants.TH_TH_TH;425break;426default:427locales[i] = Locale.forLanguageTag(currentToken);428}429}430return locales;431}432433private static volatile Boolean isNonENSupported = null;434435/*436* Returns true if the non EN resources jar file exists in jre437* extension directory. @returns true if the jar file is there. Otherwise,438* returns false.439*/440private static boolean isNonENLangSupported() {441if (isNonENSupported == null) {442synchronized (JRELocaleProviderAdapter.class) {443if (isNonENSupported == null) {444final String sep = File.separator;445String localeDataJar =446java.security.AccessController.doPrivileged(447new sun.security.action.GetPropertyAction("java.home"))448+ sep + "lib" + sep + "ext" + sep + LOCALE_DATA_JAR_NAME;449450/*451* Peek at the installed extension directory to see if452* localedata.jar is installed or not.453*/454final File f = new File(localeDataJar);455isNonENSupported =456AccessController.doPrivileged(new PrivilegedAction<Boolean>() {457@Override458public Boolean run() {459return f.exists();460}461});462}463}464}465return isNonENSupported;466}467}468469470