| package com.ibm.icu.util; |
| import java.util.Locale; |
| import java.util.ResourceBundle; |
| import java.util.MissingResourceException; |
| import java.io.Serializable; |
| import com.ibm.icu.impl.ICULocaleData; |
| import com.ibm.icu.text.DecimalFormatSymbols; |
| |
| /** |
| * A class encapsulating a currency, as defined by ISO 4217. A |
| * <tt>Currency</tt> object can be created given a <tt>Locale</tt> or |
| * given an ISO 4217 code. Once created, the <tt>Currency</tt> object |
| * can return various data necessary to its proper display: |
| * |
| * <ul><li>A display symbol, for a specific locale |
| * <li>The number of fraction digits to display |
| * <li>A rounding increment |
| * </ul> |
| * |
| * The <tt>DecimalFormat</tt> class uses these data to display |
| * currencies. |
| * |
| * <p>Note: This class deliberately resembles |
| * <tt>java.util.Currency</tt> but it has a completely independent |
| * implementation, and adds features not present in the JDK. |
| * @author Alan Liu |
| * @since ICU 2.2 |
| */ |
| public class Currency implements Serializable { |
| |
| /** |
| * ISO 4217 3-letter code. |
| */ |
| private String isoCode; |
| |
| /** |
| * Returns a currency object for the default currency in the given |
| * locale. |
| */ |
| public static Currency getInstance(Locale locale) { |
| // Look up the CurrencyElements resource for this locale. |
| // It contains: [0] = currency symbol, e.g. "$"; |
| // [1] = intl. currency symbol, e.g. "USD"; |
| // [2] = monetary decimal separator, e.g. ".". |
| ResourceBundle rb = ICULocaleData.getLocaleElements(locale); |
| String[] currencyElements = rb.getStringArray("CurrencyElements"); |
| return getInstance(currencyElements[1]); |
| } |
| |
| /** |
| * Returns a currency object given an ISO 4217 3-letter code. |
| */ |
| public static Currency getInstance(String theISOCode) { |
| return new Currency(theISOCode); |
| } |
| |
| /** |
| * Returns the ISO 4217 3-letter code for this currency object. |
| */ |
| public String getCurrencyCode() { |
| return isoCode; |
| } |
| |
| /** |
| * Returns the display string for this currency object in the |
| * given locale. For example, the display string for the USD |
| * currency object in the en_US locale is "$". |
| */ |
| public String getSymbol(Locale locale) { |
| // Look up the Currencies resource for the given locale. The |
| // Currencies locale looks like this in the original C |
| // resource file: |
| //|en { |
| //| Currencies { |
| //| USD { "$" } |
| //| CHF { "sFr" } |
| //| //... |
| //| } |
| //|} |
| ResourceBundle rb = ICULocaleData.getLocaleElements(locale); |
| // We can't cast this to String[][]; the cast has to happen later |
| try { |
| Object[][] currencies = (Object[][]) rb.getObject("Currencies"); |
| // Do a linear search |
| for (int i=0; i<currencies.length; ++i) { |
| if (isoCode.equals((String) currencies[i][0])) { |
| return (String) currencies[i][1]; |
| } |
| } |
| } |
| catch (MissingResourceException e) {} |
| |
| try { |
| // Since the Currencies resource is not fully populated yet, |
| // check to see if we can find what we want in the CurrencyElements |
| // resource. |
| String[] currencyElements = rb.getStringArray("CurrencyElements"); |
| if (currencyElements[1].equals(isoCode)) { |
| return currencyElements[0]; |
| } |
| } |
| catch (MissingResourceException e2) {} |
| |
| // If we fail to find a match, use the full ISO code |
| return isoCode; |
| } |
| |
| /** |
| * Returns the number of the number of fraction digits that should |
| * be displayed for this currency. |
| * @return a non-negative number of fraction digits to be |
| * displayed |
| */ |
| public int getDefaultFractionDigits() { |
| return (findData())[0].intValue(); |
| } |
| |
| /** |
| * Returns the rounding increment for this currency, or 0.0 if no |
| * rounding is done by this currency. |
| * @return the non-negative rounding increment, or 0.0 if none |
| */ |
| public double getRoundingIncrement() { |
| Integer[] data = findData(); |
| |
| int data1 = data[1].intValue(); // rounding increment |
| |
| // If there is no rounding return 0.0 to indicate no rounding. |
| // This is the high-runner case, by far. |
| if (data1 == 0) { |
| return 0.0; |
| } |
| |
| int data0 = data[0].intValue(); // fraction digits |
| |
| // If the meta data is invalid, return 0.0 to indicate no rounding. |
| if (data0 < 0 || data0 >= POW10.length) { |
| return 0.0; |
| } |
| |
| // Return data[1] / 10^(data[0]). The only actual rounding data, |
| // as of this writing, is CHF { 2, 25 }. |
| return (double) data1 / POW10[data0]; |
| } |
| |
| /** |
| * Returns the ISO 4217 code for this currency. |
| */ |
| public String toString() { |
| return isoCode; |
| } |
| |
| /** |
| * Constructs a currency object for the given ISO 4217 3-letter |
| * code. This constructor assumes that the code is valid. |
| */ |
| private Currency(String theISOCode) { |
| isoCode = theISOCode; |
| } |
| |
| /** |
| * Internal function to look up currency data. Result is an array of |
| * two Integers. The first is the fraction digits. The second is the |
| * rounding increment, or 0 if none. The rounding increment is in |
| * units of 10^(-fraction_digits). |
| */ |
| private Integer[] findData() { |
| |
| try { |
| // Get CurrencyMeta resource out of root locale file. [This may |
| // move out of the root locale file later; if it does, update this |
| // code.] |
| ResourceBundle root = ICULocaleData.getLocaleElements(""); |
| |
| Object[][] currencyMeta = (Object[][]) root.getObject("CurrencyMeta"); |
| |
| Integer[] i = null; |
| int defaultPos = -1; |
| |
| // Do a linear search for isoCode. At the same time, |
| // record the position of the DEFAULT meta data. If the |
| // meta data becomes large, make this faster. |
| for (int j=0; j<currencyMeta.length; ++j) { |
| Object[] row = currencyMeta[j]; |
| String s = (String) row[0]; |
| int c = isoCode.compareToIgnoreCase(s); |
| if (c == 0) { |
| i = (Integer[]) row[1]; |
| break; |
| } |
| if ("DEFAULT".equalsIgnoreCase(s)) { |
| defaultPos = j; |
| } |
| if (c < 0 && defaultPos >= 0) { |
| break; |
| } |
| } |
| |
| if (i == null && defaultPos >= 0) { |
| i = (Integer[]) currencyMeta[defaultPos][1]; |
| } |
| |
| if (i != null && i.length >= 2) { |
| return i; |
| } |
| } |
| catch (MissingResourceException e) {} |
| |
| // Config/build error; return hard-coded defaults |
| return LAST_RESORT_DATA; |
| } |
| |
| // Default currency meta data of last resort. We try to use the |
| // defaults encoded in the meta data resource bundle. If there is a |
| // configuration/build error and these are not available, we use these |
| // hard-coded defaults (which should be identical). |
| private static final Integer[] LAST_RESORT_DATA = |
| new Integer[] { new Integer(2), new Integer(0) }; |
| |
| // POW10[i] = 10^i |
| private static final int[] POW10 = { 1, 10, 100, 1000, 10000, 100000, |
| 1000000, 10000000, 100000000, 1000000000 }; |
| } |
| |
| //eof |