Home » openjdk-7 » java » util » [javadoc | source]

    1   /*
    2    * Copyright (c) 2000, 2011, 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 java.util;
   27   
   28   import java.io.BufferedInputStream;
   29   import java.io.DataInputStream;
   30   import java.io.File;
   31   import java.io.FileInputStream;
   32   import java.io.FileReader;
   33   import java.io.IOException;
   34   import java.io.Serializable;
   35   import java.security.AccessController;
   36   import java.security.PrivilegedAction;
   37   import java.util.logging.Level;
   38   import java.util.regex.Pattern;
   39   import java.util.regex.Matcher;
   40   import java.util.spi.CurrencyNameProvider;
   41   import java.util.spi.LocaleServiceProvider;
   42   import sun.util.LocaleServiceProviderPool;
   43   import sun.util.logging.PlatformLogger;
   44   import sun.util.resources.LocaleData;
   45   import sun.util.resources.OpenListResourceBundle;
   46   
   47   
   48   /**
   49    * Represents a currency. Currencies are identified by their ISO 4217 currency
   50    * codes. Visit the <a href="http://www.iso.org/iso/en/prods-services/popstds/currencycodes.html">
   51    * ISO web site</a> for more information, including a table of
   52    * currency codes.
   53    * <p>
   54    * The class is designed so that there's never more than one
   55    * <code>Currency</code> instance for any given currency. Therefore, there's
   56    * no public constructor. You obtain a <code>Currency</code> instance using
   57    * the <code>getInstance</code> methods.
   58    * <p>
   59    * Users can supersede the Java runtime currency data by creating a properties
   60    * file named <code>&lt;JAVA_HOME&gt;/lib/currency.properties</code>.  The contents
   61    * of the properties file are key/value pairs of the ISO 3166 country codes
   62    * and the ISO 4217 currency data respectively.  The value part consists of
   63    * three ISO 4217 values of a currency, i.e., an alphabetic code, a numeric
   64    * code, and a minor unit.  Those three ISO 4217 values are separated by commas.
   65    * The lines which start with '#'s are considered comment lines.  For example,
   66    * <p>
   67    * <code>
   68    * #Sample currency properties<br>
   69    * JP=JPZ,999,0
   70    * </code>
   71    * <p>
   72    * will supersede the currency data for Japan.
   73    *
   74    * @since 1.4
   75    */
   76   public final class Currency implements Serializable {
   77   
   78       private static final long serialVersionUID = -158308464356906721L;
   79   
   80       /**
   81        * ISO 4217 currency code for this currency.
   82        *
   83        * @serial
   84        */
   85       private final String currencyCode;
   86   
   87       /**
   88        * Default fraction digits for this currency.
   89        * Set from currency data tables.
   90        */
   91       transient private final int defaultFractionDigits;
   92   
   93       /**
   94        * ISO 4217 numeric code for this currency.
   95        * Set from currency data tables.
   96        */
   97       transient private final int numericCode;
   98   
   99   
  100       // class data: instance map
  101   
  102       private static HashMap<String, Currency> instances = new HashMap<String, Currency>(7);
  103       private static HashSet<Currency> available;
  104   
  105   
  106       // Class data: currency data obtained from currency.data file.
  107       // Purpose:
  108       // - determine valid country codes
  109       // - determine valid currency codes
  110       // - map country codes to currency codes
  111       // - obtain default fraction digits for currency codes
  112       //
  113       // sc = special case; dfd = default fraction digits
  114       // Simple countries are those where the country code is a prefix of the
  115       // currency code, and there are no known plans to change the currency.
  116       //
  117       // table formats:
  118       // - mainTable:
  119       //   - maps country code to 32-bit int
  120       //   - 26*26 entries, corresponding to [A-Z]*[A-Z]
  121       //   - \u007F -> not valid country
  122       //   - bits 18-31: unused
  123       //   - bits 8-17: numeric code (0 to 1023)
  124       //   - bit 7: 1 - special case, bits 0-4 indicate which one
  125       //            0 - simple country, bits 0-4 indicate final char of currency code
  126       //   - bits 5-6: fraction digits for simple countries, 0 for special cases
  127       //   - bits 0-4: final char for currency code for simple country, or ID of special case
  128       // - special case IDs:
  129       //   - 0: country has no currency
  130       //   - other: index into sc* arrays + 1
  131       // - scCutOverTimes: cut-over time in millis as returned by
  132       //   System.currentTimeMillis for special case countries that are changing
  133       //   currencies; Long.MAX_VALUE for countries that are not changing currencies
  134       // - scOldCurrencies: old currencies for special case countries
  135       // - scNewCurrencies: new currencies for special case countries that are
  136       //   changing currencies; null for others
  137       // - scOldCurrenciesDFD: default fraction digits for old currencies
  138       // - scNewCurrenciesDFD: default fraction digits for new currencies, 0 for
  139       //   countries that are not changing currencies
  140       // - otherCurrencies: concatenation of all currency codes that are not the
  141       //   main currency of a simple country, separated by "-"
  142       // - otherCurrenciesDFD: decimal format digits for currencies in otherCurrencies, same order
  143   
  144       static int formatVersion;
  145       static int dataVersion;
  146       static int[] mainTable;
  147       static long[] scCutOverTimes;
  148       static String[] scOldCurrencies;
  149       static String[] scNewCurrencies;
  150       static int[] scOldCurrenciesDFD;
  151       static int[] scNewCurrenciesDFD;
  152       static int[] scOldCurrenciesNumericCode;
  153       static int[] scNewCurrenciesNumericCode;
  154       static String otherCurrencies;
  155       static int[] otherCurrenciesDFD;
  156       static int[] otherCurrenciesNumericCode;
  157   
  158       // handy constants - must match definitions in GenerateCurrencyData
  159       // magic number
  160       private static final int MAGIC_NUMBER = 0x43757244;
  161       // number of characters from A to Z
  162       private static final int A_TO_Z = ('Z' - 'A') + 1;
  163       // entry for invalid country codes
  164       private static final int INVALID_COUNTRY_ENTRY = 0x007F;
  165       // entry for countries without currency
  166       private static final int COUNTRY_WITHOUT_CURRENCY_ENTRY = 0x0080;
  167       // mask for simple case country entries
  168       private static final int SIMPLE_CASE_COUNTRY_MASK = 0x0000;
  169       // mask for simple case country entry final character
  170       private static final int SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK = 0x001F;
  171       // mask for simple case country entry default currency digits
  172       private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK = 0x0060;
  173       // shift count for simple case country entry default currency digits
  174       private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT = 5;
  175       // mask for special case country entries
  176       private static final int SPECIAL_CASE_COUNTRY_MASK = 0x0080;
  177       // mask for special case country index
  178       private static final int SPECIAL_CASE_COUNTRY_INDEX_MASK = 0x001F;
  179       // delta from entry index component in main table to index into special case tables
  180       private static final int SPECIAL_CASE_COUNTRY_INDEX_DELTA = 1;
  181       // mask for distinguishing simple and special case countries
  182       private static final int COUNTRY_TYPE_MASK = SIMPLE_CASE_COUNTRY_MASK | SPECIAL_CASE_COUNTRY_MASK;
  183       // mask for the numeric code of the currency
  184       private static final int NUMERIC_CODE_MASK = 0x0003FF00;
  185       // shift count for the numeric code of the currency
  186       private static final int NUMERIC_CODE_SHIFT = 8;
  187   
  188       // Currency data format version
  189       private static final int VALID_FORMAT_VERSION = 1;
  190   
  191       static {
  192           AccessController.doPrivileged(new PrivilegedAction() {
  193               public Object run() {
  194                   String homeDir = System.getProperty("java.home");
  195                   try {
  196                       String dataFile = homeDir + File.separator +
  197                               "lib" + File.separator + "currency.data";
  198                       DataInputStream dis = new DataInputStream(
  199                           new BufferedInputStream(
  200                           new FileInputStream(dataFile)));
  201                       if (dis.readInt() != MAGIC_NUMBER) {
  202                           throw new InternalError("Currency data is possibly corrupted");
  203                       }
  204                       formatVersion = dis.readInt();
  205                       if (formatVersion != VALID_FORMAT_VERSION) {
  206                           throw new InternalError("Currency data format is incorrect");
  207                       }
  208                       dataVersion = dis.readInt();
  209                       mainTable = readIntArray(dis, A_TO_Z * A_TO_Z);
  210                       int scCount = dis.readInt();
  211                       scCutOverTimes = readLongArray(dis, scCount);
  212                       scOldCurrencies = readStringArray(dis, scCount);
  213                       scNewCurrencies = readStringArray(dis, scCount);
  214                       scOldCurrenciesDFD = readIntArray(dis, scCount);
  215                       scNewCurrenciesDFD = readIntArray(dis, scCount);
  216                       scOldCurrenciesNumericCode = readIntArray(dis, scCount);
  217                       scNewCurrenciesNumericCode = readIntArray(dis, scCount);
  218                       int ocCount = dis.readInt();
  219                       otherCurrencies = dis.readUTF();
  220                       otherCurrenciesDFD = readIntArray(dis, ocCount);
  221                       otherCurrenciesNumericCode = readIntArray(dis, ocCount);
  222                       dis.close();
  223                   } catch (IOException e) {
  224                       InternalError ie = new InternalError();
  225                       ie.initCause(e);
  226                       throw ie;
  227                   }
  228   
  229                   // look for the properties file for overrides
  230                   try {
  231                       File propFile = new File(homeDir + File.separator +
  232                                                "lib" + File.separator +
  233                                                "currency.properties");
  234                       if (propFile.exists()) {
  235                           Properties props = new Properties();
  236                           try (FileReader fr = new FileReader(propFile)) {
  237                               props.load(fr);
  238                           }
  239                           Set<String> keys = props.stringPropertyNames();
  240                           Pattern propertiesPattern =
  241                               Pattern.compile("([A-Z]{3})\\s*,\\s*(\\d{3})\\s*,\\s*([0-3])");
  242                           for (String key : keys) {
  243                              replaceCurrencyData(propertiesPattern,
  244                                  key.toUpperCase(Locale.ROOT),
  245                                  props.getProperty(key).toUpperCase(Locale.ROOT));
  246                           }
  247                       }
  248                   } catch (IOException e) {
  249                       info("currency.properties is ignored because of an IOException", e);
  250                   }
  251                   return null;
  252               }
  253           });
  254       }
  255   
  256       /**
  257        * Constants for retrieving localized names from the name providers.
  258        */
  259       private static final int SYMBOL = 0;
  260       private static final int DISPLAYNAME = 1;
  261   
  262   
  263       /**
  264        * Constructs a <code>Currency</code> instance. The constructor is private
  265        * so that we can insure that there's never more than one instance for a
  266        * given currency.
  267        */
  268       private Currency(String currencyCode, int defaultFractionDigits, int numericCode) {
  269           this.currencyCode = currencyCode;
  270           this.defaultFractionDigits = defaultFractionDigits;
  271           this.numericCode = numericCode;
  272       }
  273   
  274       /**
  275        * Returns the <code>Currency</code> instance for the given currency code.
  276        *
  277        * @param currencyCode the ISO 4217 code of the currency
  278        * @return the <code>Currency</code> instance for the given currency code
  279        * @exception NullPointerException if <code>currencyCode</code> is null
  280        * @exception IllegalArgumentException if <code>currencyCode</code> is not
  281        * a supported ISO 4217 code.
  282        */
  283       public static Currency getInstance(String currencyCode) {
  284           return getInstance(currencyCode, Integer.MIN_VALUE, 0);
  285       }
  286   
  287       private static Currency getInstance(String currencyCode, int defaultFractionDigits,
  288           int numericCode) {
  289           synchronized (instances) {
  290               // Try to look up the currency code in the instances table.
  291               // This does the null pointer check as a side effect.
  292               // Also, if there already is an entry, the currencyCode must be valid.
  293               Currency instance = instances.get(currencyCode);
  294               if (instance != null) {
  295                   return instance;
  296               }
  297   
  298               if (defaultFractionDigits == Integer.MIN_VALUE) {
  299                   // Currency code not internally generated, need to verify first
  300                   // A currency code must have 3 characters and exist in the main table
  301                   // or in the list of other currencies.
  302                   if (currencyCode.length() != 3) {
  303                       throw new IllegalArgumentException();
  304                   }
  305                   char char1 = currencyCode.charAt(0);
  306                   char char2 = currencyCode.charAt(1);
  307                   int tableEntry = getMainTableEntry(char1, char2);
  308                   if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
  309                           && tableEntry != INVALID_COUNTRY_ENTRY
  310                           && currencyCode.charAt(2) - 'A' == (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK)) {
  311                       defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
  312                       numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
  313                   } else {
  314                       // Check for '-' separately so we don't get false hits in the table.
  315                       if (currencyCode.charAt(2) == '-') {
  316                           throw new IllegalArgumentException();
  317                       }
  318                       int index = otherCurrencies.indexOf(currencyCode);
  319                       if (index == -1) {
  320                           throw new IllegalArgumentException();
  321                       }
  322                       defaultFractionDigits = otherCurrenciesDFD[index / 4];
  323                       numericCode = otherCurrenciesNumericCode[index / 4];
  324                   }
  325               }
  326   
  327               instance = new Currency(currencyCode, defaultFractionDigits, numericCode);
  328               instances.put(currencyCode, instance);
  329               return instance;
  330           }
  331       }
  332   
  333       /**
  334        * Returns the <code>Currency</code> instance for the country of the
  335        * given locale. The language and variant components of the locale
  336        * are ignored. The result may vary over time, as countries change their
  337        * currencies. For example, for the original member countries of the
  338        * European Monetary Union, the method returns the old national currencies
  339        * until December 31, 2001, and the Euro from January 1, 2002, local time
  340        * of the respective countries.
  341        * <p>
  342        * The method returns <code>null</code> for territories that don't
  343        * have a currency, such as Antarctica.
  344        *
  345        * @param locale the locale for whose country a <code>Currency</code>
  346        * instance is needed
  347        * @return the <code>Currency</code> instance for the country of the given
  348        * locale, or null
  349        * @exception NullPointerException if <code>locale</code> or its country
  350        * code is null
  351        * @exception IllegalArgumentException if the country of the given locale
  352        * is not a supported ISO 3166 country code.
  353        */
  354       public static Currency getInstance(Locale locale) {
  355           String country = locale.getCountry();
  356           if (country == null) {
  357               throw new NullPointerException();
  358           }
  359   
  360           if (country.length() != 2) {
  361               throw new IllegalArgumentException();
  362           }
  363   
  364           char char1 = country.charAt(0);
  365           char char2 = country.charAt(1);
  366           int tableEntry = getMainTableEntry(char1, char2);
  367           if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
  368                       && tableEntry != INVALID_COUNTRY_ENTRY) {
  369               char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
  370               int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
  371               int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
  372               StringBuffer sb = new StringBuffer(country);
  373               sb.append(finalChar);
  374               return getInstance(sb.toString(), defaultFractionDigits, numericCode);
  375           } else {
  376               // special cases
  377               if (tableEntry == INVALID_COUNTRY_ENTRY) {
  378                   throw new IllegalArgumentException();
  379               }
  380               if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) {
  381                   return null;
  382               } else {
  383                   int index = (tableEntry & SPECIAL_CASE_COUNTRY_INDEX_MASK) - SPECIAL_CASE_COUNTRY_INDEX_DELTA;
  384                   if (scCutOverTimes[index] == Long.MAX_VALUE || System.currentTimeMillis() < scCutOverTimes[index]) {
  385                       return getInstance(scOldCurrencies[index], scOldCurrenciesDFD[index],
  386                           scOldCurrenciesNumericCode[index]);
  387                   } else {
  388                       return getInstance(scNewCurrencies[index], scNewCurrenciesDFD[index],
  389                           scNewCurrenciesNumericCode[index]);
  390                   }
  391               }
  392           }
  393       }
  394   
  395       /**
  396        * Gets the set of available currencies.  The returned set of currencies
  397        * contains all of the available currencies, which may include currencies
  398        * that represent obsolete ISO 4217 codes.  The set can be modified
  399        * without affecting the available currencies in the runtime.
  400        *
  401        * @return the set of available currencies.  If there is no currency
  402        *    available in the runtime, the returned set is empty.
  403        * @since 1.7
  404        */
  405       public static Set<Currency> getAvailableCurrencies() {
  406           synchronized(Currency.class) {
  407               if (available == null) {
  408                   available = new HashSet<Currency>(256);
  409   
  410                   // Add simple currencies first
  411                   for (char c1 = 'A'; c1 <= 'Z'; c1 ++) {
  412                       for (char c2 = 'A'; c2 <= 'Z'; c2 ++) {
  413                           int tableEntry = getMainTableEntry(c1, c2);
  414                           if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
  415                                && tableEntry != INVALID_COUNTRY_ENTRY) {
  416                               char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
  417                               int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
  418                               int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
  419                               StringBuilder sb = new StringBuilder();
  420                               sb.append(c1);
  421                               sb.append(c2);
  422                               sb.append(finalChar);
  423                               available.add(getInstance(sb.toString(), defaultFractionDigits, numericCode));
  424                           }
  425                       }
  426                   }
  427   
  428                   // Now add other currencies
  429                   StringTokenizer st = new StringTokenizer(otherCurrencies, "-");
  430                   while (st.hasMoreElements()) {
  431                       available.add(getInstance((String)st.nextElement()));
  432                   }
  433               }
  434           }
  435   
  436           return (Set<Currency>) available.clone();
  437       }
  438   
  439       /**
  440        * Gets the ISO 4217 currency code of this currency.
  441        *
  442        * @return the ISO 4217 currency code of this currency.
  443        */
  444       public String getCurrencyCode() {
  445           return currencyCode;
  446       }
  447   
  448       /**
  449        * Gets the symbol of this currency for the default locale.
  450        * For example, for the US Dollar, the symbol is "$" if the default
  451        * locale is the US, while for other locales it may be "US$". If no
  452        * symbol can be determined, the ISO 4217 currency code is returned.
  453        *
  454        * @return the symbol of this currency for the default locale
  455        */
  456       public String getSymbol() {
  457           return getSymbol(Locale.getDefault(Locale.Category.DISPLAY));
  458       }
  459   
  460       /**
  461        * Gets the symbol of this currency for the specified locale.
  462        * For example, for the US Dollar, the symbol is "$" if the specified
  463        * locale is the US, while for other locales it may be "US$". If no
  464        * symbol can be determined, the ISO 4217 currency code is returned.
  465        *
  466        * @param locale the locale for which a display name for this currency is
  467        * needed
  468        * @return the symbol of this currency for the specified locale
  469        * @exception NullPointerException if <code>locale</code> is null
  470        */
  471       public String getSymbol(Locale locale) {
  472           try {
  473               // Check whether a provider can provide an implementation that's closer
  474               // to the requested locale than what the Java runtime itself can provide.
  475               LocaleServiceProviderPool pool =
  476                   LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
  477   
  478               if (pool.hasProviders()) {
  479                   // Assuming that all the country locales include necessary currency
  480                   // symbols in the Java runtime's resources,  so there is no need to
  481                   // examine whether Java runtime's currency resource bundle is missing
  482                   // names.  Therefore, no resource bundle is provided for calling this
  483                   // method.
  484                   String symbol = pool.getLocalizedObject(
  485                                       CurrencyNameGetter.INSTANCE,
  486                                       locale, (OpenListResourceBundle)null,
  487                                       currencyCode, SYMBOL);
  488                   if (symbol != null) {
  489                       return symbol;
  490                   }
  491               }
  492   
  493               ResourceBundle bundle = LocaleData.getCurrencyNames(locale);
  494               return bundle.getString(currencyCode);
  495           } catch (MissingResourceException e) {
  496               // use currency code as symbol of last resort
  497               return currencyCode;
  498           }
  499       }
  500   
  501       /**
  502        * Gets the default number of fraction digits used with this currency.
  503        * For example, the default number of fraction digits for the Euro is 2,
  504        * while for the Japanese Yen it's 0.
  505        * In the case of pseudo-currencies, such as IMF Special Drawing Rights,
  506        * -1 is returned.
  507        *
  508        * @return the default number of fraction digits used with this currency
  509        */
  510       public int getDefaultFractionDigits() {
  511           return defaultFractionDigits;
  512       }
  513   
  514       /**
  515        * Returns the ISO 4217 numeric code of this currency.
  516        *
  517        * @return the ISO 4217 numeric code of this currency
  518        * @since 1.7
  519        */
  520       public int getNumericCode() {
  521           return numericCode;
  522       }
  523   
  524       /**
  525        * Gets the name that is suitable for displaying this currency for
  526        * the default locale.  If there is no suitable display name found
  527        * for the default locale, the ISO 4217 currency code is returned.
  528        *
  529        * @return the display name of this currency for the default locale
  530        * @since 1.7
  531        */
  532       public String getDisplayName() {
  533           return getDisplayName(Locale.getDefault(Locale.Category.DISPLAY));
  534       }
  535   
  536       /**
  537        * Gets the name that is suitable for displaying this currency for
  538        * the specified locale.  If there is no suitable display name found
  539        * for the specified locale, the ISO 4217 currency code is returned.
  540        *
  541        * @param locale the locale for which a display name for this currency is
  542        * needed
  543        * @return the display name of this currency for the specified locale
  544        * @exception NullPointerException if <code>locale</code> is null
  545        * @since 1.7
  546        */
  547       public String getDisplayName(Locale locale) {
  548           try {
  549               OpenListResourceBundle bundle = LocaleData.getCurrencyNames(locale);
  550               String result = null;
  551               String bundleKey = currencyCode.toLowerCase(Locale.ROOT);
  552   
  553               // Check whether a provider can provide an implementation that's closer
  554               // to the requested locale than what the Java runtime itself can provide.
  555               LocaleServiceProviderPool pool =
  556                   LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
  557               if (pool.hasProviders()) {
  558                   result = pool.getLocalizedObject(
  559                                       CurrencyNameGetter.INSTANCE,
  560                                       locale, bundleKey, bundle, currencyCode, DISPLAYNAME);
  561               }
  562   
  563               if (result == null) {
  564                   result = bundle.getString(bundleKey);
  565               }
  566   
  567               if (result != null) {
  568                   return result;
  569               }
  570           } catch (MissingResourceException e) {
  571               // fall through
  572           }
  573   
  574           // use currency code as symbol of last resort
  575           return currencyCode;
  576       }
  577   
  578       /**
  579        * Returns the ISO 4217 currency code of this currency.
  580        *
  581        * @return the ISO 4217 currency code of this currency
  582        */
  583       public String toString() {
  584           return currencyCode;
  585       }
  586   
  587       /**
  588        * Resolves instances being deserialized to a single instance per currency.
  589        */
  590       private Object readResolve() {
  591           return getInstance(currencyCode);
  592       }
  593   
  594       /**
  595        * Gets the main table entry for the country whose country code consists
  596        * of char1 and char2.
  597        */
  598       private static int getMainTableEntry(char char1, char char2) {
  599           if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
  600               throw new IllegalArgumentException();
  601           }
  602           return mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')];
  603       }
  604   
  605       /**
  606        * Sets the main table entry for the country whose country code consists
  607        * of char1 and char2.
  608        */
  609       private static void setMainTableEntry(char char1, char char2, int entry) {
  610           if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
  611               throw new IllegalArgumentException();
  612           }
  613           mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')] = entry;
  614       }
  615   
  616       /**
  617        * Obtains a localized currency names from a CurrencyNameProvider
  618        * implementation.
  619        */
  620       private static class CurrencyNameGetter
  621           implements LocaleServiceProviderPool.LocalizedObjectGetter<CurrencyNameProvider,
  622                                                                      String> {
  623           private static final CurrencyNameGetter INSTANCE = new CurrencyNameGetter();
  624   
  625           public String getObject(CurrencyNameProvider currencyNameProvider,
  626                                   Locale locale,
  627                                   String key,
  628                                   Object... params) {
  629               assert params.length == 1;
  630               int type = (Integer)params[0];
  631   
  632               switch(type) {
  633               case SYMBOL:
  634                   return currencyNameProvider.getSymbol(key, locale);
  635               case DISPLAYNAME:
  636                   return currencyNameProvider.getDisplayName(key, locale);
  637               default:
  638                   assert false; // shouldn't happen
  639               }
  640   
  641               return null;
  642           }
  643       }
  644   
  645       private static int[] readIntArray(DataInputStream dis, int count) throws IOException {
  646           int[] ret = new int[count];
  647           for (int i = 0; i < count; i++) {
  648               ret[i] = dis.readInt();
  649           }
  650   
  651           return ret;
  652       }
  653   
  654       private static long[] readLongArray(DataInputStream dis, int count) throws IOException {
  655           long[] ret = new long[count];
  656           for (int i = 0; i < count; i++) {
  657               ret[i] = dis.readLong();
  658           }
  659   
  660           return ret;
  661       }
  662   
  663       private static String[] readStringArray(DataInputStream dis, int count) throws IOException {
  664           String[] ret = new String[count];
  665           for (int i = 0; i < count; i++) {
  666               ret[i] = dis.readUTF();
  667           }
  668   
  669           return ret;
  670       }
  671   
  672       /**
  673        * Replaces currency data found in the currencydata.properties file
  674        *
  675        * @param pattern regex pattern for the properties
  676        * @param ctry country code
  677        * @param data currency data.  This is a comma separated string that
  678        *    consists of "three-letter alphabet code", "three-digit numeric code",
  679        *    and "one-digit (0,1,2, or 3) default fraction digit".
  680        *    For example, "JPZ,392,0".
  681        * @throws
  682        */
  683       private static void replaceCurrencyData(Pattern pattern, String ctry, String curdata) {
  684   
  685           if (ctry.length() != 2) {
  686               // ignore invalid country code
  687               String message = new StringBuilder()
  688                   .append("The entry in currency.properties for ")
  689                   .append(ctry).append(" is ignored because of the invalid country code.")
  690                   .toString();
  691               info(message, null);
  692               return;
  693           }
  694   
  695           Matcher m = pattern.matcher(curdata);
  696           if (!m.find()) {
  697               // format is not recognized.  ignore the data
  698               String message = new StringBuilder()
  699                   .append("The entry in currency.properties for ")
  700                   .append(ctry)
  701                   .append(" is ignored because the value format is not recognized.")
  702                   .toString();
  703               info(message, null);
  704               return;
  705           }
  706   
  707           String code = m.group(1);
  708           int numeric = Integer.parseInt(m.group(2));
  709           int fraction = Integer.parseInt(m.group(3));
  710           int entry = numeric << NUMERIC_CODE_SHIFT;
  711   
  712           int index;
  713           for (index = 0; index < scOldCurrencies.length; index++) {
  714               if (scOldCurrencies[index].equals(code)) {
  715                   break;
  716               }
  717           }
  718   
  719           if (index == scOldCurrencies.length) {
  720               // simple case
  721               entry |= (fraction << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT) |
  722                        (code.charAt(2) - 'A');
  723           } else {
  724               // special case
  725               entry |= SPECIAL_CASE_COUNTRY_MASK |
  726                        (index + SPECIAL_CASE_COUNTRY_INDEX_DELTA);
  727           }
  728           setMainTableEntry(ctry.charAt(0), ctry.charAt(1), entry);
  729       }
  730   
  731       private static void info(String message, Throwable t) {
  732           PlatformLogger logger = PlatformLogger.getLogger("java.util.Currency");
  733           if (logger.isLoggable(PlatformLogger.INFO)) {
  734               if (t != null) {
  735                   logger.info(message, t);
  736               } else {
  737                   logger.info(message);
  738               }
  739           }
  740       }
  741   }

Home » openjdk-7 » java » util » [javadoc | source]