src/windows/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java

Print this page
rev 6958 : imported patch 8010666
   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 package sun.util.locale.provider;
  26 
  27 import java.lang.ref.SoftReference;
  28 import java.text.DateFormat;
  29 import java.text.DateFormatSymbols;
  30 import java.text.DecimalFormat;
  31 import java.text.DecimalFormatSymbols;
  32 import java.text.NumberFormat;
  33 import java.text.SimpleDateFormat;
  34 import java.text.spi.DateFormatProvider;
  35 import java.text.spi.DateFormatSymbolsProvider;
  36 import java.text.spi.DecimalFormatSymbolsProvider;
  37 import java.text.spi.NumberFormatProvider;
  38 import java.util.Calendar;
  39 import java.util.Collections;

  40 import java.util.HashSet;
  41 import java.util.Locale;
  42 import java.util.Map;
  43 import java.util.ResourceBundle.Control;
  44 import java.util.Set;
  45 import java.util.TimeZone;
  46 import java.util.concurrent.ConcurrentHashMap;
  47 import java.util.concurrent.ConcurrentMap;
  48 import java.util.concurrent.atomic.AtomicReferenceArray;
  49 import java.util.spi.CalendarDataProvider;
  50 import java.util.spi.CalendarNameProvider;


  51 import sun.util.spi.CalendarProvider;
  52 
  53 /**
  54  * LocaleProviderdapter implementation for the Windows locale data.
  55  *
  56  * @author Naoto Sato
  57  */
  58 public class HostLocaleProviderAdapterImpl {
  59 
  60     // locale categories
  61     private static final int CAT_DISPLAY = 0;
  62     private static final int CAT_FORMAT  = 1;
  63 
  64     // NumberFormat styles
  65     private static final int NF_NUMBER   = 0;
  66     private static final int NF_CURRENCY = 1;
  67     private static final int NF_PERCENT  = 2;
  68     private static final int NF_INTEGER  = 3;
  69     private static final int NF_MAX = NF_INTEGER;
  70 
  71     // CalendarData value types
  72     private static final int CD_FIRSTDAYOFWEEK = 0;
  73     private static final int CD_MINIMALDAYSINFIRSTWEEK = 1;
  74 








  75     // Native Calendar ID to LDML calendar type map
  76     private static final String[] calIDToLDML = {
  77         "",
  78         "gregory",
  79         "gregory_en-US",
  80         "japanese",
  81         "roc",
  82         "",          // No appropriate type for CAL_KOREA
  83         "islamic",
  84         "buddhist",
  85         "hebrew",
  86         "gregory_fr",
  87         "gregory_ar",
  88         "gregory_en",
  89         "gregory_fr",
  90     };
  91 
  92     // Caches
  93     private static ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> dateFormatCache = new ConcurrentHashMap<>();
  94     private static ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> dateFormatSymbolsCache = new ConcurrentHashMap<>();
  95     private static ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> numberFormatCache = new ConcurrentHashMap<>();
  96     private static ConcurrentMap<Locale, SoftReference<DecimalFormatSymbols>> decimalFormatSymbolsCache = new ConcurrentHashMap<>();
  97 
  98     private static final Set<Locale> supportedLocaleSet;

  99     static {
 100         Set<Locale> tmpSet = new HashSet<>();
 101         if (initialize()) {
 102             // Assuming the default locales do not include any extensions, so
 103             // no stripping is needed here.
 104             Locale l = Locale.forLanguageTag(getDefaultLocale(CAT_FORMAT).replace('_', '-'));
 105             tmpSet.addAll(Control.getNoFallbackControl(Control.FORMAT_DEFAULT).getCandidateLocales("", l));
 106             l = Locale.forLanguageTag(getDefaultLocale(CAT_DISPLAY).replace('_', '-'));
 107             tmpSet.addAll(Control.getNoFallbackControl(Control.FORMAT_DEFAULT).getCandidateLocales("", l));






 108         }



 109         supportedLocaleSet = Collections.unmodifiableSet(tmpSet);
 110     }
 111     private final static Locale[] supportedLocale = supportedLocaleSet.toArray(new Locale[0]);
 112 
 113     public static DateFormatProvider getDateFormatProvider() {
 114         return new DateFormatProvider() {
 115             @Override
 116             public Locale[] getAvailableLocales() {
 117                 return getSupportedCalendarLocales();
 118             }
 119 
 120             @Override
 121             public boolean isSupportedLocale(Locale locale) {
 122                 return isSupportedCalendarLocale(locale);
 123             }
 124 
 125             @Override
 126             public DateFormat getDateInstance(int style, Locale locale) {
 127                 AtomicReferenceArray<String> patterns = getDateTimePatterns(locale);
 128                 return new SimpleDateFormat(patterns.get(style/2),


 375             public Locale[] getAvailableLocales() {
 376                 return getSupportedCalendarLocales();
 377             }
 378 
 379             @Override
 380             public boolean isSupportedLocale(Locale locale) {
 381                 return isSupportedCalendarLocale(locale);
 382             }
 383 
 384             @Override
 385             public Calendar getInstance(TimeZone zone, Locale locale) {
 386                 return new Calendar.Builder()
 387                              .setLocale(getCalendarLocale(locale))
 388                              .setTimeZone(zone)
 389                              .setInstant(System.currentTimeMillis())
 390                              .build();
 391             }
 392         };
 393     }
 394 


























































































 395     private static String convertDateTimePattern(String winPattern) {
 396         String ret = winPattern.replaceAll("dddd", "EEEE");
 397         ret = ret.replaceAll("ddd", "EEE");
 398         ret = ret.replaceAll("tt", "aa");
 399         ret = ret.replaceAll("g", "GG");
 400         return ret;
 401     }
 402 
 403     private static Locale[] getSupportedCalendarLocales() {
 404         if (supportedLocale.length != 0 &&
 405             supportedLocaleSet.contains(Locale.JAPAN) &&
 406             isJapaneseCalendar()) {
 407             Locale[] sup = new Locale[supportedLocale.length+1];
 408             sup[0] = JRELocaleConstants.JA_JP_JP;
 409             System.arraycopy(supportedLocale, 0, sup, 1, supportedLocale.length);
 410             return sup;
 411         }
 412         return supportedLocale;
 413     }
 414 
 415     private static boolean isSupportedCalendarLocale(Locale locale) {
 416         Locale base = locale.stripExtensions();









 417         if (!supportedLocaleSet.contains(base)) {
 418             return false;
 419         }
 420 
 421         int calid = getCalendarID(locale.toLanguageTag());
 422         if (calid <= 0 || calid >= calIDToLDML.length) {
 423             return false;
 424         }
 425 
 426         String requestedCalType = locale.getUnicodeLocaleType("ca");
 427         String nativeCalType = calIDToLDML[calid]
 428                 .replaceFirst("_.*", ""); // remove locale part.
 429 
 430         if (requestedCalType == null) {
 431             return Calendar.getAvailableCalendarTypes().contains(nativeCalType);
 432         } else {
 433             return requestedCalType.equals(nativeCalType);
 434         }
 435     }
 436 
 437     private static Locale[] getSupportedNativeDigitLocales() {
 438         if (supportedLocale.length != 0 &&
 439             supportedLocaleSet.contains(JRELocaleConstants.TH_TH) &&
 440             isNativeDigit("th-TH")) {
 441             Locale[] sup = new Locale[supportedLocale.length+1];


 529 
 530     // For NumberFormatProvider
 531     private static native String getNumberPattern(int numberStyle, String langTag);
 532     private static native boolean isNativeDigit(String langTag);
 533 
 534     // For DecimalFormatSymbolsProvider
 535     private static native String getCurrencySymbol(String langTag, String currencySymbol);
 536     private static native char getDecimalSeparator(String langTag, char decimalSeparator);
 537     private static native char getGroupingSeparator(String langTag, char groupingSeparator);
 538     private static native String getInfinity(String langTag, String infinity);
 539     private static native String getInternationalCurrencySymbol(String langTag, String internationalCurrencySymbol);
 540     private static native char getMinusSign(String langTag, char minusSign);
 541     private static native char getMonetaryDecimalSeparator(String langTag, char monetaryDecimalSeparator);
 542     private static native String getNaN(String langTag, String nan);
 543     private static native char getPercent(String langTag, char percent);
 544     private static native char getPerMill(String langTag, char perMill);
 545     private static native char getZeroDigit(String langTag, char zeroDigit);
 546 
 547     // For CalendarDataProvider
 548     private static native int getCalendarDataValue(String langTag, int type);



 549 }
   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 package sun.util.locale.provider;
  26 
  27 import java.lang.ref.SoftReference;
  28 import java.text.DateFormat;
  29 import java.text.DateFormatSymbols;
  30 import java.text.DecimalFormat;
  31 import java.text.DecimalFormatSymbols;
  32 import java.text.NumberFormat;
  33 import java.text.SimpleDateFormat;
  34 import java.text.spi.DateFormatProvider;
  35 import java.text.spi.DateFormatSymbolsProvider;
  36 import java.text.spi.DecimalFormatSymbolsProvider;
  37 import java.text.spi.NumberFormatProvider;
  38 import java.util.Calendar;
  39 import java.util.Collections;
  40 import java.util.Currency;
  41 import java.util.HashSet;
  42 import java.util.Locale;
  43 import java.util.Map;
  44 import java.util.ResourceBundle.Control;
  45 import java.util.Set;
  46 import java.util.TimeZone;
  47 import java.util.concurrent.ConcurrentHashMap;
  48 import java.util.concurrent.ConcurrentMap;
  49 import java.util.concurrent.atomic.AtomicReferenceArray;
  50 import java.util.spi.CalendarDataProvider;
  51 import java.util.spi.CalendarNameProvider;
  52 import java.util.spi.CurrencyNameProvider;
  53 import java.util.spi.LocaleNameProvider;
  54 import sun.util.spi.CalendarProvider;
  55 
  56 /**
  57  * LocaleProviderdapter implementation for the Windows locale data.
  58  *
  59  * @author Naoto Sato
  60  */
  61 public class HostLocaleProviderAdapterImpl {
  62 
  63     // locale categories
  64     private static final int CAT_DISPLAY = 0;
  65     private static final int CAT_FORMAT  = 1;
  66 
  67     // NumberFormat styles
  68     private static final int NF_NUMBER   = 0;
  69     private static final int NF_CURRENCY = 1;
  70     private static final int NF_PERCENT  = 2;
  71     private static final int NF_INTEGER  = 3;
  72     private static final int NF_MAX = NF_INTEGER;
  73 
  74     // CalendarData value types
  75     private static final int CD_FIRSTDAYOFWEEK = 0;
  76     private static final int CD_MINIMALDAYSINFIRSTWEEK = 1;
  77 
  78     // Currency/Locale display name types
  79     private static final int DN_CURRENCY_NAME   = 0;
  80     private static final int DN_CURRENCY_SYMBOL = 1;
  81     private static final int DN_LOCALE_LANGUAGE = 2;
  82     private static final int DN_LOCALE_SCRIPT   = 3;
  83     private static final int DN_LOCALE_REGION   = 4;
  84     private static final int DN_LOCALE_VARIANT  = 5;
  85 
  86     // Native Calendar ID to LDML calendar type map
  87     private static final String[] calIDToLDML = {
  88         "",
  89         "gregory",
  90         "gregory_en-US",
  91         "japanese",
  92         "roc",
  93         "",          // No appropriate type for CAL_KOREA
  94         "islamic",
  95         "buddhist",
  96         "hebrew",
  97         "gregory_fr",
  98         "gregory_ar",
  99         "gregory_en",
 100         "gregory_fr",
 101     };
 102 
 103     // Caches
 104     private static ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> dateFormatCache = new ConcurrentHashMap<>();
 105     private static ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> dateFormatSymbolsCache = new ConcurrentHashMap<>();
 106     private static ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> numberFormatCache = new ConcurrentHashMap<>();
 107     private static ConcurrentMap<Locale, SoftReference<DecimalFormatSymbols>> decimalFormatSymbolsCache = new ConcurrentHashMap<>();
 108 
 109     private static final Set<Locale> supportedLocaleSet;
 110     private static final String nativeDisplayLanguage;
 111     static {
 112         Set<Locale> tmpSet = new HashSet<>();
 113         if (initialize()) {
 114             // Assuming the default locales do not include any extensions, so
 115             // no stripping is needed here.
 116             Control c = Control.getNoFallbackControl(Control.FORMAT_DEFAULT);
 117             String displayLocale = getDefaultLocale(CAT_DISPLAY);
 118             Locale l = Locale.forLanguageTag(displayLocale.replace('_', '-'));
 119             tmpSet.addAll(c.getCandidateLocales("", l));
 120             nativeDisplayLanguage = l.getLanguage();
 121 
 122             String formatLocale = getDefaultLocale(CAT_FORMAT);
 123             if (!formatLocale.equals(displayLocale)) {
 124                 l = Locale.forLanguageTag(formatLocale.replace('_', '-'));
 125                 tmpSet.addAll(c.getCandidateLocales("", l));
 126             }
 127         } else {
 128             nativeDisplayLanguage = "";
 129         }
 130         supportedLocaleSet = Collections.unmodifiableSet(tmpSet);
 131     }
 132     private final static Locale[] supportedLocale = supportedLocaleSet.toArray(new Locale[0]);
 133 
 134     public static DateFormatProvider getDateFormatProvider() {
 135         return new DateFormatProvider() {
 136             @Override
 137             public Locale[] getAvailableLocales() {
 138                 return getSupportedCalendarLocales();
 139             }
 140 
 141             @Override
 142             public boolean isSupportedLocale(Locale locale) {
 143                 return isSupportedCalendarLocale(locale);
 144             }
 145 
 146             @Override
 147             public DateFormat getDateInstance(int style, Locale locale) {
 148                 AtomicReferenceArray<String> patterns = getDateTimePatterns(locale);
 149                 return new SimpleDateFormat(patterns.get(style/2),


 396             public Locale[] getAvailableLocales() {
 397                 return getSupportedCalendarLocales();
 398             }
 399 
 400             @Override
 401             public boolean isSupportedLocale(Locale locale) {
 402                 return isSupportedCalendarLocale(locale);
 403             }
 404 
 405             @Override
 406             public Calendar getInstance(TimeZone zone, Locale locale) {
 407                 return new Calendar.Builder()
 408                              .setLocale(getCalendarLocale(locale))
 409                              .setTimeZone(zone)
 410                              .setInstant(System.currentTimeMillis())
 411                              .build();
 412             }
 413         };
 414     }
 415 
 416     public static CurrencyNameProvider getCurrencyNameProvider() {
 417         return new CurrencyNameProvider() {
 418             @Override
 419             public Locale[] getAvailableLocales() {
 420                 return supportedLocale;
 421             }
 422 
 423             @Override
 424             public boolean isSupportedLocale(Locale locale) {
 425                 // Ignore the extensions for now
 426                 return supportedLocaleSet.contains(locale.stripExtensions()) &&
 427                        locale.getLanguage().equals(nativeDisplayLanguage);
 428             }
 429 
 430             @Override
 431             public String getSymbol(String currencyCode, Locale locale) {
 432                 // Retrieves the currency symbol by calling
 433                 // GetLocaleInfoEx(LOCALE_SCURRENCY).
 434                 // It only works with the "locale"'s currency in its native
 435                 // language.
 436                 try {
 437                     if (Currency.getInstance(locale).getCurrencyCode()
 438                         .equals(currencyCode)) {
 439                         return getDisplayString(locale.toLanguageTag(),
 440                                 DN_CURRENCY_SYMBOL, currencyCode);
 441                     }
 442                 } catch (IllegalArgumentException iae) {}
 443                 return null;
 444             }
 445 
 446             @Override
 447             public String getDisplayName(String currencyCode, Locale locale) {
 448                 // Retrieves the display name by calling
 449                 // GetLocaleInfoEx(LOCALE_SNATIVECURRNAME).
 450                 // It only works with the "locale"'s currency in its native
 451                 // language.
 452                 try {
 453                     if (Currency.getInstance(locale).getCurrencyCode()
 454                         .equals(currencyCode)) {
 455                         return getDisplayString(locale.toLanguageTag(),
 456                                 DN_CURRENCY_NAME, currencyCode);
 457                     }
 458                 } catch (IllegalArgumentException iae) {}
 459                 return null;
 460             }
 461         };
 462     }
 463 
 464     public static LocaleNameProvider getLocaleNameProvider() {
 465         return new LocaleNameProvider() {
 466             @Override
 467             public Locale[] getAvailableLocales() {
 468                 return supportedLocale;
 469             }
 470 
 471             @Override
 472             public boolean isSupportedLocale(Locale locale) {
 473                 return supportedLocaleSet.contains(locale.stripExtensions()) &&
 474                        locale.getLanguage().equals(nativeDisplayLanguage);
 475             }
 476 
 477             @Override
 478             public String getDisplayLanguage(String languageCode, Locale locale) {
 479                 // Retrieves the display language name by calling
 480                 // GetLocaleInfoEx(LOCALE_SLOCALIZEDLANGUAGENAME).
 481                 return getDisplayString(locale.toLanguageTag(),
 482                             DN_LOCALE_LANGUAGE, languageCode);
 483             }
 484 
 485             @Override
 486             public String getDisplayCountry(String countryCode, Locale locale) {
 487                 // Retrieves the display country name by calling
 488                 // GetLocaleInfoEx(LOCALE_SLOCALIZEDCOUNTRYNAME).
 489                 return getDisplayString(locale.toLanguageTag(),
 490                             DN_LOCALE_REGION, nativeDisplayLanguage+"-"+countryCode);
 491             }
 492 
 493             @Override
 494             public String getDisplayScript(String scriptCode, Locale locale) {
 495                 return null;
 496             }
 497 
 498             @Override
 499             public String getDisplayVariant(String variantCode, Locale locale) {
 500                 return null;
 501             }
 502         };
 503     }
 504 
 505 
 506     private static String convertDateTimePattern(String winPattern) {
 507         String ret = winPattern.replaceAll("dddd", "EEEE");
 508         ret = ret.replaceAll("ddd", "EEE");
 509         ret = ret.replaceAll("tt", "aa");
 510         ret = ret.replaceAll("g", "GG");
 511         return ret;
 512     }
 513 
 514     private static Locale[] getSupportedCalendarLocales() {
 515         if (supportedLocale.length != 0 &&
 516             supportedLocaleSet.contains(Locale.JAPAN) &&
 517             isJapaneseCalendar()) {
 518             Locale[] sup = new Locale[supportedLocale.length+1];
 519             sup[0] = JRELocaleConstants.JA_JP_JP;
 520             System.arraycopy(supportedLocale, 0, sup, 1, supportedLocale.length);
 521             return sup;
 522         }
 523         return supportedLocale;
 524     }
 525 
 526     private static boolean isSupportedCalendarLocale(Locale locale) {
 527         Locale base = locale;
 528 
 529         if (base.hasExtensions() || base.getVariant() != "") {
 530             // strip off extensions and variant.
 531             base = new Locale.Builder()
 532                             .setLocale(locale)
 533                             .clearExtensions()
 534                             .build();
 535         }
 536 
 537         if (!supportedLocaleSet.contains(base)) {
 538             return false;
 539         }
 540 
 541         int calid = getCalendarID(base.toLanguageTag());
 542         if (calid <= 0 || calid >= calIDToLDML.length) {
 543             return false;
 544         }
 545 
 546         String requestedCalType = locale.getUnicodeLocaleType("ca");
 547         String nativeCalType = calIDToLDML[calid]
 548                 .replaceFirst("_.*", ""); // remove locale part.
 549 
 550         if (requestedCalType == null) {
 551             return Calendar.getAvailableCalendarTypes().contains(nativeCalType);
 552         } else {
 553             return requestedCalType.equals(nativeCalType);
 554         }
 555     }
 556 
 557     private static Locale[] getSupportedNativeDigitLocales() {
 558         if (supportedLocale.length != 0 &&
 559             supportedLocaleSet.contains(JRELocaleConstants.TH_TH) &&
 560             isNativeDigit("th-TH")) {
 561             Locale[] sup = new Locale[supportedLocale.length+1];


 649 
 650     // For NumberFormatProvider
 651     private static native String getNumberPattern(int numberStyle, String langTag);
 652     private static native boolean isNativeDigit(String langTag);
 653 
 654     // For DecimalFormatSymbolsProvider
 655     private static native String getCurrencySymbol(String langTag, String currencySymbol);
 656     private static native char getDecimalSeparator(String langTag, char decimalSeparator);
 657     private static native char getGroupingSeparator(String langTag, char groupingSeparator);
 658     private static native String getInfinity(String langTag, String infinity);
 659     private static native String getInternationalCurrencySymbol(String langTag, String internationalCurrencySymbol);
 660     private static native char getMinusSign(String langTag, char minusSign);
 661     private static native char getMonetaryDecimalSeparator(String langTag, char monetaryDecimalSeparator);
 662     private static native String getNaN(String langTag, String nan);
 663     private static native char getPercent(String langTag, char percent);
 664     private static native char getPerMill(String langTag, char perMill);
 665     private static native char getZeroDigit(String langTag, char zeroDigit);
 666 
 667     // For CalendarDataProvider
 668     private static native int getCalendarDataValue(String langTag, int type);
 669 
 670     // For Locale/CurrencyNameProvider
 671     private static native String getDisplayString(String langTag, int key, String value);
 672 }