Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/util/locale/provider/LocaleServiceProviderPool.java
41161 views
1
/*
2
* Copyright (c) 2005, 2020, 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.locale.provider;
27
28
import java.util.ArrayList;
29
import java.util.Arrays;
30
import java.util.Collections;
31
import java.util.HashSet;
32
import java.util.IllformedLocaleException;
33
import java.util.List;
34
import java.util.Locale;
35
import java.util.Locale.Builder;
36
import java.util.ResourceBundle.Control;
37
import java.util.Set;
38
import java.util.concurrent.ConcurrentHashMap;
39
import java.util.concurrent.ConcurrentMap;
40
import java.util.spi.LocaleServiceProvider;
41
42
/**
43
* An instance of this class holds a set of the third party implementations of a particular
44
* locale sensitive service, such as {@link java.util.spi.LocaleNameProvider}.
45
*
46
* @author Naoto Sato
47
* @author Masayoshi Okutsu
48
*/
49
public final class LocaleServiceProviderPool {
50
51
/**
52
* A Map that holds singleton instances of this class. Each instance holds a
53
* set of provider implementations of a particular locale sensitive service.
54
*/
55
private static final ConcurrentMap<Class<? extends LocaleServiceProvider>, LocaleServiceProviderPool> poolOfPools =
56
new ConcurrentHashMap<>();
57
58
/**
59
* A Map that retains Locale->provider mapping
60
*/
61
private final ConcurrentMap<Locale, List<LocaleServiceProvider>> providersCache =
62
new ConcurrentHashMap<>();
63
64
/**
65
* Available locales for this locale sensitive service. This also contains
66
* JRE's available locales
67
*/
68
private Set<Locale> availableLocales = null;
69
70
/**
71
* Provider class
72
*/
73
private final Class<? extends LocaleServiceProvider> providerClass;
74
75
/**
76
* Array of all Locale Sensitive SPI classes.
77
*
78
* We know "spiClasses" contains classes that extends LocaleServiceProvider,
79
* but generic array creation is not allowed, thus the "unchecked" warning
80
* is suppressed here.
81
*/
82
@SuppressWarnings("unchecked")
83
static final Class<LocaleServiceProvider>[] spiClasses =
84
(Class<LocaleServiceProvider>[]) new Class<?>[] {
85
java.text.spi.BreakIteratorProvider.class,
86
java.text.spi.CollatorProvider.class,
87
java.text.spi.DateFormatProvider.class,
88
java.text.spi.DateFormatSymbolsProvider.class,
89
java.text.spi.DecimalFormatSymbolsProvider.class,
90
java.text.spi.NumberFormatProvider.class,
91
java.util.spi.CurrencyNameProvider.class,
92
java.util.spi.LocaleNameProvider.class,
93
java.util.spi.TimeZoneNameProvider.class,
94
java.util.spi.CalendarDataProvider.class
95
};
96
97
/**
98
* A factory method that returns a singleton instance
99
*/
100
public static LocaleServiceProviderPool getPool(Class<? extends LocaleServiceProvider> providerClass) {
101
LocaleServiceProviderPool pool = poolOfPools.get(providerClass);
102
if (pool == null) {
103
LocaleServiceProviderPool newPool =
104
new LocaleServiceProviderPool(providerClass);
105
pool = poolOfPools.putIfAbsent(providerClass, newPool);
106
if (pool == null) {
107
pool = newPool;
108
}
109
}
110
111
return pool;
112
}
113
114
/**
115
* The sole constructor.
116
*
117
* @param c class of the locale sensitive service
118
*/
119
private LocaleServiceProviderPool (final Class<? extends LocaleServiceProvider> c) {
120
providerClass = c;
121
}
122
123
/**
124
* Lazy loaded set of available locales.
125
* Loading all locales is a very long operation.
126
*/
127
private static class AllAvailableLocales {
128
/**
129
* Available locales for all locale sensitive services.
130
* This also contains JRE's available locales
131
*/
132
static final Locale[] allAvailableLocales;
133
134
static {
135
Set<Locale> all = new HashSet<>();
136
for (Class<? extends LocaleServiceProvider> c : spiClasses) {
137
LocaleServiceProviderPool pool =
138
LocaleServiceProviderPool.getPool(c);
139
all.addAll(pool.getAvailableLocaleSet());
140
}
141
142
allAvailableLocales = all.toArray(new Locale[0]);
143
}
144
145
// No instantiation
146
private AllAvailableLocales() {
147
}
148
}
149
150
/**
151
* Returns an array of available locales for all the provider classes.
152
* This array is a merged array of all the locales that are provided by each
153
* provider, including the JRE.
154
*
155
* @return an array of the available locales for all provider classes
156
*/
157
public static Locale[] getAllAvailableLocales() {
158
return AllAvailableLocales.allAvailableLocales.clone();
159
}
160
161
/**
162
* Returns an array of available locales. This array is a
163
* merged array of all the locales that are provided by each
164
* provider, including the JRE.
165
*
166
* @return an array of the available locales
167
*/
168
public Locale[] getAvailableLocales() {
169
Set<Locale> locList = new HashSet<>();
170
locList.addAll(getAvailableLocaleSet());
171
// Make sure it all contains JRE's locales for compatibility.
172
locList.addAll(Arrays.asList(LocaleProviderAdapter.forJRE().getAvailableLocales()));
173
Locale[] tmp = new Locale[locList.size()];
174
locList.toArray(tmp);
175
return tmp;
176
}
177
178
/**
179
* Returns the union of locale sets that are available from
180
* each service provider. This method does NOT return the
181
* defensive copy.
182
*
183
* @return a set of available locales
184
*/
185
private synchronized Set<Locale> getAvailableLocaleSet() {
186
if (availableLocales == null) {
187
availableLocales = new HashSet<>();
188
for (LocaleProviderAdapter.Type type : LocaleProviderAdapter.getAdapterPreference()) {
189
LocaleProviderAdapter lda = LocaleProviderAdapter.forType(type);
190
if (lda != null) {
191
LocaleServiceProvider lsp = lda.getLocaleServiceProvider(providerClass);
192
if (lsp != null) {
193
Locale[] locales = lsp.getAvailableLocales();
194
for (Locale locale: locales) {
195
availableLocales.add(getLookupLocale(locale));
196
}
197
}
198
}
199
}
200
}
201
202
return availableLocales;
203
}
204
205
/**
206
* Returns the provider's localized object for the specified
207
* locale.
208
*
209
* @param getter an object on which getObject() method
210
* is called to obtain the provider's instance.
211
* @param locale the given locale that is used as the starting one
212
* @param params provider specific parameters
213
* @return provider's instance, or null.
214
*/
215
public <P extends LocaleServiceProvider, S> S getLocalizedObject(LocalizedObjectGetter<P, S> getter,
216
Locale locale,
217
Object... params) {
218
return getLocalizedObjectImpl(getter, locale, true, null, params);
219
}
220
221
/**
222
* Returns the provider's localized name for the specified
223
* locale.
224
*
225
* @param getter an object on which getObject() method
226
* is called to obtain the provider's instance.
227
* @param locale the given locale that is used as the starting one
228
* @param key the key string for name providers
229
* @param params provider specific parameters
230
* @return provider's instance, or null.
231
*/
232
public <P extends LocaleServiceProvider, S> S getLocalizedObject(LocalizedObjectGetter<P, S> getter,
233
Locale locale,
234
String key,
235
Object... params) {
236
return getLocalizedObjectImpl(getter, locale, false, key, params);
237
}
238
239
/**
240
* Returns the provider's localized name for the specified
241
* locale.
242
*
243
* @param getter an object on which getObject() method
244
* is called to obtain the provider's instance.
245
* @param locale the given locale that is used as the starting one
246
* @param isObjectProvider flag designating object provder or not
247
* @param key the key string for name providers
248
* @param params provider specific parameters
249
* @return provider's instance, or null.
250
*/
251
public <P extends LocaleServiceProvider, S> S getLocalizedObject(LocalizedObjectGetter<P, S> getter,
252
Locale locale,
253
Boolean isObjectProvider,
254
String key,
255
Object... params) {
256
return getLocalizedObjectImpl(getter, locale, isObjectProvider, key, params);
257
}
258
259
@SuppressWarnings("unchecked")
260
private <P extends LocaleServiceProvider, S> S getLocalizedObjectImpl(LocalizedObjectGetter<P, S> getter,
261
Locale locale,
262
boolean isObjectProvider,
263
String key,
264
Object... params) {
265
if (locale == null) {
266
throw new NullPointerException();
267
}
268
269
List<Locale> lookupLocales = getLookupLocales(locale);
270
271
for (Locale current : lookupLocales) {
272
S providersObj;
273
274
for (LocaleServiceProvider lsp: findProviders(current, isObjectProvider)) {
275
providersObj = getter.getObject((P)lsp, locale, key, params);
276
if (providersObj != null) {
277
return providersObj;
278
} else if (isObjectProvider) {
279
System.getLogger(LocaleServiceProviderPool.class.getCanonicalName())
280
.log(System.Logger.Level.INFO,
281
"A locale sensitive service object provider returned null, " +
282
"which should not happen. Provider: " + lsp + " Locale: " + locale);
283
}
284
}
285
}
286
287
// not found.
288
return null;
289
}
290
291
/**
292
* Returns the list of locale service provider instances that support
293
* the specified locale.
294
*
295
* @param locale the given locale
296
* @return the list of locale data adapter types
297
*/
298
private List<LocaleServiceProvider> findProviders(Locale locale, boolean isObjectProvider) {
299
List<LocaleServiceProvider> providersList = providersCache.get(locale);
300
if (providersList == null) {
301
for (LocaleProviderAdapter.Type type : LocaleProviderAdapter.getAdapterPreference()) {
302
LocaleProviderAdapter lda = LocaleProviderAdapter.forType(type);
303
if (lda != null) {
304
LocaleServiceProvider lsp = lda.getLocaleServiceProvider(providerClass);
305
if (lsp != null) {
306
if (lsp.isSupportedLocale(locale)) {
307
if (providersList == null) {
308
providersList = new ArrayList<>(2);
309
}
310
providersList.add(lsp);
311
if (isObjectProvider) {
312
break;
313
}
314
}
315
}
316
}
317
}
318
if (providersList == null) {
319
providersList = NULL_LIST;
320
}
321
List<LocaleServiceProvider> val = providersCache.putIfAbsent(locale, providersList);
322
if (val != null) {
323
providersList = val;
324
}
325
}
326
return providersList;
327
}
328
329
/**
330
* Returns a list of candidate locales for service look up.
331
* @param locale the input locale
332
* @return the list of candidate locales for the given locale
333
*/
334
static List<Locale> getLookupLocales(Locale locale) {
335
// Note: We currently use the default implementation of
336
// ResourceBundle.Control.getCandidateLocales. The result
337
// returned by getCandidateLocales are already normalized
338
// (no extensions) for service look up.
339
return Control.getNoFallbackControl(Control.FORMAT_DEFAULT)
340
.getCandidateLocales("", locale);
341
}
342
343
/**
344
* Returns an instance of Locale used for service look up.
345
* The result Locale has no extensions except for ja_JP_JP
346
* and th_TH_TH
347
*
348
* @param locale the locale
349
* @return the locale used for service look up
350
*/
351
static Locale getLookupLocale(Locale locale) {
352
Locale lookupLocale = locale;
353
if (locale.hasExtensions()
354
&& !locale.equals(JRELocaleConstants.JA_JP_JP)
355
&& !locale.equals(JRELocaleConstants.TH_TH_TH)) {
356
// remove extensions
357
Builder locbld = new Builder();
358
try {
359
locbld.setLocale(locale);
360
locbld.clearExtensions();
361
lookupLocale = locbld.build();
362
} catch (IllformedLocaleException e) {
363
// A Locale with non-empty extensions
364
// should have well-formed fields except
365
// for ja_JP_JP and th_TH_TH. Therefore,
366
// it should never enter in this catch clause.
367
System.getLogger(LocaleServiceProviderPool.class.getCanonicalName())
368
.log(System.Logger.Level.INFO,
369
"A locale(" + locale + ") has non-empty extensions, but has illformed fields.");
370
371
// Fallback - script field will be lost.
372
lookupLocale = new Locale(locale.getLanguage(), locale.getCountry(), locale.getVariant());
373
}
374
}
375
return lookupLocale;
376
}
377
378
/**
379
* A dummy locale service provider list that indicates there is no
380
* provider available
381
*/
382
private static final List<LocaleServiceProvider> NULL_LIST =
383
Collections.emptyList();
384
385
/**
386
* An interface to get a localized object for each locale sensitive
387
* service class.
388
*/
389
public interface LocalizedObjectGetter<P extends LocaleServiceProvider, S> {
390
/**
391
* Returns an object from the provider
392
*
393
* @param lsp the provider
394
* @param locale the locale
395
* @param key key string to localize, or null if the provider is not
396
* a name provider
397
* @param params provider specific params
398
* @return localized object from the provider
399
*/
400
S getObject(P lsp,
401
Locale locale,
402
String key,
403
Object... params);
404
}
405
}
406
407