Path: blob/master/src/java.base/share/classes/sun/util/resources/LocaleData.java
41159 views
/*1* Copyright (c) 1996, 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*/2425/*26* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved27* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved28*29* The original version of this source code and documentation30* is copyrighted and owned by Taligent, Inc., a wholly-owned31* subsidiary of IBM. These materials are provided under terms32* of a License Agreement between Taligent and Sun. This technology33* is protected by multiple US and International patents.34*35* This notice and attribution to Taligent may not be removed.36* Taligent is a registered trademark of Taligent, Inc.37*38*/3940package sun.util.resources;4142import java.security.AccessController;43import java.security.PrivilegedAction;44import java.util.Arrays;45import java.util.Iterator;46import java.util.List;47import java.util.Locale;48import java.util.Map;49import java.util.MissingResourceException;50import java.util.ResourceBundle;51import java.util.Set;52import java.util.concurrent.ConcurrentHashMap;53import java.util.spi.ResourceBundleProvider;54import sun.util.locale.provider.JRELocaleProviderAdapter;55import sun.util.locale.provider.LocaleProviderAdapter;56import static sun.util.locale.provider.LocaleProviderAdapter.Type.CLDR;57import static sun.util.locale.provider.LocaleProviderAdapter.Type.JRE;58import sun.util.locale.provider.ResourceBundleBasedAdapter;5960/**61* Provides information about and access to resource bundles in the62* sun.text.resources and sun.util.resources packages or in their corresponding63* packages for CLDR.64*65* @author Asmus Freytag66* @author Mark Davis67*/6869public class LocaleData {70private static final ResourceBundle.Control defaultControl71= ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT);7273private static final String DOTCLDR = ".cldr";7475// Map of key (base name + locale) to candidates76private static final Map<String, List<Locale>> CANDIDATES_MAP = new ConcurrentHashMap<>();7778private final LocaleProviderAdapter.Type type;7980public LocaleData(LocaleProviderAdapter.Type type) {81this.type = type;82}8384/**85* Gets a calendar data resource bundle, using privileges86* to allow accessing a sun.* package.87*/88public ResourceBundle getCalendarData(Locale locale) {89return getBundle(type.getUtilResourcesPackage() + ".CalendarData", locale);90}9192/**93* Gets a currency names resource bundle, using privileges94* to allow accessing a sun.* package.95*/96public OpenListResourceBundle getCurrencyNames(Locale locale) {97return (OpenListResourceBundle) getBundle(type.getUtilResourcesPackage() + ".CurrencyNames", locale);98}99100/**101* Gets a locale names resource bundle, using privileges102* to allow accessing a sun.* package.103*/104public OpenListResourceBundle getLocaleNames(Locale locale) {105return (OpenListResourceBundle) getBundle(type.getUtilResourcesPackage() + ".LocaleNames", locale);106}107108/**109* Gets a time zone names resource bundle, using privileges110* to allow accessing a sun.* package.111*/112public TimeZoneNamesBundle getTimeZoneNames(Locale locale) {113return (TimeZoneNamesBundle) getBundle(type.getUtilResourcesPackage() + ".TimeZoneNames", locale);114}115116/**117* Gets a break iterator info resource bundle, using privileges118* to allow accessing a sun.* package.119*/120public ResourceBundle getBreakIteratorInfo(Locale locale) {121return getBundle(type.getTextResourcesPackage() + ".BreakIteratorInfo", locale);122}123124/**125* Gets a break iterator resources resource bundle, using126* privileges to allow accessing a sun.* package.127*/128public ResourceBundle getBreakIteratorResources(Locale locale) {129return getBundle(type.getTextResourcesPackage() + ".BreakIteratorResources", locale);130}131132/**133* Gets a collation data resource bundle, using privileges134* to allow accessing a sun.* package.135*/136public ResourceBundle getCollationData(Locale locale) {137return getBundle(type.getTextResourcesPackage() + ".CollationData", locale);138}139140/**141* Gets a date format data resource bundle, using privileges142* to allow accessing a sun.* package.143*/144public ResourceBundle getDateFormatData(Locale locale) {145return getBundle(type.getTextResourcesPackage() + ".FormatData", locale);146}147148public void setSupplementary(ParallelListResourceBundle formatData) {149if (!formatData.areParallelContentsComplete()) {150String suppName = type.getTextResourcesPackage() + ".JavaTimeSupplementary";151setSupplementary(suppName, formatData);152}153}154155private boolean setSupplementary(String suppName, ParallelListResourceBundle formatData) {156ParallelListResourceBundle parent = (ParallelListResourceBundle) formatData.getParent();157boolean resetKeySet = false;158if (parent != null) {159resetKeySet = setSupplementary(suppName, parent);160}161OpenListResourceBundle supp = getSupplementary(suppName, formatData.getLocale());162formatData.setParallelContents(supp);163resetKeySet |= supp != null;164// If any parents or this bundle has parallel data, reset keyset to create165// a new keyset with the data.166if (resetKeySet) {167formatData.resetKeySet();168}169return resetKeySet;170}171172/**173* Gets a number format data resource bundle, using privileges174* to allow accessing a sun.* package.175*/176public ResourceBundle getNumberFormatData(Locale locale) {177return getBundle(type.getTextResourcesPackage() + ".FormatData", locale);178}179180@SuppressWarnings("removal")181public static ResourceBundle getBundle(final String baseName, final Locale locale) {182return AccessController.doPrivileged(new PrivilegedAction<>() {183@Override184public ResourceBundle run() {185return Bundles.of(baseName, locale, LocaleDataStrategy.INSTANCE);186}187});188}189190@SuppressWarnings("removal")191private static OpenListResourceBundle getSupplementary(final String baseName, final Locale locale) {192return AccessController.doPrivileged(new PrivilegedAction<>() {193@Override194public OpenListResourceBundle run() {195OpenListResourceBundle rb = null;196try {197rb = (OpenListResourceBundle) Bundles.of(baseName, locale,198SupplementaryStrategy.INSTANCE);199} catch (MissingResourceException e) {200// return null if no supplementary is available201}202return rb;203}204});205}206207private static abstract class LocaleDataResourceBundleProvider208implements ResourceBundleProvider {209/**210* Changes baseName to its module dependent package name and211* calls the super class implementation. For example,212* if the baseName is "sun.text.resources.FormatData" and locale is ja_JP,213* the baseName is changed to "sun.text.resources.ext.FormatData". If214* baseName contains ".cldr", such as "sun.text.resources.cldr.FormatData",215* the name is changed to "sun.text.resources.cldr.ext.FormatData".216*/217protected String toBundleName(String baseName, Locale locale) {218return LocaleDataStrategy.INSTANCE.toBundleName(baseName, locale);219}220221/**222* Retrieves the other bundle name for legacy ISO 639 languages.223*/224protected String toOtherBundleName(String baseName, String bundleName, Locale locale) {225return Bundles.toOtherBundleName(baseName, bundleName, locale);226}227}228229/**230* A ResourceBundleProvider implementation for loading locale data231* resource bundles except for the java.time supplementary data.232*/233public static abstract class CommonResourceBundleProvider extends LocaleDataResourceBundleProvider {234}235236/**237* A ResourceBundleProvider implementation for loading supplementary238* resource bundles for java.time.239*/240public static abstract class SupplementaryResourceBundleProvider extends LocaleDataResourceBundleProvider {241}242243// Bundles.Strategy implementations244245private static class LocaleDataStrategy implements Bundles.Strategy {246private static final LocaleDataStrategy INSTANCE = new LocaleDataStrategy();247// TODO: avoid hard-coded Locales248private static Set<Locale> JAVA_BASE_LOCALES249= Set.of(Locale.ROOT, Locale.ENGLISH, Locale.US, new Locale("en", "US", "POSIX"));250251private LocaleDataStrategy() {252}253254/*255* This method overrides the default implementation to search256* from a prebaked locale string list to determin the candidate257* locale list.258*259* @param baseName the resource bundle base name.260* locale the requested locale for the resource bundle.261* @return a list of candidate locales to search from.262* @exception NullPointerException if baseName or locale is null.263*/264@Override265public List<Locale> getCandidateLocales(String baseName, Locale locale) {266String key = baseName + '-' + locale.toLanguageTag();267List<Locale> candidates = CANDIDATES_MAP.get(key);268if (candidates == null) {269LocaleProviderAdapter.Type type = baseName.contains(DOTCLDR) ? CLDR : JRE;270LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type);271candidates = adapter instanceof ResourceBundleBasedAdapter ?272((ResourceBundleBasedAdapter)adapter).getCandidateLocales(baseName, locale) :273defaultControl.getCandidateLocales(baseName, locale);274275// Weed out Locales which are known to have no resource bundles276int lastDot = baseName.lastIndexOf('.');277String category = (lastDot >= 0) ? baseName.substring(lastDot + 1) : baseName;278Set<String> langtags = ((JRELocaleProviderAdapter)adapter).getLanguageTagSet(category);279if (!langtags.isEmpty()) {280for (Iterator<Locale> itr = candidates.iterator(); itr.hasNext();) {281if (!adapter.isSupportedProviderLocale(itr.next(), langtags)) {282itr.remove();283}284}285}286CANDIDATES_MAP.putIfAbsent(key, candidates);287}288return candidates;289}290291boolean inJavaBaseModule(String baseName, Locale locale) {292return JAVA_BASE_LOCALES.contains(locale);293}294295@Override296public String toBundleName(String baseName, Locale locale) {297String newBaseName = baseName;298if (!inJavaBaseModule(baseName, locale)) {299if (baseName.startsWith(JRE.getUtilResourcesPackage())300|| baseName.startsWith(JRE.getTextResourcesPackage())) {301// Assume the lengths are the same.302assert JRE.getUtilResourcesPackage().length()303== JRE.getTextResourcesPackage().length();304int index = JRE.getUtilResourcesPackage().length();305if (baseName.indexOf(DOTCLDR, index) > 0) {306index += DOTCLDR.length();307}308newBaseName = baseName.substring(0, index + 1) + "ext"309+ baseName.substring(index);310}311}312return defaultControl.toBundleName(newBaseName, locale);313}314315@Override316public Class<? extends ResourceBundleProvider> getResourceBundleProviderType(String baseName,317Locale locale) {318return inJavaBaseModule(baseName, locale) ?319null : CommonResourceBundleProvider.class;320}321}322323private static class SupplementaryStrategy extends LocaleDataStrategy {324private static final SupplementaryStrategy INSTANCE325= new SupplementaryStrategy();326// TODO: avoid hard-coded Locales327private static Set<Locale> JAVA_BASE_LOCALES328= Set.of(Locale.ROOT, Locale.ENGLISH, Locale.US);329330private SupplementaryStrategy() {331}332333@Override334public List<Locale> getCandidateLocales(String baseName, Locale locale) {335// Specifiy only the given locale336return Arrays.asList(locale);337}338339@Override340public Class<? extends ResourceBundleProvider> getResourceBundleProviderType(String baseName,341Locale locale) {342return inJavaBaseModule(baseName, locale) ?343null : SupplementaryResourceBundleProvider.class;344}345346@Override347boolean inJavaBaseModule(String baseName, Locale locale) {348return JAVA_BASE_LOCALES.contains(locale);349}350}351}352353354