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