Home | History | Annotate | Download | only in util
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package java.util;
     19 
     20 // BEGIN android-added
     21 import com.ibm.icu4jni.util.LocaleData;
     22 import com.ibm.icu4jni.util.Resources;
     23 import java.util.logging.Logger;
     24 import org.apache.harmony.luni.util.Msg;
     25 // END android-added
     26 
     27 import java.security.AccessController;
     28 import java.io.Serializable;
     29 import java.security.PrivilegedAction;
     30 
     31 /**
     32  * This class represents a currency as identified in the ISO 4217 currency
     33  * codes.
     34  */
     35 public final class Currency implements Serializable {
     36 
     37     private static final long serialVersionUID = -158308464356906721L;
     38 
     39     private static final Hashtable<String, Currency> codesToCurrencies = new Hashtable<String, Currency>();
     40     private static final Hashtable<Locale, Currency> localesToCurrencies = new Hashtable<Locale, Currency>();
     41 
     42     private final String currencyCode;
     43 
     44     // BEGIN android-added
     45     // TODO: this isn't set if we're restored from serialized form,
     46     // so getDefaultFractionDigits always returns 0!
     47     private transient int defaultFractionDigits;
     48     // END android-added
     49 
     50     private Currency(String currencyCode) {
     51         // BEGIN android-changed
     52         this.currencyCode = currencyCode;
     53 
     54         // In some places the code XXX is used as the fall back currency.
     55         // The RI returns -1, but ICU defaults to 2 for unknown currencies.
     56         if (currencyCode.equals("XXX")) {
     57             this.defaultFractionDigits = -1;
     58             return;
     59         }
     60 
     61         this.defaultFractionDigits = Resources.getCurrencyFractionDigitsNative(currencyCode);
     62         if (defaultFractionDigits < 0) {
     63             throw new IllegalArgumentException(Msg.getString("K0322", currencyCode));
     64         }
     65         // END android-changed
     66     }
     67 
     68     /**
     69      * Returns the {@code Currency} instance for the given currency code.
     70      * <p>
     71      *
     72      * @param currencyCode
     73      *            the currency code.
     74      * @return the {@code Currency} instance for this currency code.
     75      *
     76      * @throws IllegalArgumentException
     77      *             if the currency code is not a supported ISO 4217 currency
     78      *             code.
     79      */
     80     public static Currency getInstance(String currencyCode) {
     81         // BEGIN android-changed
     82         Currency currency = codesToCurrencies.get(currencyCode);
     83         if (currency == null) {
     84             currency = new Currency(currencyCode);
     85             codesToCurrencies.put(currencyCode, currency);
     86         }
     87         return currency;
     88         // END android-changed
     89     }
     90 
     91     /**
     92      * Returns the {@code Currency} instance for this {@code Locale}'s country.
     93      *
     94      * @param locale
     95      *            the {@code Locale} of a country.
     96      * @return the {@code Currency} used in the country defined by the locale parameter.
     97      *
     98      * @throws IllegalArgumentException
     99      *             if the locale's country is not a supported ISO 3166 Country.
    100      */
    101     public static Currency getInstance(Locale locale) {
    102         // BEGIN android-changed
    103         Currency currency = localesToCurrencies.get(locale);
    104         if (currency != null) {
    105             return currency;
    106         }
    107         String country = locale.getCountry();
    108         String variant = locale.getVariant();
    109         if (variant.length() > 0 && (variant.equals("EURO") || variant.equals("HK") ||
    110                 variant.equals("PREEURO"))) {
    111             country = country + "_" + variant;
    112         }
    113 
    114         String currencyCode = Resources.getCurrencyCodeNative(country);
    115         if (currencyCode == null) {
    116             throw new IllegalArgumentException(Msg.getString("K0323", locale.toString()));
    117         } else if (currencyCode.equals("None")) {
    118             return null;
    119         }
    120         Currency result = getInstance(currencyCode);
    121         localesToCurrencies.put(locale, result);
    122         return result;
    123         // END android-changed
    124     }
    125 
    126     /**
    127      * Returns this {@code Currency}'s ISO 4217 currency code.
    128      *
    129      * @return this {@code Currency}'s ISO 4217 currency code.
    130      */
    131     public String getCurrencyCode() {
    132         return currencyCode;
    133     }
    134 
    135     /**
    136      * Returns the symbol for this currency in the default locale. For instance,
    137      * if the default locale is the US, the symbol of the US dollar is "$". For
    138      * other locales it may be "US$". If no symbol can be determined, the ISO
    139      * 4217 currency code of the US dollar is returned.
    140      *
    141      * @return the symbol for this {@code Currency} in the default {@code Locale}.
    142      */
    143     public String getSymbol() {
    144         return getSymbol(Locale.getDefault());
    145     }
    146 
    147     /**
    148      * Returns the symbol for this currency in the given {@code Locale}.
    149      * That is, given "USD" and Locale.US, you'd get "$", but given "USD" and a non-US locale,
    150      * you'd get "US$".
    151      * <p>
    152      * If the locale only specifies a language rather than a language and a countries (e.g.
    153      * {@code Locale.JAPANESE, new Locale("en","")}), the the ISO
    154      * 4217 currency code is returned.
    155      * <p>
    156      * If there is no currency symbol specific to this locale does not exist, the
    157      * ISO 4217 currency code is returned.
    158      * <p>
    159      *
    160      * @param locale
    161      *            the locale for which the currency symbol should be returned.
    162      * @return the representation of this {@code Currency}'s symbol in the specified
    163      *         locale.
    164      */
    165     public String getSymbol(Locale locale) {
    166         // BEGIN android-changed
    167         if (locale.getCountry().length() == 0) {
    168             return currencyCode;
    169         }
    170 
    171         // Check the locale first, in case the locale has the same currency.
    172         LocaleData localeData = Resources.getLocaleData(locale);
    173         if (localeData.internationalCurrencySymbol.equals(currencyCode)) {
    174             return localeData.currencySymbol;
    175         }
    176 
    177         // Try ICU, and fall back to the currency code if ICU has nothing.
    178         String symbol = Resources.getCurrencySymbolNative(locale.toString(), currencyCode);
    179         return symbol != null ? symbol : currencyCode;
    180         // END android-changed
    181     }
    182 
    183     /**
    184      * Returns the default number of fraction digits for this currency. For
    185      * instance, the default number of fraction digits for the US dollar is 2.
    186      * For the Japanese Yen the number is 0. In the case of pseudo-currencies,
    187      * such as IMF Special Drawing Rights, -1 is returned.
    188      *
    189      * @return the default number of fraction digits for this currency.
    190      */
    191     public int getDefaultFractionDigits() {
    192         // BEGIN android-changed
    193         // return com.ibm.icu.util.Currency.getInstance(currencyCode).getDefaultFractionDigits();
    194         return defaultFractionDigits;
    195         // END android-changed
    196     }
    197 
    198     /**
    199      * Returns this currency's ISO 4217 currency code.
    200      *
    201      * @return this currency's ISO 4217 currency code.
    202      */
    203     @Override
    204     public String toString() {
    205         return currencyCode;
    206     }
    207 
    208     private Object readResolve() {
    209         return getInstance(currencyCode);
    210     }
    211 
    212     // TODO: remove this in favor of direct access (and no ResourceBundle cruft).
    213     private static ResourceBundle getCurrencyBundle(final Locale locale) {
    214         return AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() {
    215             public ResourceBundle run() {
    216                 String bundle = "org.apache.harmony.luni.internal.locale.Currency";
    217                 return ResourceBundle.getBundle(bundle, locale);
    218             }
    219         });
    220     }
    221 }
    222