Print this page
rev 5931 : imported patch 8000245.8000273.8000615
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;
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 129 // Add the JRE Locale Data Adapter implementation.
130 130 providers.putIfAbsent(LocaleProviderAdapter.Type.JRE,
131 131 LocaleProviderAdapter.forJRE().getLocaleServiceProvider(c));
132 132
133 133 // Add the SPI Locale Data Adapter implementation.
134 134 LocaleProviderAdapter lda = LocaleProviderAdapter.forType(LocaleProviderAdapter.Type.SPI);
135 135 LocaleServiceProvider provider = lda.getLocaleServiceProvider(c);
136 136 if (provider != null) {
137 137 providers.putIfAbsent(LocaleProviderAdapter.Type.SPI, provider);
138 138 }
139 139
140 140 // Add the CLDR Locale Data Adapter implementation, if needed.
141 141 lda = LocaleProviderAdapter.forType(LocaleProviderAdapter.Type.CLDR);
142 142 if (lda != null) {
143 143 provider = lda.getLocaleServiceProvider(c);
144 144 if (provider != null) {
145 145 providers.putIfAbsent(LocaleProviderAdapter.Type.CLDR, provider);
146 146 }
147 147 }
148 148
149 149 // Add the Host Locale Data Adapter implementation, if needed.
150 150 lda = LocaleProviderAdapter.forType(LocaleProviderAdapter.Type.HOST);
151 151 if (lda != null) {
152 152 provider = lda.getLocaleServiceProvider(c);
153 153 if (provider != null) {
154 154 providers.putIfAbsent(LocaleProviderAdapter.Type.HOST, provider);
155 155 }
156 156 }
157 157 }
158 158
159 159 static void config(Class<? extends Object> caller, String message) {
160 160 PlatformLogger logger = PlatformLogger.getLogger(caller.getCanonicalName());
161 161 logger.config(message);
162 162 }
163 163
164 164 /**
165 165 * Lazy loaded set of available locales.
166 166 * Loading all locales is a very long operation.
167 167 */
168 168 private static class AllAvailableLocales {
169 169 /**
170 170 * Available locales for all locale sensitive services.
171 171 * This also contains JRE's available locales
172 172 */
173 173 static final Locale[] allAvailableLocales;
174 174
175 175 static {
176 176 Set<Locale> all = new HashSet<>();
177 177 for (Class<? extends LocaleServiceProvider> c : spiClasses) {
178 178 LocaleServiceProviderPool pool =
179 179 LocaleServiceProviderPool.getPool(c);
180 180 all.addAll(pool.getAvailableLocaleList());
181 181 }
182 182
183 183 allAvailableLocales = all.toArray(new Locale[0]);
184 184 }
185 185
186 186 // No instantiation
187 187 private AllAvailableLocales() {
188 188 }
189 189 }
190 190
191 191 /**
192 192 * Returns an array of available locales for all the provider classes.
193 193 * This array is a merged array of all the locales that are provided by each
194 194 * provider, including the JRE.
195 195 *
196 196 * @return an array of the available locales for all provider classes
197 197 */
198 198 public static Locale[] getAllAvailableLocales() {
199 199 return AllAvailableLocales.allAvailableLocales.clone();
200 200 }
201 201
202 202 /**
203 203 * Returns an array of available locales. This array is a
204 204 * merged array of all the locales that are provided by each
205 205 * provider, including the JRE.
206 206 *
207 207 * @return an array of the available locales
208 208 */
209 209 public Locale[] getAvailableLocales() {
210 210 Set<Locale> locList = getAvailableLocaleList();
211 211 Locale[] tmp = new Locale[locList.size()];
212 212 locList.toArray(tmp);
213 213 return tmp;
214 214 }
215 215
216 216 private synchronized Set<Locale> getAvailableLocaleList() {
217 217 if (availableLocales == null) {
218 218 availableLocales = new HashSet<>();
219 219 for (LocaleServiceProvider lsp : providers.values()) {
220 220 Locale[] locales = lsp.getAvailableLocales();
221 221 for (Locale locale: locales) {
222 222 availableLocales.add(getLookupLocale(locale));
223 223 }
224 224 }
225 225
226 226 // Remove Locale.ROOT for the compatibility.
227 227 availableLocales.remove(Locale.ROOT);
228 228 }
229 229
230 230 return availableLocales;
231 231 }
232 232
233 233 /**
234 234 * Returns whether any provider for this locale sensitive
235 235 * service is available or not, excluding JRE's one.
236 236 *
237 237 * @return true if any provider (other than JRE) is available
238 238 */
239 239 boolean hasProviders() {
240 240 return providers.size() != 1 ||
241 241 providers.get(LocaleProviderAdapter.Type.JRE) == null;
242 242 }
243 243
244 244 /**
245 245 * Returns the provider's localized object for the specified
246 246 * locale.
247 247 *
248 248 * @param getter an object on which getObject() method
249 249 * is called to obtain the provider's instance.
250 250 * @param locale the given locale that is used as the starting one
251 251 * @param params provider specific parameters
252 252 * @return provider's instance, or null.
253 253 */
254 254 public <P extends LocaleServiceProvider, S> S getLocalizedObject(LocalizedObjectGetter<P, S> getter,
255 255 Locale locale,
256 256 Object... params) {
257 257 return getLocalizedObjectImpl(getter, locale, true, null, params);
258 258 }
259 259
260 260 /**
261 261 * Returns the provider's localized name for the specified
262 262 * locale.
263 263 *
264 264 * @param getter an object on which getObject() method
265 265 * is called to obtain the provider's instance.
266 266 * @param locale the given locale that is used as the starting one
267 267 * @param key the key string for name providers
268 268 * @param params provider specific parameters
269 269 * @return provider's instance, or null.
270 270 */
271 271 public <P extends LocaleServiceProvider, S> S getLocalizedObject(LocalizedObjectGetter<P, S> getter,
272 272 Locale locale,
273 273 String key,
274 274 Object... params) {
275 275 return getLocalizedObjectImpl(getter, locale, false, key, params);
276 276 }
277 277
278 278 @SuppressWarnings("unchecked")
279 279 private <P extends LocaleServiceProvider, S> S getLocalizedObjectImpl(LocalizedObjectGetter<P, S> getter,
280 280 Locale locale,
281 281 boolean isObjectProvider,
282 282 String key,
283 283 Object... params) {
284 284 if (locale == null) {
285 285 throw new NullPointerException();
286 286 }
287 287
288 288 // Check whether JRE is the sole locale data provider or not,
289 289 // and directly call it if it is.
290 290 if (!hasProviders()) {
291 291 return getter.getObject(
292 292 (P)providers.get(LocaleProviderAdapter.Type.JRE),
293 293 locale, key, params);
294 294 }
↓ open down ↓ |
294 lines elided |
↑ open up ↑ |
295 295
296 296 List<Locale> lookupLocales = getLookupLocales(locale);
297 297
298 298 Set<Locale> available = getAvailableLocaleList();
299 299 for (Locale current : lookupLocales) {
300 300 if (available.contains(current)) {
301 301 S providersObj;
302 302
303 303 for (LocaleProviderAdapter.Type type: findProviders(current)) {
304 304 LocaleServiceProvider lsp = providers.get(type);
305 - providersObj = getter.getObject((P)lsp, current, key, params);
305 + providersObj = getter.getObject((P)lsp, locale, key, params);
306 306 if (providersObj != null) {
307 307 return providersObj;
308 308 } else if (isObjectProvider) {
309 309 config(LocaleServiceProviderPool.class,
310 310 "A locale sensitive service provider returned null for a localized objects, which should not happen. provider: "
311 311 + lsp + " locale: " + locale);
312 312 }
313 313 }
314 314 }
315 315 }
316 316
317 317 // not found.
318 318 return null;
319 319 }
320 320
321 321 /**
322 322 * Returns the list of locale service provider instances that support
323 323 * the specified locale.
324 324 *
325 325 * @param locale the given locale
326 326 * @return the list of locale data adapter types
327 327 */
328 328 private List<LocaleProviderAdapter.Type> findProviders(Locale locale) {
329 329 List<LocaleProviderAdapter.Type> providersList = providersCache.get(locale);
330 330 if (providersList == null) {
331 331 for (LocaleProviderAdapter.Type type : LocaleProviderAdapter.getAdapterPreference()) {
332 332 LocaleServiceProvider lsp = providers.get(type);
333 333 if (lsp != null) {
334 334 if (lsp.isSupportedLocale(locale)) {
335 335 if (providersList == null) {
336 336 providersList = new ArrayList<>(2);
337 337 }
338 338 providersList.add(type);
339 339
340 340 }
341 341 }
342 342 }
343 343 if (providersList == null) {
344 344 providersList = NULL_LIST;
345 345 }
346 346 List<LocaleProviderAdapter.Type> val = providersCache.putIfAbsent(locale, providersList);
347 347 if (val != null) {
348 348 providersList = val;
349 349 }
350 350 }
351 351 return providersList;
352 352 }
353 353
354 354 /**
355 355 * Returns a list of candidate locales for service look up.
356 356 * @param locale the input locale
357 357 * @return the list of candidate locales for the given locale
358 358 */
359 359 private static List<Locale> getLookupLocales(Locale locale) {
360 360 // Note: We currently use the default implementation of
361 361 // ResourceBundle.Control.getCandidateLocales. The result
362 362 // returned by getCandidateLocales are already normalized
363 363 // (no extensions) for service look up.
364 364 List<Locale> lookupLocales = Control.getNoFallbackControl(Control.FORMAT_DEFAULT)
365 365 .getCandidateLocales("", locale);
366 366 return lookupLocales;
367 367 }
368 368
369 369 /**
370 370 * Returns an instance of Locale used for service look up.
371 371 * The result Locale has no extensions except for ja_JP_JP
372 372 * and th_TH_TH
373 373 *
374 374 * @param locale the locale
375 375 * @return the locale used for service look up
376 376 */
377 377 static Locale getLookupLocale(Locale locale) {
378 378 Locale lookupLocale = locale;
379 379 if (locale.hasExtensions()
380 380 && !locale.equals(JRELocaleConstants.JA_JP_JP)
381 381 && !locale.equals(JRELocaleConstants.TH_TH_TH)) {
382 382 // remove extensions
383 383 Builder locbld = new Builder();
384 384 try {
385 385 locbld.setLocale(locale);
386 386 locbld.clearExtensions();
387 387 lookupLocale = locbld.build();
388 388 } catch (IllformedLocaleException e) {
389 389 // A Locale with non-empty extensions
390 390 // should have well-formed fields except
391 391 // for ja_JP_JP and th_TH_TH. Therefore,
392 392 // it should never enter in this catch clause.
393 393 config(LocaleServiceProviderPool.class,
394 394 "A locale(" + locale + ") has non-empty extensions, but has illformed fields.");
395 395
396 396 // Fallback - script field will be lost.
397 397 lookupLocale = new Locale(locale.getLanguage(), locale.getCountry(), locale.getVariant());
398 398 }
399 399 }
400 400 return lookupLocale;
401 401 }
402 402
403 403 /**
404 404 * A dummy locale service provider list that indicates there is no
405 405 * provider available
406 406 */
407 407 private static List<LocaleProviderAdapter.Type> NULL_LIST =
408 408 Collections.emptyList();
409 409
410 410 /**
411 411 * An interface to get a localized object for each locale sensitive
412 412 * service class.
413 413 */
414 414 public interface LocalizedObjectGetter<P extends LocaleServiceProvider, S> {
415 415 /**
416 416 * Returns an object from the provider
417 417 *
418 418 * @param lsp the provider
419 419 * @param locale the locale
420 420 * @param key key string to localize, or null if the provider is not
421 421 * a name provider
422 422 * @param params provider specific params
423 423 * @return localized object from the provider
424 424 */
425 425 public S getObject(P lsp,
426 426 Locale locale,
427 427 String key,
428 428 Object... params);
429 429 }
430 430 }
↓ open down ↓ |
115 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX