Print this page
rev 5615 : 6336885: RFE: Locale Data Deployment Enhancements
4609153: Provide locale data for Indic locales
5104387: Support for gl_ES locale (galician language)
6337471: desktop/system locale preferences support
7056139: (cal) SPI support for locale-dependent Calendar parameters
7058206: Provide CalendarData SPI for week params and display field value names
7073852: Support multiple scripts for digits and decimal symbols per locale
7079560: [Fmt-Da] Context dependent month names support in SimpleDateFormat
7171324: getAvailableLocales() of locale sensitive services should return the actual availability of locales
7151414: (cal) Support calendar type identification
7168528: LocaleServiceProvider needs to be aware of Locale extensions
7171372: (cal) locale's default Calendar should be created if unknown calendar is specified
Summary: JEP 127: Improve Locale Data Packaging and Adopt Unicode CLDR Data (part 1 w/o Jigsaw. by Naoto Sato and Masayoshi Okutsu)

Split Close
Expand all
Collapse all
          --- old/src/share/classes/java/util/Currency.java
          +++ new/src/share/classes/java/util/Currency.java
↓ open down ↓ 28 lines elided ↑ open up ↑
  29   29  import java.io.DataInputStream;
  30   30  import java.io.File;
  31   31  import java.io.FileInputStream;
  32   32  import java.io.FileReader;
  33   33  import java.io.IOException;
  34   34  import java.io.Serializable;
  35   35  import java.security.AccessController;
  36   36  import java.security.PrivilegedAction;
  37   37  import java.util.concurrent.ConcurrentHashMap;
  38   38  import java.util.concurrent.ConcurrentMap;
  39      -import java.util.logging.Level;
  40   39  import java.util.regex.Pattern;
  41   40  import java.util.regex.Matcher;
  42   41  import java.util.spi.CurrencyNameProvider;
  43      -import java.util.spi.LocaleServiceProvider;
  44      -import sun.util.LocaleServiceProviderPool;
       42 +import sun.util.locale.provider.LocaleServiceProviderPool;
  45   43  import sun.util.logging.PlatformLogger;
  46      -import sun.util.resources.LocaleData;
  47      -import sun.util.resources.OpenListResourceBundle;
  48   44  
  49   45  
  50   46  /**
  51   47   * Represents a currency. Currencies are identified by their ISO 4217 currency
  52   48   * codes. Visit the <a href="http://www.iso.org/iso/en/prods-services/popstds/currencycodes.html">
  53   49   * ISO web site</a> for more information, including a table of
  54   50   * currency codes.
  55   51   * <p>
  56   52   * The class is designed so that there's never more than one
  57   53   * <code>Currency</code> instance for any given currency. Therefore, there's
↓ open down ↓ 126 lines elided ↑ open up ↑
 184  180      private static final int COUNTRY_TYPE_MASK = SIMPLE_CASE_COUNTRY_MASK | SPECIAL_CASE_COUNTRY_MASK;
 185  181      // mask for the numeric code of the currency
 186  182      private static final int NUMERIC_CODE_MASK = 0x0003FF00;
 187  183      // shift count for the numeric code of the currency
 188  184      private static final int NUMERIC_CODE_SHIFT = 8;
 189  185  
 190  186      // Currency data format version
 191  187      private static final int VALID_FORMAT_VERSION = 1;
 192  188  
 193  189      static {
 194      -        AccessController.doPrivileged(new PrivilegedAction<Object>() {
 195      -            public Object run() {
      190 +        AccessController.doPrivileged(new PrivilegedAction<Void>() {
      191 +            @Override
      192 +            public Void run() {
 196  193                  String homeDir = System.getProperty("java.home");
 197  194                  try {
 198  195                      String dataFile = homeDir + File.separator +
 199  196                              "lib" + File.separator + "currency.data";
 200      -                    DataInputStream dis = new DataInputStream(
 201      -                        new BufferedInputStream(
 202      -                        new FileInputStream(dataFile)));
 203      -                    if (dis.readInt() != MAGIC_NUMBER) {
 204      -                        throw new InternalError("Currency data is possibly corrupted");
      197 +                    try (DataInputStream dis = new DataInputStream(
      198 +                             new BufferedInputStream(
      199 +                             new FileInputStream(dataFile)))) {
      200 +                        if (dis.readInt() != MAGIC_NUMBER) {
      201 +                            throw new InternalError("Currency data is possibly corrupted");
      202 +                        }
      203 +                        formatVersion = dis.readInt();
      204 +                        if (formatVersion != VALID_FORMAT_VERSION) {
      205 +                            throw new InternalError("Currency data format is incorrect");
      206 +                        }
      207 +                        dataVersion = dis.readInt();
      208 +                        mainTable = readIntArray(dis, A_TO_Z * A_TO_Z);
      209 +                        int scCount = dis.readInt();
      210 +                        scCutOverTimes = readLongArray(dis, scCount);
      211 +                        scOldCurrencies = readStringArray(dis, scCount);
      212 +                        scNewCurrencies = readStringArray(dis, scCount);
      213 +                        scOldCurrenciesDFD = readIntArray(dis, scCount);
      214 +                        scNewCurrenciesDFD = readIntArray(dis, scCount);
      215 +                        scOldCurrenciesNumericCode = readIntArray(dis, scCount);
      216 +                        scNewCurrenciesNumericCode = readIntArray(dis, scCount);
      217 +                        int ocCount = dis.readInt();
      218 +                        otherCurrencies = dis.readUTF();
      219 +                        otherCurrenciesDFD = readIntArray(dis, ocCount);
      220 +                        otherCurrenciesNumericCode = readIntArray(dis, ocCount);
 205  221                      }
 206      -                    formatVersion = dis.readInt();
 207      -                    if (formatVersion != VALID_FORMAT_VERSION) {
 208      -                        throw new InternalError("Currency data format is incorrect");
 209      -                    }
 210      -                    dataVersion = dis.readInt();
 211      -                    mainTable = readIntArray(dis, A_TO_Z * A_TO_Z);
 212      -                    int scCount = dis.readInt();
 213      -                    scCutOverTimes = readLongArray(dis, scCount);
 214      -                    scOldCurrencies = readStringArray(dis, scCount);
 215      -                    scNewCurrencies = readStringArray(dis, scCount);
 216      -                    scOldCurrenciesDFD = readIntArray(dis, scCount);
 217      -                    scNewCurrenciesDFD = readIntArray(dis, scCount);
 218      -                    scOldCurrenciesNumericCode = readIntArray(dis, scCount);
 219      -                    scNewCurrenciesNumericCode = readIntArray(dis, scCount);
 220      -                    int ocCount = dis.readInt();
 221      -                    otherCurrencies = dis.readUTF();
 222      -                    otherCurrenciesDFD = readIntArray(dis, ocCount);
 223      -                    otherCurrenciesNumericCode = readIntArray(dis, ocCount);
 224      -                    dis.close();
 225  222                  } catch (IOException e) {
 226  223                      throw new InternalError(e);
 227  224                  }
 228  225  
 229  226                  // look for the properties file for overrides
 230  227                  try {
 231  228                      File propFile = new File(homeDir + File.separator +
 232  229                                               "lib" + File.separator +
 233  230                                               "currency.properties");
 234  231                      if (propFile.exists()) {
↓ open down ↓ 102 lines elided ↑ open up ↑
 337  334       * European Monetary Union, the method returns the old national currencies
 338  335       * until December 31, 2001, and the Euro from January 1, 2002, local time
 339  336       * of the respective countries.
 340  337       * <p>
 341  338       * The method returns <code>null</code> for territories that don't
 342  339       * have a currency, such as Antarctica.
 343  340       *
 344  341       * @param locale the locale for whose country a <code>Currency</code>
 345  342       * instance is needed
 346  343       * @return the <code>Currency</code> instance for the country of the given
 347      -     * locale, or null
      344 +     * locale, or {@code null}
 348  345       * @exception NullPointerException if <code>locale</code> or its country
 349      -     * code is null
 350      -     * @exception IllegalArgumentException if the country of the given locale
      346 +     * code is {@code null}
      347 +     * @exception IllegalArgumentException if the country of the given {@code locale}
 351  348       * is not a supported ISO 3166 country code.
 352  349       */
 353  350      public static Currency getInstance(Locale locale) {
 354  351          String country = locale.getCountry();
 355  352          if (country == null) {
 356  353              throw new NullPointerException();
 357  354          }
 358  355  
 359  356          if (country.length() != 2) {
 360  357              throw new IllegalArgumentException();
 361  358          }
 362  359  
 363  360          char char1 = country.charAt(0);
 364  361          char char2 = country.charAt(1);
 365  362          int tableEntry = getMainTableEntry(char1, char2);
 366  363          if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
 367  364                      && tableEntry != INVALID_COUNTRY_ENTRY) {
 368  365              char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
 369  366              int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
 370  367              int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
 371      -            StringBuffer sb = new StringBuffer(country);
      368 +            StringBuilder sb = new StringBuilder(country);
 372  369              sb.append(finalChar);
 373  370              return getInstance(sb.toString(), defaultFractionDigits, numericCode);
 374  371          } else {
 375  372              // special cases
 376  373              if (tableEntry == INVALID_COUNTRY_ENTRY) {
 377  374                  throw new IllegalArgumentException();
 378  375              }
 379  376              if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) {
 380  377                  return null;
 381  378              } else {
↓ open down ↓ 81 lines elided ↑ open up ↑
 463  460       * For example, for the US Dollar, the symbol is "$" if the specified
 464  461       * locale is the US, while for other locales it may be "US$". If no
 465  462       * symbol can be determined, the ISO 4217 currency code is returned.
 466  463       *
 467  464       * @param locale the locale for which a display name for this currency is
 468  465       * needed
 469  466       * @return the symbol of this currency for the specified locale
 470  467       * @exception NullPointerException if <code>locale</code> is null
 471  468       */
 472  469      public String getSymbol(Locale locale) {
 473      -        try {
 474      -            // Check whether a provider can provide an implementation that's closer
 475      -            // to the requested locale than what the Java runtime itself can provide.
 476      -            LocaleServiceProviderPool pool =
 477      -                LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
 478      -
 479      -            if (pool.hasProviders()) {
 480      -                // Assuming that all the country locales include necessary currency
 481      -                // symbols in the Java runtime's resources,  so there is no need to
 482      -                // examine whether Java runtime's currency resource bundle is missing
 483      -                // names.  Therefore, no resource bundle is provided for calling this
 484      -                // method.
 485      -                String symbol = pool.getLocalizedObject(
 486      -                                    CurrencyNameGetter.INSTANCE,
 487      -                                    locale, (OpenListResourceBundle)null,
 488      -                                    currencyCode, SYMBOL);
 489      -                if (symbol != null) {
 490      -                    return symbol;
 491      -                }
 492      -            }
 493      -
 494      -            ResourceBundle bundle = LocaleData.getCurrencyNames(locale);
 495      -            return bundle.getString(currencyCode);
 496      -        } catch (MissingResourceException e) {
 497      -            // use currency code as symbol of last resort
 498      -            return currencyCode;
      470 +        LocaleServiceProviderPool pool =
      471 +            LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
      472 +        String symbol = pool.getLocalizedObject(
      473 +                                CurrencyNameGetter.INSTANCE,
      474 +                                locale, currencyCode, SYMBOL);
      475 +        if (symbol != null) {
      476 +            return symbol;
 499  477          }
      478 +
      479 +        // use currency code as symbol of last resort
      480 +        return currencyCode;
 500  481      }
 501  482  
 502  483      /**
 503  484       * Gets the default number of fraction digits used with this currency.
 504  485       * For example, the default number of fraction digits for the Euro is 2,
 505  486       * while for the Japanese Yen it's 0.
 506  487       * In the case of pseudo-currencies, such as IMF Special Drawing Rights,
 507  488       * -1 is returned.
 508  489       *
 509  490       * @return the default number of fraction digits used with this currency
↓ open down ↓ 29 lines elided ↑ open up ↑
 539  520       * the specified locale.  If there is no suitable display name found
 540  521       * for the specified locale, the ISO 4217 currency code is returned.
 541  522       *
 542  523       * @param locale the locale for which a display name for this currency is
 543  524       * needed
 544  525       * @return the display name of this currency for the specified locale
 545  526       * @exception NullPointerException if <code>locale</code> is null
 546  527       * @since 1.7
 547  528       */
 548  529      public String getDisplayName(Locale locale) {
 549      -        try {
 550      -            OpenListResourceBundle bundle = LocaleData.getCurrencyNames(locale);
 551      -            String result = null;
 552      -            String bundleKey = currencyCode.toLowerCase(Locale.ROOT);
 553      -
 554      -            // Check whether a provider can provide an implementation that's closer
 555      -            // to the requested locale than what the Java runtime itself can provide.
 556      -            LocaleServiceProviderPool pool =
 557      -                LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
 558      -            if (pool.hasProviders()) {
 559      -                result = pool.getLocalizedObject(
 560      -                                    CurrencyNameGetter.INSTANCE,
 561      -                                    locale, bundleKey, bundle, currencyCode, DISPLAYNAME);
 562      -            }
 563      -
 564      -            if (result == null) {
 565      -                result = bundle.getString(bundleKey);
 566      -            }
 567      -
 568      -            if (result != null) {
 569      -                return result;
 570      -            }
 571      -        } catch (MissingResourceException e) {
 572      -            // fall through
      530 +        LocaleServiceProviderPool pool =
      531 +            LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
      532 +        String result = pool.getLocalizedObject(
      533 +                                CurrencyNameGetter.INSTANCE,
      534 +                                locale, currencyCode, DISPLAYNAME);
      535 +        if (result != null) {
      536 +            return result;
 573  537          }
 574  538  
 575  539          // use currency code as symbol of last resort
 576  540          return currencyCode;
 577  541      }
 578  542  
 579  543      /**
 580  544       * Returns the ISO 4217 currency code of this currency.
 581  545       *
 582  546       * @return the ISO 4217 currency code of this currency
 583  547       */
      548 +    @Override
 584  549      public String toString() {
 585  550          return currencyCode;
 586  551      }
 587  552  
 588  553      /**
 589  554       * Resolves instances being deserialized to a single instance per currency.
 590  555       */
 591  556      private Object readResolve() {
 592  557          return getInstance(currencyCode);
 593  558      }
↓ open down ↓ 22 lines elided ↑ open up ↑
 616  581  
 617  582      /**
 618  583       * Obtains a localized currency names from a CurrencyNameProvider
 619  584       * implementation.
 620  585       */
 621  586      private static class CurrencyNameGetter
 622  587          implements LocaleServiceProviderPool.LocalizedObjectGetter<CurrencyNameProvider,
 623  588                                                                     String> {
 624  589          private static final CurrencyNameGetter INSTANCE = new CurrencyNameGetter();
 625  590  
      591 +        @Override
 626  592          public String getObject(CurrencyNameProvider currencyNameProvider,
 627  593                                  Locale locale,
 628  594                                  String key,
 629  595                                  Object... params) {
 630  596              assert params.length == 1;
 631  597              int type = (Integer)params[0];
 632  598  
 633  599              switch(type) {
 634  600              case SYMBOL:
 635  601                  return currencyNameProvider.getSymbol(key, locale);
↓ open down ↓ 107 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX