1 /* 2 * Copyright (c) 2012, 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.security.AccessController; 29 import java.security.PrivilegedActionException; 30 import java.security.PrivilegedExceptionAction; 31 import java.text.*; 32 import java.text.spi.*; 33 import java.util.*; 34 import java.util.concurrent.*; 35 import java.util.spi.*; 36 37 /** 38 * LocaleProviderAdapter implementation for the installed SPI implementations. 39 * 40 * @author Naoto Sato 41 * @author Masayoshi Okutsu 42 */ 43 public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter { 44 45 /** 46 * Returns the type of this LocaleProviderAdapter 47 */ 48 @Override 49 public LocaleProviderAdapter.Type getAdapterType() { 50 return LocaleProviderAdapter.Type.SPI; 51 } 52 53 @Override 54 protected <P extends LocaleServiceProvider> P findInstalledProvider(final Class<P> c) { 55 try { 56 return AccessController.doPrivileged(new PrivilegedExceptionAction<P>() { 57 @Override 58 @SuppressWarnings("unchecked") 59 public P run() { 60 P delegate = null; 61 62 for (LocaleServiceProvider provider : ServiceLoader.loadInstalled(c)) { 63 if (delegate == null) { 64 try { 65 delegate = 66 (P) Class.forName(SPILocaleProviderAdapter.class.getCanonicalName() + 67 "$" + 68 c.getSimpleName() + 69 "Delegate") 70 .newInstance(); 71 } catch (ClassNotFoundException | 72 InstantiationException | 73 IllegalAccessException e) { 74 LocaleServiceProviderPool.config(SPILocaleProviderAdapter.class, e.toString()); 75 return null; 76 } 77 } 78 79 ((Delegate)delegate).addImpl(provider); 80 } 81 return delegate; 82 } 83 }); 84 } catch (PrivilegedActionException e) { 85 LocaleServiceProviderPool.config(SPILocaleProviderAdapter.class, e.toString()); 86 } 87 return null; 88 } 89 90 /* 91 * Delegate interface. All the implementations have to have the class name 92 * following "<provider class name>Delegate" convention. 93 */ 94 interface Delegate<P extends LocaleServiceProvider> { 95 public void addImpl(P impl); 96 public P getImpl(Locale locale); 97 } 98 99 /* 100 * Obtain the real SPI implementation, using locale fallback 101 */ 102 private static <P extends LocaleServiceProvider> P getImpl(Map<Locale, P> map, Locale locale) { 103 for (Locale l : LocaleServiceProviderPool.getLookupLocales(locale)) { 104 P ret = map.get(l); 105 if (ret != null) { 106 return ret; 107 } 108 } 109 return null; 110 } 111 112 /* 113 * Delegates for the actual SPI implementations. 114 */ 115 static class BreakIteratorProviderDelegate extends BreakIteratorProvider 116 implements Delegate<BreakIteratorProvider> { 117 private ConcurrentMap<Locale, BreakIteratorProvider> map = new ConcurrentHashMap<>(); 118 119 @Override 120 public void addImpl(BreakIteratorProvider impl) { 121 for (Locale l : impl.getAvailableLocales()) { 122 map.put(l, impl); 123 } 124 } 125 126 @Override 127 public BreakIteratorProvider getImpl(Locale locale) { 128 return SPILocaleProviderAdapter.getImpl(map, locale); 129 } 130 131 @Override 132 public Locale[] getAvailableLocales() { 133 return map.keySet().toArray(new Locale[0]); 134 } 135 136 @Override 137 public boolean isSupportedLocale(Locale locale) { 138 return map.keySet().contains(locale); 139 } 140 141 @Override 142 public BreakIterator getWordInstance(Locale locale) { 143 BreakIteratorProvider bip = getImpl(locale); 144 if (bip != null) { 145 return bip.getWordInstance(locale); 146 } else { 147 return null; 148 } 149 } 150 151 @Override 152 public BreakIterator getLineInstance(Locale locale) { 153 BreakIteratorProvider bip = getImpl(locale); 154 if (bip != null) { 155 return bip.getLineInstance(locale); 156 } else { 157 return null; 158 } 159 } 160 161 @Override 162 public BreakIterator getCharacterInstance(Locale locale) { 163 BreakIteratorProvider bip = getImpl(locale); 164 if (bip != null) { 165 return bip.getCharacterInstance(locale); 166 } else { 167 return null; 168 } 169 } 170 171 @Override 172 public BreakIterator getSentenceInstance(Locale locale) { 173 BreakIteratorProvider bip = getImpl(locale); 174 if (bip != null) { 175 return bip.getSentenceInstance(locale); 176 } else { 177 return null; 178 } 179 } 180 181 } 182 183 static class CollatorProviderDelegate extends CollatorProvider implements Delegate<CollatorProvider> { 184 private ConcurrentMap<Locale, CollatorProvider> map = new ConcurrentHashMap<>(); 185 186 @Override 187 public void addImpl(CollatorProvider impl) { 188 for (Locale l : impl.getAvailableLocales()) { 189 map.put(l, impl); 190 } 191 } 192 193 @Override 194 public CollatorProvider getImpl(Locale locale) { 195 return SPILocaleProviderAdapter.getImpl(map, locale); 196 } 197 198 @Override 199 public Locale[] getAvailableLocales() { 200 return map.keySet().toArray(new Locale[0]); 201 } 202 203 @Override 204 public boolean isSupportedLocale(Locale locale) { 205 return map.keySet().contains(locale); 206 } 207 208 @Override 209 public Collator getInstance(Locale locale) { 210 CollatorProvider cp = getImpl(locale); 211 if (cp != null) { 212 return cp.getInstance(locale); 213 } else { 214 return null; 215 } 216 } 217 } 218 219 static class DateFormatProviderDelegate extends DateFormatProvider 220 implements Delegate<DateFormatProvider> { 221 private ConcurrentMap<Locale, DateFormatProvider> map = new ConcurrentHashMap<>(); 222 223 @Override 224 public void addImpl(DateFormatProvider impl) { 225 for (Locale l : impl.getAvailableLocales()) { 226 map.put(l, impl); 227 } 228 } 229 230 @Override 231 public DateFormatProvider getImpl(Locale locale) { 232 return SPILocaleProviderAdapter.getImpl(map, locale); 233 } 234 235 @Override 236 public Locale[] getAvailableLocales() { 237 return map.keySet().toArray(new Locale[0]); 238 } 239 240 @Override 241 public boolean isSupportedLocale(Locale locale) { 242 return map.keySet().contains(locale); 243 } 244 245 @Override 246 public DateFormat getTimeInstance(int style, Locale locale) { 247 DateFormatProvider dfp = getImpl(locale); 248 if (dfp != null) { 249 return dfp.getTimeInstance(style, locale); 250 } else { 251 return null; 252 } 253 } 254 255 @Override 256 public DateFormat getDateInstance(int style, Locale locale) { 257 DateFormatProvider dfp = getImpl(locale); 258 if (dfp != null) { 259 return dfp.getDateInstance(style, locale); 260 } else { 261 return null; 262 } 263 } 264 265 @Override 266 public DateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale locale) { 267 DateFormatProvider dfp = getImpl(locale); 268 if (dfp != null) { 269 return dfp.getDateTimeInstance(dateStyle, timeStyle, locale); 270 } else { 271 return null; 272 } 273 } 274 } 275 276 static class DateFormatSymbolsProviderDelegate extends DateFormatSymbolsProvider 277 implements Delegate<DateFormatSymbolsProvider> { 278 private ConcurrentMap<Locale, DateFormatSymbolsProvider> map = new ConcurrentHashMap<>(); 279 280 @Override 281 public void addImpl(DateFormatSymbolsProvider impl) { 282 for (Locale l : impl.getAvailableLocales()) { 283 map.put(l, impl); 284 } 285 } 286 287 @Override 288 public DateFormatSymbolsProvider getImpl(Locale locale) { 289 return SPILocaleProviderAdapter.getImpl(map, locale); 290 } 291 292 @Override 293 public Locale[] getAvailableLocales() { 294 return map.keySet().toArray(new Locale[0]); 295 } 296 297 @Override 298 public boolean isSupportedLocale(Locale locale) { 299 return map.keySet().contains(locale); 300 } 301 302 @Override 303 public DateFormatSymbols getInstance(Locale locale) { 304 DateFormatSymbolsProvider dfsp = getImpl(locale); 305 if (dfsp != null) { 306 return dfsp.getInstance(locale); 307 } else { 308 return null; 309 } 310 } 311 } 312 313 static class DecimalFormatSymbolsProviderDelegate extends DecimalFormatSymbolsProvider 314 implements Delegate<DecimalFormatSymbolsProvider> { 315 private ConcurrentMap<Locale, DecimalFormatSymbolsProvider> map = new ConcurrentHashMap<>(); 316 317 @Override 318 public void addImpl(DecimalFormatSymbolsProvider impl) { 319 for (Locale l : impl.getAvailableLocales()) { 320 map.put(l, impl); 321 } 322 } 323 324 @Override 325 public DecimalFormatSymbolsProvider getImpl(Locale locale) { 326 return SPILocaleProviderAdapter.getImpl(map, locale); 327 } 328 329 @Override 330 public Locale[] getAvailableLocales() { 331 return map.keySet().toArray(new Locale[0]); 332 } 333 334 @Override 335 public boolean isSupportedLocale(Locale locale) { 336 return map.keySet().contains(locale); 337 } 338 339 @Override 340 public DecimalFormatSymbols getInstance(Locale locale) { 341 DecimalFormatSymbolsProvider dfsp = getImpl(locale); 342 if (dfsp != null) { 343 return dfsp.getInstance(locale); 344 } else { 345 return null; 346 } 347 } 348 } 349 350 static class NumberFormatProviderDelegate extends NumberFormatProvider 351 implements Delegate<NumberFormatProvider> { 352 private ConcurrentMap<Locale, NumberFormatProvider> map = new ConcurrentHashMap<>(); 353 354 @Override 355 public void addImpl(NumberFormatProvider impl) { 356 for (Locale l : impl.getAvailableLocales()) { 357 map.put(l, impl); 358 } 359 } 360 361 @Override 362 public NumberFormatProvider getImpl(Locale locale) { 363 return SPILocaleProviderAdapter.getImpl(map, locale); 364 } 365 366 @Override 367 public Locale[] getAvailableLocales() { 368 return map.keySet().toArray(new Locale[0]); 369 } 370 371 @Override 372 public boolean isSupportedLocale(Locale locale) { 373 return map.keySet().contains(locale); 374 } 375 376 @Override 377 public NumberFormat getCurrencyInstance(Locale locale) { 378 NumberFormatProvider nfp = getImpl(locale); 379 if (nfp != null) { 380 return nfp.getCurrencyInstance(locale); 381 } else { 382 return null; 383 } 384 } 385 386 @Override 387 public NumberFormat getIntegerInstance(Locale locale) { 388 NumberFormatProvider nfp = getImpl(locale); 389 if (nfp != null) { 390 return nfp.getIntegerInstance(locale); 391 } else { 392 return null; 393 } 394 } 395 396 @Override 397 public NumberFormat getNumberInstance(Locale locale) { 398 NumberFormatProvider nfp = getImpl(locale); 399 if (nfp != null) { 400 return nfp.getNumberInstance(locale); 401 } else { 402 return null; 403 } 404 } 405 406 @Override 407 public NumberFormat getPercentInstance(Locale locale) { 408 NumberFormatProvider nfp = getImpl(locale); 409 if (nfp != null) { 410 return nfp.getPercentInstance(locale); 411 } else { 412 return null; 413 } 414 } 415 } 416 417 static class CalendarDataProviderDelegate extends CalendarDataProvider 418 implements Delegate<CalendarDataProvider> { 419 private ConcurrentMap<Locale, CalendarDataProvider> map = new ConcurrentHashMap<>(); 420 421 @Override 422 public void addImpl(CalendarDataProvider impl) { 423 for (Locale l : impl.getAvailableLocales()) { 424 map.put(l, impl); 425 } 426 } 427 428 @Override 429 public CalendarDataProvider getImpl(Locale locale) { 430 return SPILocaleProviderAdapter.getImpl(map, locale); 431 } 432 433 @Override 434 public Locale[] getAvailableLocales() { 435 return map.keySet().toArray(new Locale[0]); 436 } 437 438 @Override 439 public boolean isSupportedLocale(Locale locale) { 440 return map.keySet().contains(locale); 441 } 442 443 @Override 444 public int getFirstDayOfWeek(Locale locale) { 445 CalendarDataProvider cdp = getImpl(locale); 446 if (cdp != null) { 447 return cdp.getFirstDayOfWeek(locale); 448 } else { 449 return 0; 450 } 451 } 452 453 @Override 454 public int getMinimalDaysInFirstWeek(Locale locale) { 455 CalendarDataProvider cdp = getImpl(locale); 456 if (cdp != null) { 457 return cdp.getMinimalDaysInFirstWeek(locale); 458 } else { 459 return 0; 460 } 461 } 462 463 @Override 464 public String getDisplayName(String calendarType, 465 int field, int value, 466 int style, Locale locale) { 467 CalendarDataProvider cdp = getImpl(locale); 468 if (cdp != null) { 469 return cdp.getDisplayName(calendarType, field, value, style, locale); 470 } else { 471 return null; 472 } 473 } 474 475 @Override 476 public Map<String, Integer> getDisplayNames(String calendarType, 477 int field, int style, 478 Locale locale) { 479 CalendarDataProvider cdp = getImpl(locale); 480 if (cdp != null) { 481 return cdp.getDisplayNames(calendarType, field, style, locale); 482 } else { 483 return null; 484 } 485 } 486 } 487 488 static class CurrencyNameProviderDelegate extends CurrencyNameProvider 489 implements Delegate<CurrencyNameProvider> { 490 private ConcurrentMap<Locale, CurrencyNameProvider> map = new ConcurrentHashMap<>(); 491 492 @Override 493 public void addImpl(CurrencyNameProvider impl) { 494 for (Locale l : impl.getAvailableLocales()) { 495 map.put(l, impl); 496 } 497 } 498 499 @Override 500 public CurrencyNameProvider getImpl(Locale locale) { 501 return SPILocaleProviderAdapter.getImpl(map, locale); 502 } 503 504 @Override 505 public Locale[] getAvailableLocales() { 506 return map.keySet().toArray(new Locale[0]); 507 } 508 509 @Override 510 public boolean isSupportedLocale(Locale locale) { 511 return map.keySet().contains(locale); 512 } 513 514 @Override 515 public String getSymbol(String currencyCode, Locale locale) { 516 CurrencyNameProvider cnp = getImpl(locale); 517 if (cnp != null) { 518 return cnp.getSymbol(currencyCode, locale); 519 } else { 520 return null; 521 } 522 } 523 524 @Override 525 public String getDisplayName(String currencyCode, Locale locale) { 526 CurrencyNameProvider cnp = getImpl(locale); 527 if (cnp != null) { 528 return cnp.getDisplayName(currencyCode, locale); 529 } else { 530 return null; 531 } 532 } 533 } 534 535 static class LocaleNameProviderDelegate extends LocaleNameProvider 536 implements Delegate<LocaleNameProvider> { 537 private ConcurrentMap<Locale, LocaleNameProvider> map = new ConcurrentHashMap<>(); 538 539 @Override 540 public void addImpl(LocaleNameProvider impl) { 541 for (Locale l : impl.getAvailableLocales()) { 542 map.put(l, impl); 543 } 544 } 545 546 @Override 547 public LocaleNameProvider getImpl(Locale locale) { 548 return SPILocaleProviderAdapter.getImpl(map, locale); 549 } 550 551 @Override 552 public Locale[] getAvailableLocales() { 553 return map.keySet().toArray(new Locale[0]); 554 } 555 556 @Override 557 public boolean isSupportedLocale(Locale locale) { 558 return map.keySet().contains(locale); 559 } 560 561 @Override 562 public String getDisplayLanguage(String languageCode, Locale locale) { 563 LocaleNameProvider lnp = getImpl(locale); 564 if (lnp != null) { 565 return lnp.getDisplayLanguage(languageCode, locale); 566 } else { 567 return null; 568 } 569 } 570 571 @Override 572 public String getDisplayScript(String scriptCode, Locale locale) { 573 LocaleNameProvider lnp = getImpl(locale); 574 if (lnp != null) { 575 return lnp.getDisplayScript(scriptCode, locale); 576 } else { 577 return null; 578 } 579 } 580 581 @Override 582 public String getDisplayCountry(String countryCode, Locale locale) { 583 LocaleNameProvider lnp = getImpl(locale); 584 if (lnp != null) { 585 return lnp.getDisplayCountry(countryCode, locale); 586 } else { 587 return null; 588 } 589 } 590 591 @Override 592 public String getDisplayVariant(String variant, Locale locale) { 593 LocaleNameProvider lnp = getImpl(locale); 594 if (lnp != null) { 595 return lnp.getDisplayVariant(variant, locale); 596 } else { 597 return null; 598 } 599 } 600 601 } 602 603 static class TimeZoneNameProviderDelegate extends TimeZoneNameProvider 604 implements Delegate<TimeZoneNameProvider> { 605 private ConcurrentMap<Locale, TimeZoneNameProvider> map = new ConcurrentHashMap<>(); 606 607 @Override 608 public void addImpl(TimeZoneNameProvider impl) { 609 for (Locale l : impl.getAvailableLocales()) { 610 map.put(l, impl); 611 } 612 } 613 614 @Override 615 public TimeZoneNameProvider getImpl(Locale locale) { 616 return SPILocaleProviderAdapter.getImpl(map, locale); 617 } 618 619 @Override 620 public Locale[] getAvailableLocales() { 621 return map.keySet().toArray(new Locale[0]); 622 } 623 624 @Override 625 public boolean isSupportedLocale(Locale locale) { 626 return map.keySet().contains(locale); 627 } 628 629 @Override 630 public String getDisplayName(String ID, boolean daylight, int style, Locale locale) { 631 TimeZoneNameProvider tznp = getImpl(locale); 632 if (tznp != null) { 633 return tznp.getDisplayName(ID, daylight, style, locale); 634 } else { 635 return null; 636 } 637 } 638 } 639 }