Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java
41159 views
1
/*
2
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.util.cldr;
27
28
import java.security.AccessController;
29
import java.security.PrivilegedAction;
30
import java.security.PrivilegedActionException;
31
import java.security.PrivilegedExceptionAction;
32
import java.text.spi.BreakIteratorProvider;
33
import java.text.spi.CollatorProvider;
34
import java.util.Arrays;
35
import java.util.Collections;
36
import java.util.HashSet;
37
import java.util.List;
38
import java.util.Locale;
39
import java.util.Map;
40
import java.util.Optional;
41
import java.util.ServiceLoader;
42
import java.util.Set;
43
import java.util.StringTokenizer;
44
import java.util.concurrent.ConcurrentHashMap;
45
import java.util.spi.CalendarDataProvider;
46
import java.util.spi.CalendarNameProvider;
47
import java.util.spi.TimeZoneNameProvider;
48
import sun.util.locale.provider.JRELocaleProviderAdapter;
49
import sun.util.locale.provider.LocaleDataMetaInfo;
50
import sun.util.locale.provider.LocaleProviderAdapter;
51
52
/**
53
* LocaleProviderAdapter implementation for the CLDR locale data.
54
*
55
* @author Masayoshi Okutsu
56
* @author Naoto Sato
57
*/
58
public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter {
59
60
private static final CLDRBaseLocaleDataMetaInfo baseMetaInfo = new CLDRBaseLocaleDataMetaInfo();
61
// Assumption: CLDR has only one non-Base module.
62
private final LocaleDataMetaInfo nonBaseMetaInfo;
63
64
// parent locales map
65
private static volatile Map<Locale, Locale> parentLocalesMap;
66
// language aliases map
67
private static volatile Map<String,String> langAliasesMap;
68
// cache to hold locale to locale mapping for language aliases.
69
private static final Map<Locale, Locale> langAliasesCache;
70
static {
71
parentLocalesMap = new ConcurrentHashMap<>();
72
langAliasesMap = new ConcurrentHashMap<>();
73
langAliasesCache = new ConcurrentHashMap<>();
74
// Assuming these locales do NOT have irregular parent locales.
75
parentLocalesMap.put(Locale.ROOT, Locale.ROOT);
76
parentLocalesMap.put(Locale.ENGLISH, Locale.ENGLISH);
77
parentLocalesMap.put(Locale.US, Locale.US);
78
}
79
80
@SuppressWarnings("removal")
81
public CLDRLocaleProviderAdapter() {
82
LocaleDataMetaInfo nbmi;
83
84
try {
85
nbmi = AccessController.doPrivileged((PrivilegedExceptionAction<LocaleDataMetaInfo>) () -> {
86
for (LocaleDataMetaInfo ldmi : ServiceLoader.loadInstalled(LocaleDataMetaInfo.class)) {
87
if (ldmi.getType() == Type.CLDR) {
88
return ldmi;
89
}
90
}
91
return null;
92
});
93
} catch (PrivilegedActionException pae) {
94
throw new InternalError(pae.getCause());
95
}
96
97
nonBaseMetaInfo = nbmi;
98
}
99
100
/**
101
* Returns the type of this LocaleProviderAdapter
102
* @return the type of this
103
*/
104
@Override
105
public LocaleProviderAdapter.Type getAdapterType() {
106
return LocaleProviderAdapter.Type.CLDR;
107
}
108
109
@Override
110
public BreakIteratorProvider getBreakIteratorProvider() {
111
return null;
112
}
113
114
@Override
115
public CalendarDataProvider getCalendarDataProvider() {
116
if (calendarDataProvider == null) {
117
@SuppressWarnings("removal")
118
CalendarDataProvider provider = AccessController.doPrivileged(
119
(PrivilegedAction<CalendarDataProvider>) () ->
120
new CLDRCalendarDataProviderImpl(
121
getAdapterType(),
122
getLanguageTagSet("CalendarData")));
123
124
synchronized (this) {
125
if (calendarDataProvider == null) {
126
calendarDataProvider = provider;
127
}
128
}
129
}
130
return calendarDataProvider;
131
}
132
133
@Override
134
public CalendarNameProvider getCalendarNameProvider() {
135
if (calendarNameProvider == null) {
136
@SuppressWarnings("removal")
137
CalendarNameProvider provider = AccessController.doPrivileged(
138
(PrivilegedAction<CalendarNameProvider>) ()
139
-> new CLDRCalendarNameProviderImpl(
140
getAdapterType(),
141
getLanguageTagSet("FormatData")));
142
143
synchronized (this) {
144
if (calendarNameProvider == null) {
145
calendarNameProvider = provider;
146
}
147
}
148
}
149
return calendarNameProvider;
150
}
151
152
@Override
153
public CollatorProvider getCollatorProvider() {
154
return null;
155
}
156
157
@Override
158
public TimeZoneNameProvider getTimeZoneNameProvider() {
159
if (timeZoneNameProvider == null) {
160
@SuppressWarnings("removal")
161
TimeZoneNameProvider provider = AccessController.doPrivileged(
162
(PrivilegedAction<TimeZoneNameProvider>) () ->
163
new CLDRTimeZoneNameProviderImpl(
164
getAdapterType(),
165
getLanguageTagSet("TimeZoneNames")));
166
167
synchronized (this) {
168
if (timeZoneNameProvider == null) {
169
timeZoneNameProvider = provider;
170
}
171
}
172
}
173
return timeZoneNameProvider;
174
}
175
176
@Override
177
public Locale[] getAvailableLocales() {
178
Set<String> all = createLanguageTagSet("AvailableLocales");
179
Locale[] locs = new Locale[all.size()];
180
int index = 0;
181
for (String tag : all) {
182
locs[index++] = Locale.forLanguageTag(tag);
183
}
184
return locs;
185
}
186
187
private static Locale applyAliases(Locale loc) {
188
if (langAliasesMap.isEmpty()) {
189
langAliasesMap = baseMetaInfo.getLanguageAliasMap();
190
}
191
Locale locale = langAliasesCache.get(loc);
192
if (locale == null) {
193
String locTag = loc.toLanguageTag();
194
Locale aliasLocale = langAliasesMap.containsKey(locTag)
195
? Locale.forLanguageTag(langAliasesMap.get(locTag)) : loc;
196
langAliasesCache.putIfAbsent(loc, aliasLocale);
197
return aliasLocale;
198
} else {
199
return locale;
200
}
201
}
202
203
@Override
204
protected Set<String> createLanguageTagSet(String category) {
205
// Assume all categories support the same set as AvailableLocales
206
// in CLDR adapter.
207
category = "AvailableLocales";
208
209
// Directly call Base tags, as we know it's in the base module.
210
String supportedLocaleString = baseMetaInfo.availableLanguageTags(category);
211
String nonBaseTags = null;
212
213
if (nonBaseMetaInfo != null) {
214
nonBaseTags = nonBaseMetaInfo.availableLanguageTags(category);
215
}
216
if (nonBaseTags != null) {
217
if (supportedLocaleString != null) {
218
supportedLocaleString += " " + nonBaseTags;
219
} else {
220
supportedLocaleString = nonBaseTags;
221
}
222
}
223
if (supportedLocaleString == null) {
224
return Collections.emptySet();
225
}
226
StringTokenizer tokens = new StringTokenizer(supportedLocaleString);
227
Set<String> tagset = new HashSet<>((tokens.countTokens() * 4 + 2) / 3);
228
while (tokens.hasMoreTokens()) {
229
tagset.add(tokens.nextToken());
230
}
231
return tagset;
232
}
233
234
// Implementation of ResourceBundleBasedAdapter
235
@Override
236
public List<Locale> getCandidateLocales(String baseName, Locale locale) {
237
List<Locale> candidates = super.getCandidateLocales(baseName, applyAliases(locale));
238
return applyParentLocales(baseName, candidates);
239
}
240
241
private List<Locale> applyParentLocales(String baseName, List<Locale> candidates) {
242
// check irregular parents
243
for (int i = 0; i < candidates.size(); i++) {
244
Locale l = candidates.get(i);
245
if (!l.equals(Locale.ROOT)) {
246
Locale p = getParentLocale(l);
247
if (p != null &&
248
!candidates.get(i+1).equals(p)) {
249
List<Locale> applied = candidates.subList(0, i+1);
250
if (applied.contains(p)) {
251
// avoid circular recursion (could happen with nb/no case)
252
continue;
253
}
254
applied.addAll(applyParentLocales(baseName, super.getCandidateLocales(baseName, p)));
255
return applied;
256
}
257
}
258
}
259
260
return candidates;
261
}
262
263
private static Locale getParentLocale(Locale locale) {
264
Locale parent = parentLocalesMap.get(locale);
265
266
if (parent == null) {
267
String tag = locale.toLanguageTag();
268
for (Map.Entry<Locale, String[]> entry : baseMetaInfo.parentLocales().entrySet()) {
269
if (Arrays.binarySearch(entry.getValue(), tag) >= 0) {
270
parent = entry.getKey();
271
break;
272
}
273
}
274
if (parent == null) {
275
parent = locale; // non existent marker
276
}
277
parentLocalesMap.putIfAbsent(locale, parent);
278
}
279
280
if (locale.equals(parent)) {
281
// means no irregular parent.
282
parent = null;
283
}
284
285
return parent;
286
}
287
288
/**
289
* This method returns equivalent CLDR supported locale
290
* for no, no-NO locales so that COMPAT locales do not precede
291
* those locales during ResourceBundle search path, also if an alias exists for a locale,
292
* it returns equivalent locale, e.g for zh_HK it returns zh_Hant-HK.
293
*/
294
private static Locale getEquivalentLoc(Locale locale) {
295
return switch (locale.toString()) {
296
case "no", "no_NO" -> Locale.forLanguageTag("nb");
297
default -> applyAliases(locale);
298
};
299
}
300
301
@Override
302
public boolean isSupportedProviderLocale(Locale locale, Set<String> langtags) {
303
return Locale.ROOT.equals(locale)
304
|| langtags.contains(locale.stripExtensions().toLanguageTag())
305
|| langtags.contains(getEquivalentLoc(locale).toLanguageTag());
306
}
307
308
/**
309
* Returns the canonical ID for the given ID
310
*/
311
public Optional<String> canonicalTZID(String id) {
312
return Optional.ofNullable(baseMetaInfo.tzCanonicalIDs().get(id));
313
}
314
}
315
316