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/LocaleResources.java
38918 views
1
/*
2
* Copyright (c) 2012, 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
/*
27
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
29
*
30
* The original version of this source code and documentation
31
* is copyrighted and owned by Taligent, Inc., a wholly-owned
32
* subsidiary of IBM. These materials are provided under terms
33
* of a License Agreement between Taligent and Sun. This technology
34
* is protected by multiple US and International patents.
35
*
36
* This notice and attribution to Taligent may not be removed.
37
* Taligent is a registered trademark of Taligent, Inc.
38
*
39
*/
40
41
package sun.util.locale.provider;
42
43
import java.lang.ref.ReferenceQueue;
44
import java.lang.ref.SoftReference;
45
import java.text.MessageFormat;
46
import java.util.Calendar;
47
import java.util.LinkedHashSet;
48
import java.util.Locale;
49
import java.util.Map;
50
import java.util.Objects;
51
import java.util.ResourceBundle;
52
import java.util.Set;
53
import java.util.concurrent.ConcurrentHashMap;
54
import java.util.concurrent.ConcurrentMap;
55
import sun.util.calendar.ZoneInfo;
56
import sun.util.resources.LocaleData;
57
import sun.util.resources.OpenListResourceBundle;
58
import sun.util.resources.ParallelListResourceBundle;
59
import sun.util.resources.TimeZoneNamesBundle;
60
61
/**
62
* Central accessor to locale-dependent resources for JRE/CLDR provider adapters.
63
*
64
* @author Masayoshi Okutsu
65
* @author Naoto Sato
66
*/
67
public class LocaleResources {
68
69
private final Locale locale;
70
private final LocaleData localeData;
71
private final LocaleProviderAdapter.Type type;
72
73
// Resource cache
74
private ConcurrentMap<String, ResourceReference> cache = new ConcurrentHashMap<>();
75
private ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
76
77
// cache key prefixes
78
private static final String BREAK_ITERATOR_INFO = "BII.";
79
private static final String CALENDAR_DATA = "CALD.";
80
private static final String COLLATION_DATA_CACHEKEY = "COLD";
81
private static final String DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY = "DFSD";
82
private static final String CURRENCY_NAMES = "CN.";
83
private static final String LOCALE_NAMES = "LN.";
84
private static final String TIME_ZONE_NAMES = "TZN.";
85
private static final String ZONE_IDS_CACHEKEY = "ZID";
86
private static final String CALENDAR_NAMES = "CALN.";
87
private static final String NUMBER_PATTERNS_CACHEKEY = "NP";
88
private static final String DATE_TIME_PATTERN = "DTP.";
89
90
// null singleton cache value
91
private static final Object NULLOBJECT = new Object();
92
93
LocaleResources(ResourceBundleBasedAdapter adapter, Locale locale) {
94
this.locale = locale;
95
this.localeData = adapter.getLocaleData();
96
type = ((LocaleProviderAdapter)adapter).getAdapterType();
97
}
98
99
private void removeEmptyReferences() {
100
Object ref;
101
while ((ref = referenceQueue.poll()) != null) {
102
cache.remove(((ResourceReference)ref).getCacheKey());
103
}
104
}
105
106
Object getBreakIteratorInfo(String key) {
107
Object biInfo;
108
String cacheKey = BREAK_ITERATOR_INFO + key;
109
110
removeEmptyReferences();
111
ResourceReference data = cache.get(cacheKey);
112
if (data == null || ((biInfo = data.get()) == null)) {
113
biInfo = localeData.getBreakIteratorInfo(locale).getObject(key);
114
cache.put(cacheKey, new ResourceReference(cacheKey, biInfo, referenceQueue));
115
}
116
117
return biInfo;
118
}
119
120
int getCalendarData(String key) {
121
Integer caldata;
122
String cacheKey = CALENDAR_DATA + key;
123
124
removeEmptyReferences();
125
126
ResourceReference data = cache.get(cacheKey);
127
if (data == null || ((caldata = (Integer) data.get()) == null)) {
128
ResourceBundle rb = localeData.getCalendarData(locale);
129
if (rb.containsKey(key)) {
130
caldata = Integer.parseInt(rb.getString(key));
131
} else {
132
caldata = 0;
133
}
134
135
cache.put(cacheKey,
136
new ResourceReference(cacheKey, (Object) caldata, referenceQueue));
137
}
138
139
return caldata;
140
}
141
142
public String getCollationData() {
143
String key = "Rule";
144
String coldata = "";
145
146
removeEmptyReferences();
147
ResourceReference data = cache.get(COLLATION_DATA_CACHEKEY);
148
if (data == null || ((coldata = (String) data.get()) == null)) {
149
ResourceBundle rb = localeData.getCollationData(locale);
150
if (rb.containsKey(key)) {
151
coldata = rb.getString(key);
152
}
153
cache.put(COLLATION_DATA_CACHEKEY,
154
new ResourceReference(COLLATION_DATA_CACHEKEY, (Object) coldata, referenceQueue));
155
}
156
157
return coldata;
158
}
159
160
public Object[] getDecimalFormatSymbolsData() {
161
Object[] dfsdata;
162
163
removeEmptyReferences();
164
ResourceReference data = cache.get(DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY);
165
if (data == null || ((dfsdata = (Object[]) data.get()) == null)) {
166
// Note that only dfsdata[0] is prepared here in this method. Other
167
// elements are provided by the caller, yet they are cached here.
168
ResourceBundle rb = localeData.getNumberFormatData(locale);
169
dfsdata = new Object[3];
170
171
// NumberElements look up. First, try the Unicode extension
172
String numElemKey;
173
String numberType = locale.getUnicodeLocaleType("nu");
174
if (numberType != null) {
175
numElemKey = numberType + ".NumberElements";
176
if (rb.containsKey(numElemKey)) {
177
dfsdata[0] = rb.getStringArray(numElemKey);
178
}
179
}
180
181
// Next, try DefaultNumberingSystem value
182
if (dfsdata[0] == null && rb.containsKey("DefaultNumberingSystem")) {
183
numElemKey = rb.getString("DefaultNumberingSystem") + ".NumberElements";
184
if (rb.containsKey(numElemKey)) {
185
dfsdata[0] = rb.getStringArray(numElemKey);
186
}
187
}
188
189
// Last resort. No need to check the availability.
190
// Just let it throw MissingResourceException when needed.
191
if (dfsdata[0] == null) {
192
dfsdata[0] = rb.getStringArray("NumberElements");
193
}
194
195
cache.put(DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY,
196
new ResourceReference(DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY, (Object) dfsdata, referenceQueue));
197
}
198
199
return dfsdata;
200
}
201
202
public String getCurrencyName(String key) {
203
Object currencyName = null;
204
String cacheKey = CURRENCY_NAMES + key;
205
206
removeEmptyReferences();
207
ResourceReference data = cache.get(cacheKey);
208
209
if (data != null && ((currencyName = data.get()) != null)) {
210
if (currencyName.equals(NULLOBJECT)) {
211
currencyName = null;
212
}
213
214
return (String) currencyName;
215
}
216
217
OpenListResourceBundle olrb = localeData.getCurrencyNames(locale);
218
219
if (olrb.containsKey(key)) {
220
currencyName = olrb.getObject(key);
221
cache.put(cacheKey,
222
new ResourceReference(cacheKey, currencyName, referenceQueue));
223
}
224
225
return (String) currencyName;
226
}
227
228
public String getLocaleName(String key) {
229
Object localeName = null;
230
String cacheKey = LOCALE_NAMES + key;
231
232
removeEmptyReferences();
233
ResourceReference data = cache.get(cacheKey);
234
235
if (data != null && ((localeName = data.get()) != null)) {
236
if (localeName.equals(NULLOBJECT)) {
237
localeName = null;
238
}
239
240
return (String) localeName;
241
}
242
243
OpenListResourceBundle olrb = localeData.getLocaleNames(locale);
244
245
if (olrb.containsKey(key)) {
246
localeName = olrb.getObject(key);
247
cache.put(cacheKey,
248
new ResourceReference(cacheKey, localeName, referenceQueue));
249
}
250
251
return (String) localeName;
252
}
253
254
String[] getTimeZoneNames(String key) {
255
String[] names = null;
256
String cacheKey = TIME_ZONE_NAMES + '.' + key;
257
258
removeEmptyReferences();
259
ResourceReference data = cache.get(cacheKey);
260
261
if (Objects.isNull(data) || Objects.isNull((names = (String[]) data.get()))) {
262
TimeZoneNamesBundle tznb = localeData.getTimeZoneNames(locale);
263
if (tznb.containsKey(key)) {
264
names = tznb.getStringArray(key);
265
cache.put(cacheKey,
266
new ResourceReference(cacheKey, (Object) names, referenceQueue));
267
}
268
}
269
270
return names;
271
}
272
273
@SuppressWarnings("unchecked")
274
Set<String> getZoneIDs() {
275
Set<String> zoneIDs = null;
276
277
removeEmptyReferences();
278
ResourceReference data = cache.get(ZONE_IDS_CACHEKEY);
279
if (data == null || ((zoneIDs = (Set<String>) data.get()) == null)) {
280
TimeZoneNamesBundle rb = localeData.getTimeZoneNames(locale);
281
zoneIDs = rb.keySet();
282
cache.put(ZONE_IDS_CACHEKEY,
283
new ResourceReference(ZONE_IDS_CACHEKEY, (Object) zoneIDs, referenceQueue));
284
}
285
286
return zoneIDs;
287
}
288
289
// zoneStrings are cached separately in TimeZoneNameUtility.
290
String[][] getZoneStrings() {
291
TimeZoneNamesBundle rb = localeData.getTimeZoneNames(locale);
292
Set<String> keyset = getZoneIDs();
293
// Use a LinkedHashSet to preseve the order
294
Set<String[]> value = new LinkedHashSet<>();
295
for (String key : keyset) {
296
value.add(rb.getStringArray(key));
297
}
298
299
// Add aliases data for CLDR
300
if (type == LocaleProviderAdapter.Type.CLDR) {
301
// Note: TimeZoneNamesBundle creates a String[] on each getStringArray call.
302
Map<String, String> aliases = ZoneInfo.getAliasTable();
303
for (String alias : aliases.keySet()) {
304
if (!keyset.contains(alias)) {
305
String tzid = aliases.get(alias);
306
if (keyset.contains(tzid)) {
307
String[] val = rb.getStringArray(tzid);
308
val[0] = alias;
309
value.add(val);
310
}
311
}
312
}
313
}
314
return value.toArray(new String[0][]);
315
}
316
317
String[] getCalendarNames(String key) {
318
String[] names = null;
319
String cacheKey = CALENDAR_NAMES + key;
320
321
removeEmptyReferences();
322
ResourceReference data = cache.get(cacheKey);
323
324
if (data == null || ((names = (String[]) data.get()) == null)) {
325
ResourceBundle rb = localeData.getDateFormatData(locale);
326
if (rb.containsKey(key)) {
327
names = rb.getStringArray(key);
328
cache.put(cacheKey,
329
new ResourceReference(cacheKey, (Object) names, referenceQueue));
330
}
331
}
332
333
return names;
334
}
335
336
String[] getJavaTimeNames(String key) {
337
String[] names = null;
338
String cacheKey = CALENDAR_NAMES + key;
339
340
removeEmptyReferences();
341
ResourceReference data = cache.get(cacheKey);
342
343
if (data == null || ((names = (String[]) data.get()) == null)) {
344
ResourceBundle rb = getJavaTimeFormatData();
345
if (rb.containsKey(key)) {
346
names = rb.getStringArray(key);
347
cache.put(cacheKey,
348
new ResourceReference(cacheKey, (Object) names, referenceQueue));
349
}
350
}
351
352
return names;
353
}
354
355
public String getDateTimePattern(int timeStyle, int dateStyle, Calendar cal) {
356
if (cal == null) {
357
cal = Calendar.getInstance(locale);
358
}
359
return getDateTimePattern(null, timeStyle, dateStyle, cal.getCalendarType());
360
}
361
362
/**
363
* Returns a date-time format pattern
364
* @param timeStyle style of time; one of FULL, LONG, MEDIUM, SHORT in DateFormat,
365
* or -1 if not required
366
* @param dateStyle style of time; one of FULL, LONG, MEDIUM, SHORT in DateFormat,
367
* or -1 if not required
368
* @param calType the calendar type for the pattern
369
* @return the pattern string
370
*/
371
public String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType) {
372
calType = CalendarDataUtility.normalizeCalendarType(calType);
373
String pattern;
374
pattern = getDateTimePattern("java.time.", timeStyle, dateStyle, calType);
375
if (pattern == null) {
376
pattern = getDateTimePattern(null, timeStyle, dateStyle, calType);
377
}
378
return pattern;
379
}
380
381
private String getDateTimePattern(String prefix, int timeStyle, int dateStyle, String calType) {
382
String pattern;
383
String timePattern = null;
384
String datePattern = null;
385
386
if (timeStyle >= 0) {
387
if (prefix != null) {
388
timePattern = getDateTimePattern(prefix, "TimePatterns", timeStyle, calType);
389
}
390
if (timePattern == null) {
391
timePattern = getDateTimePattern(null, "TimePatterns", timeStyle, calType);
392
}
393
}
394
if (dateStyle >= 0) {
395
if (prefix != null) {
396
datePattern = getDateTimePattern(prefix, "DatePatterns", dateStyle, calType);
397
}
398
if (datePattern == null) {
399
datePattern = getDateTimePattern(null, "DatePatterns", dateStyle, calType);
400
}
401
}
402
if (timeStyle >= 0) {
403
if (dateStyle >= 0) {
404
String dateTimePattern = null;
405
if (prefix != null) {
406
dateTimePattern = getDateTimePattern(prefix, "DateTimePatterns", 0, calType);
407
}
408
if (dateTimePattern == null) {
409
dateTimePattern = getDateTimePattern(null, "DateTimePatterns", 0, calType);
410
}
411
switch (dateTimePattern) {
412
case "{1} {0}":
413
pattern = datePattern + " " + timePattern;
414
break;
415
case "{0} {1}":
416
pattern = timePattern + " " + datePattern;
417
break;
418
default:
419
pattern = MessageFormat.format(dateTimePattern, timePattern, datePattern);
420
break;
421
}
422
} else {
423
pattern = timePattern;
424
}
425
} else if (dateStyle >= 0) {
426
pattern = datePattern;
427
} else {
428
throw new IllegalArgumentException("No date or time style specified");
429
}
430
return pattern;
431
}
432
433
public String[] getNumberPatterns() {
434
String[] numberPatterns = null;
435
436
removeEmptyReferences();
437
ResourceReference data = cache.get(NUMBER_PATTERNS_CACHEKEY);
438
439
if (data == null || ((numberPatterns = (String[]) data.get()) == null)) {
440
ResourceBundle resource = localeData.getNumberFormatData(locale);
441
numberPatterns = resource.getStringArray("NumberPatterns");
442
cache.put(NUMBER_PATTERNS_CACHEKEY,
443
new ResourceReference(NUMBER_PATTERNS_CACHEKEY, (Object) numberPatterns, referenceQueue));
444
}
445
446
return numberPatterns;
447
}
448
449
/**
450
* Returns the FormatData resource bundle of this LocaleResources.
451
* The FormatData should be used only for accessing extra
452
* resources required by JSR 310.
453
*/
454
public ResourceBundle getJavaTimeFormatData() {
455
ResourceBundle rb = localeData.getDateFormatData(locale);
456
if (rb instanceof ParallelListResourceBundle) {
457
localeData.setSupplementary((ParallelListResourceBundle) rb);
458
}
459
return rb;
460
}
461
462
private String getDateTimePattern(String prefix, String key, int styleIndex, String calendarType) {
463
StringBuilder sb = new StringBuilder();
464
if (prefix != null) {
465
sb.append(prefix);
466
}
467
if (!"gregory".equals(calendarType)) {
468
sb.append(calendarType).append('.');
469
}
470
sb.append(key);
471
String resourceKey = sb.toString();
472
String cacheKey = sb.insert(0, DATE_TIME_PATTERN).toString();
473
474
removeEmptyReferences();
475
ResourceReference data = cache.get(cacheKey);
476
Object value = NULLOBJECT;
477
478
if (data == null || ((value = data.get()) == null)) {
479
ResourceBundle r = (prefix != null) ? getJavaTimeFormatData() : localeData.getDateFormatData(locale);
480
if (r.containsKey(resourceKey)) {
481
value = r.getStringArray(resourceKey);
482
} else {
483
assert !resourceKey.equals(key);
484
if (r.containsKey(key)) {
485
value = r.getStringArray(key);
486
}
487
}
488
cache.put(cacheKey,
489
new ResourceReference(cacheKey, value, referenceQueue));
490
}
491
if (value == NULLOBJECT) {
492
assert prefix != null;
493
return null;
494
}
495
return ((String[])value)[styleIndex];
496
}
497
498
private static class ResourceReference extends SoftReference<Object> {
499
private final String cacheKey;
500
501
ResourceReference(String cacheKey, Object o, ReferenceQueue<Object> q) {
502
super(o, q);
503
this.cacheKey = cacheKey;
504
}
505
506
String getCacheKey() {
507
return cacheKey;
508
}
509
}
510
}
511
512