Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/src/share/classes/sun/util/locale/provider/LocaleServiceProviderPool.java
+++ new/src/share/classes/sun/util/locale/provider/LocaleServiceProviderPool.java
1 1 /*
2 2 * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation. Oracle designates this
8 8 * particular file as subject to the "Classpath" exception as provided
9 9 * by Oracle in the LICENSE file that accompanied this code.
10 10 *
11 11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 14 * version 2 for more details (a copy is included in the LICENSE file that
15 15 * accompanied this code).
16 16 *
17 17 * You should have received a copy of the GNU General Public License version
18 18 * 2 along with this work; if not, write to the Free Software Foundation,
19 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 20 *
21 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 22 * or visit www.oracle.com if you need additional information or have any
23 23 * questions.
24 24 */
25 25
26 26 package sun.util.locale.provider;
27 27
28 28 import java.util.ArrayList;
29 29 import java.util.Collections;
30 30 import java.util.HashSet;
31 31 import java.util.IllformedLocaleException;
32 32 import java.util.List;
33 33 import java.util.Locale;
34 34 import java.util.Locale.Builder;
35 35 import java.util.ResourceBundle.Control;
36 36 import java.util.Set;
37 37 import java.util.concurrent.ConcurrentHashMap;
38 38 import java.util.concurrent.ConcurrentMap;
39 39 import java.util.spi.LocaleServiceProvider;
40 40 import sun.util.logging.PlatformLogger;
41 41
42 42 /**
43 43 * An instance of this class holds a set of the third party implementations of a particular
44 44 * locale sensitive service, such as {@link java.util.spi.LocaleNameProvider}.
45 45 *
46 46 * @author Naoto Sato
47 47 * @author Masayoshi Okutsu
48 48 */
49 49 public final class LocaleServiceProviderPool {
50 50
51 51 /**
52 52 * A Map that holds singleton instances of this class. Each instance holds a
53 53 * set of provider implementations of a particular locale sensitive service.
54 54 */
55 55 private static ConcurrentMap<Class<? extends LocaleServiceProvider>, LocaleServiceProviderPool> poolOfPools =
56 56 new ConcurrentHashMap<>();
57 57
58 58 /**
59 59 * A Map containing locale service providers that implement the
60 60 * specified provider SPI, keyed by a LocaleProviderAdapter.Type
61 61 */
62 62 private ConcurrentMap<LocaleProviderAdapter.Type, LocaleServiceProvider> providers =
63 63 new ConcurrentHashMap<>();
64 64
65 65 /**
66 66 * A Map that retains Locale->provider mapping
67 67 */
68 68 private ConcurrentMap<Locale, List<LocaleProviderAdapter.Type>> providersCache =
69 69 new ConcurrentHashMap<>();
70 70
71 71 /**
72 72 * Available locales for this locale sensitive service. This also contains
73 73 * JRE's available locales
74 74 */
75 75 private Set<Locale> availableLocales = null;
76 76
77 77 /**
78 78 * Provider class
79 79 */
80 80 private Class<? extends LocaleServiceProvider> providerClass;
81 81
82 82 /**
83 83 * Array of all Locale Sensitive SPI classes.
84 84 *
85 85 * We know "spiClasses" contains classes that extends LocaleServiceProvider,
86 86 * but generic array creation is not allowed, thus the "unchecked" warning
87 87 * is suppressed here.
88 88 */
89 89 @SuppressWarnings("unchecked")
90 90 static final Class<LocaleServiceProvider>[] spiClasses =
91 91 (Class<LocaleServiceProvider>[]) new Class<?>[] {
92 92 java.text.spi.BreakIteratorProvider.class,
93 93 java.text.spi.CollatorProvider.class,
94 94 java.text.spi.DateFormatProvider.class,
95 95 java.text.spi.DateFormatSymbolsProvider.class,
96 96 java.text.spi.DecimalFormatSymbolsProvider.class,
97 97 java.text.spi.NumberFormatProvider.class,
98 98 java.util.spi.CurrencyNameProvider.class,
99 99 java.util.spi.LocaleNameProvider.class,
100 100 java.util.spi.TimeZoneNameProvider.class,
101 101 java.util.spi.CalendarDataProvider.class
102 102 };
103 103
104 104 /**
105 105 * A factory method that returns a singleton instance
106 106 */
107 107 public static LocaleServiceProviderPool getPool(Class<? extends LocaleServiceProvider> providerClass) {
108 108 LocaleServiceProviderPool pool = poolOfPools.get(providerClass);
109 109 if (pool == null) {
110 110 LocaleServiceProviderPool newPool =
111 111 new LocaleServiceProviderPool(providerClass);
112 112 pool = poolOfPools.putIfAbsent(providerClass, newPool);
113 113 if (pool == null) {
114 114 pool = newPool;
115 115 }
116 116 }
117 117
118 118 return pool;
↓ open down ↓ |
118 lines elided |
↑ open up ↑ |
119 119 }
120 120
121 121 /**
122 122 * The sole constructor.
123 123 *
124 124 * @param c class of the locale sensitive service
125 125 */
126 126 private LocaleServiceProviderPool (final Class<? extends LocaleServiceProvider> c) {
127 127 providerClass = c;
128 128
129 - // Add the JRE Locale Data Adapter implementation.
130 - providers.putIfAbsent(LocaleProviderAdapter.Type.JRE,
131 - LocaleProviderAdapter.forJRE().getLocaleServiceProvider(c));
132 -
133 - // Add the SPI Locale Data Adapter implementation.
134 - LocaleProviderAdapter lda = LocaleProviderAdapter.forType(LocaleProviderAdapter.Type.SPI);
135 - LocaleServiceProvider provider = lda.getLocaleServiceProvider(c);
136 - if (provider != null) {
137 - providers.putIfAbsent(LocaleProviderAdapter.Type.SPI, provider);
138 - }
139 -
140 - // Add the CLDR Locale Data Adapter implementation, if needed.
141 - lda = LocaleProviderAdapter.forType(LocaleProviderAdapter.Type.CLDR);
142 - if (lda != null) {
143 - provider = lda.getLocaleServiceProvider(c);
144 - if (provider != null) {
145 - providers.putIfAbsent(LocaleProviderAdapter.Type.CLDR, provider);
129 + for (LocaleProviderAdapter.Type type : LocaleProviderAdapter.getAdapterPreference()) {
130 + LocaleProviderAdapter lda = LocaleProviderAdapter.forType(type);
131 + if (lda != null) {
132 + LocaleServiceProvider provider = lda.getLocaleServiceProvider(c);
133 + if (provider != null) {
134 + providers.putIfAbsent(type, provider);
135 + }
146 136 }
147 137 }
148 -
149 - // Add the Host Locale Data Adapter implementation, if needed.
150 - lda = LocaleProviderAdapter.forType(LocaleProviderAdapter.Type.HOST);
151 - if (lda != null) {
152 - provider = lda.getLocaleServiceProvider(c);
153 - if (provider != null) {
154 - providers.putIfAbsent(LocaleProviderAdapter.Type.HOST, provider);
155 - }
156 - }
157 138 }
158 139
159 140 static void config(Class<? extends Object> caller, String message) {
160 141 PlatformLogger logger = PlatformLogger.getLogger(caller.getCanonicalName());
161 142 logger.config(message);
162 143 }
163 144
164 145 /**
165 146 * Lazy loaded set of available locales.
166 147 * Loading all locales is a very long operation.
167 148 */
168 149 private static class AllAvailableLocales {
169 150 /**
170 151 * Available locales for all locale sensitive services.
171 152 * This also contains JRE's available locales
172 153 */
173 154 static final Locale[] allAvailableLocales;
174 155
175 156 static {
176 157 Set<Locale> all = new HashSet<>();
177 158 for (Class<? extends LocaleServiceProvider> c : spiClasses) {
178 159 LocaleServiceProviderPool pool =
179 160 LocaleServiceProviderPool.getPool(c);
180 161 all.addAll(pool.getAvailableLocaleList());
181 162 }
182 163
183 164 allAvailableLocales = all.toArray(new Locale[0]);
184 165 }
185 166
186 167 // No instantiation
187 168 private AllAvailableLocales() {
188 169 }
189 170 }
190 171
191 172 /**
192 173 * Returns an array of available locales for all the provider classes.
193 174 * This array is a merged array of all the locales that are provided by each
194 175 * provider, including the JRE.
195 176 *
196 177 * @return an array of the available locales for all provider classes
197 178 */
198 179 public static Locale[] getAllAvailableLocales() {
199 180 return AllAvailableLocales.allAvailableLocales.clone();
200 181 }
201 182
202 183 /**
203 184 * Returns an array of available locales. This array is a
204 185 * merged array of all the locales that are provided by each
205 186 * provider, including the JRE.
206 187 *
207 188 * @return an array of the available locales
208 189 */
209 190 public Locale[] getAvailableLocales() {
210 191 Set<Locale> locList = getAvailableLocaleList();
211 192 Locale[] tmp = new Locale[locList.size()];
212 193 locList.toArray(tmp);
213 194 return tmp;
214 195 }
215 196
216 197 private synchronized Set<Locale> getAvailableLocaleList() {
217 198 if (availableLocales == null) {
218 199 availableLocales = new HashSet<>();
219 200 for (LocaleServiceProvider lsp : providers.values()) {
220 201 Locale[] locales = lsp.getAvailableLocales();
221 202 for (Locale locale: locales) {
222 203 availableLocales.add(getLookupLocale(locale));
223 204 }
224 205 }
225 206
226 207 // Remove Locale.ROOT for the compatibility.
227 208 availableLocales.remove(Locale.ROOT);
228 209 }
229 210
230 211 return availableLocales;
231 212 }
232 213
233 214 /**
234 215 * Returns whether any provider for this locale sensitive
235 216 * service is available or not, excluding JRE's one.
236 217 *
237 218 * @return true if any provider (other than JRE) is available
238 219 */
239 220 boolean hasProviders() {
240 221 return providers.size() != 1 ||
241 222 providers.get(LocaleProviderAdapter.Type.JRE) == null;
242 223 }
243 224
244 225 /**
245 226 * Returns the provider's localized object for the specified
246 227 * locale.
247 228 *
248 229 * @param getter an object on which getObject() method
249 230 * is called to obtain the provider's instance.
250 231 * @param locale the given locale that is used as the starting one
251 232 * @param params provider specific parameters
252 233 * @return provider's instance, or null.
253 234 */
254 235 public <P extends LocaleServiceProvider, S> S getLocalizedObject(LocalizedObjectGetter<P, S> getter,
255 236 Locale locale,
256 237 Object... params) {
257 238 return getLocalizedObjectImpl(getter, locale, true, null, params);
258 239 }
259 240
260 241 /**
261 242 * Returns the provider's localized name for the specified
262 243 * locale.
263 244 *
264 245 * @param getter an object on which getObject() method
265 246 * is called to obtain the provider's instance.
266 247 * @param locale the given locale that is used as the starting one
267 248 * @param key the key string for name providers
268 249 * @param params provider specific parameters
269 250 * @return provider's instance, or null.
270 251 */
271 252 public <P extends LocaleServiceProvider, S> S getLocalizedObject(LocalizedObjectGetter<P, S> getter,
272 253 Locale locale,
273 254 String key,
274 255 Object... params) {
275 256 return getLocalizedObjectImpl(getter, locale, false, key, params);
276 257 }
277 258
278 259 @SuppressWarnings("unchecked")
279 260 private <P extends LocaleServiceProvider, S> S getLocalizedObjectImpl(LocalizedObjectGetter<P, S> getter,
280 261 Locale locale,
281 262 boolean isObjectProvider,
282 263 String key,
283 264 Object... params) {
284 265 if (locale == null) {
285 266 throw new NullPointerException();
286 267 }
287 268
288 269 // Check whether JRE is the sole locale data provider or not,
289 270 // and directly call it if it is.
290 271 if (!hasProviders()) {
291 272 return getter.getObject(
292 273 (P)providers.get(LocaleProviderAdapter.Type.JRE),
293 274 locale, key, params);
294 275 }
295 276
296 277 List<Locale> lookupLocales = getLookupLocales(locale);
297 278
298 279 Set<Locale> available = getAvailableLocaleList();
299 280 for (Locale current : lookupLocales) {
300 281 if (available.contains(current)) {
301 282 S providersObj;
302 283
303 284 for (LocaleProviderAdapter.Type type: findProviders(current)) {
304 285 LocaleServiceProvider lsp = providers.get(type);
305 286 providersObj = getter.getObject((P)lsp, current, key, params);
306 287 if (providersObj != null) {
307 288 return providersObj;
308 289 } else if (isObjectProvider) {
309 290 config(LocaleServiceProviderPool.class,
310 291 "A locale sensitive service provider returned null for a localized objects, which should not happen. provider: "
311 292 + lsp + " locale: " + locale);
312 293 }
313 294 }
314 295 }
315 296 }
316 297
317 298 // not found.
318 299 return null;
319 300 }
320 301
321 302 /**
322 303 * Returns the list of locale service provider instances that support
323 304 * the specified locale.
324 305 *
325 306 * @param locale the given locale
326 307 * @return the list of locale data adapter types
327 308 */
328 309 private List<LocaleProviderAdapter.Type> findProviders(Locale locale) {
329 310 List<LocaleProviderAdapter.Type> providersList = providersCache.get(locale);
330 311 if (providersList == null) {
331 312 for (LocaleProviderAdapter.Type type : LocaleProviderAdapter.getAdapterPreference()) {
332 313 LocaleServiceProvider lsp = providers.get(type);
333 314 if (lsp != null) {
334 315 if (lsp.isSupportedLocale(locale)) {
335 316 if (providersList == null) {
336 317 providersList = new ArrayList<>(2);
337 318 }
338 319 providersList.add(type);
339 320
340 321 }
341 322 }
342 323 }
343 324 if (providersList == null) {
344 325 providersList = NULL_LIST;
345 326 }
346 327 List<LocaleProviderAdapter.Type> val = providersCache.putIfAbsent(locale, providersList);
347 328 if (val != null) {
348 329 providersList = val;
349 330 }
350 331 }
351 332 return providersList;
352 333 }
353 334
354 335 /**
355 336 * Returns a list of candidate locales for service look up.
356 337 * @param locale the input locale
357 338 * @return the list of candidate locales for the given locale
358 339 */
359 340 private static List<Locale> getLookupLocales(Locale locale) {
360 341 // Note: We currently use the default implementation of
361 342 // ResourceBundle.Control.getCandidateLocales. The result
362 343 // returned by getCandidateLocales are already normalized
363 344 // (no extensions) for service look up.
364 345 List<Locale> lookupLocales = Control.getNoFallbackControl(Control.FORMAT_DEFAULT)
365 346 .getCandidateLocales("", locale);
366 347 return lookupLocales;
367 348 }
368 349
369 350 /**
370 351 * Returns an instance of Locale used for service look up.
371 352 * The result Locale has no extensions except for ja_JP_JP
372 353 * and th_TH_TH
373 354 *
374 355 * @param locale the locale
375 356 * @return the locale used for service look up
376 357 */
377 358 static Locale getLookupLocale(Locale locale) {
378 359 Locale lookupLocale = locale;
379 360 if (locale.hasExtensions()
380 361 && !locale.equals(JRELocaleConstants.JA_JP_JP)
381 362 && !locale.equals(JRELocaleConstants.TH_TH_TH)) {
382 363 // remove extensions
383 364 Builder locbld = new Builder();
384 365 try {
385 366 locbld.setLocale(locale);
386 367 locbld.clearExtensions();
387 368 lookupLocale = locbld.build();
388 369 } catch (IllformedLocaleException e) {
389 370 // A Locale with non-empty extensions
390 371 // should have well-formed fields except
391 372 // for ja_JP_JP and th_TH_TH. Therefore,
392 373 // it should never enter in this catch clause.
393 374 config(LocaleServiceProviderPool.class,
394 375 "A locale(" + locale + ") has non-empty extensions, but has illformed fields.");
395 376
396 377 // Fallback - script field will be lost.
397 378 lookupLocale = new Locale(locale.getLanguage(), locale.getCountry(), locale.getVariant());
398 379 }
399 380 }
400 381 return lookupLocale;
401 382 }
402 383
403 384 /**
404 385 * A dummy locale service provider list that indicates there is no
405 386 * provider available
406 387 */
407 388 private static List<LocaleProviderAdapter.Type> NULL_LIST =
408 389 Collections.emptyList();
409 390
410 391 /**
411 392 * An interface to get a localized object for each locale sensitive
412 393 * service class.
413 394 */
414 395 public interface LocalizedObjectGetter<P extends LocaleServiceProvider, S> {
415 396 /**
416 397 * Returns an object from the provider
417 398 *
418 399 * @param lsp the provider
419 400 * @param locale the locale
420 401 * @param key key string to localize, or null if the provider is not
421 402 * a name provider
422 403 * @param params provider specific params
423 404 * @return localized object from the provider
424 405 */
425 406 public S getObject(P lsp,
426 407 Locale locale,
427 408 String key,
428 409 Object... params);
429 410 }
430 411 }
↓ open down ↓ |
264 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX