1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package java.util; 28 29 import java.io.Serializable; 30 31 import libcore.icu.ICU; 32 33 /** 34 * Represents a currency. Currencies are identified by their ISO 4217 currency 35 * codes. Visit the <a href="http://www.iso.org/iso/en/prods-services/popstds/currencycodes.html"> 36 * ISO web site</a> for more information, including a table of 37 * currency codes. 38 * <p> 39 * The class is designed so that there's never more than one 40 * <code>Currency</code> instance for any given currency. Therefore, there's 41 * no public constructor. You obtain a <code>Currency</code> instance using 42 * the <code>getInstance</code> methods. 43 * <p> 44 * Users can supersede the Java runtime currency data by creating a properties 45 * file named <code><JAVA_HOME>/lib/currency.properties</code>. The contents 46 * of the properties file are key/value pairs of the ISO 3166 country codes 47 * and the ISO 4217 currency data respectively. The value part consists of 48 * three ISO 4217 values of a currency, i.e., an alphabetic code, a numeric 49 * code, and a minor unit. Those three ISO 4217 values are separated by commas. 50 * The lines which start with '#'s are considered comment lines. For example, 51 * <p> 52 * <code> 53 * #Sample currency properties<br> 54 * JP=JPZ,999,0 55 * </code> 56 * <p> 57 * will supersede the currency data for Japan. 58 * 59 * @since 1.4 60 */ 61 public final class Currency implements Serializable { 62 63 private static final long serialVersionUID = -158308464356906721L; 64 65 private static HashMap<String, Currency> instances = new HashMap<>(); 66 67 private static HashSet<Currency> available; 68 69 private transient final android.icu.util.Currency icuCurrency; 70 71 private final String currencyCode; 72 73 /** 74 * Constructs a <code>Currency</code> instance. The constructor is private 75 * so that we can insure that there's never more than one instance for a 76 * given currency. 77 */ Currency(android.icu.util.Currency icuCurrency)78 private Currency(android.icu.util.Currency icuCurrency) { 79 this.icuCurrency = icuCurrency; 80 this.currencyCode = icuCurrency.getCurrencyCode(); 81 } 82 83 /** 84 * Returns the <code>Currency</code> instance for the given currency code. 85 * 86 * @param currencyCode the ISO 4217 code of the currency 87 * @return the <code>Currency</code> instance for the given currency code 88 * @exception NullPointerException if <code>currencyCode</code> is null 89 * @exception IllegalArgumentException if <code>currencyCode</code> is not 90 * a supported ISO 4217 code. 91 */ getInstance(String currencyCode)92 public static Currency getInstance(String currencyCode) { 93 synchronized (instances) { 94 Currency instance = instances.get(currencyCode); 95 if (instance == null) { 96 android.icu.util.Currency icuInstance = 97 android.icu.util.Currency.getInstance(currencyCode); 98 if (icuInstance == null) { 99 return null; 100 } 101 instance = new Currency(icuInstance); 102 instances.put(currencyCode, instance); 103 } 104 return instance; 105 } 106 } 107 108 /** 109 * Returns the <code>Currency</code> instance for the country of the 110 * given locale. The language and variant components of the locale 111 * are ignored. The result may vary over time, as countries change their 112 * currencies. For example, for the original member countries of the 113 * European Monetary Union, the method returns the old national currencies 114 * until December 31, 2001, and the Euro from January 1, 2002, local time 115 * of the respective countries. 116 * <p> 117 * The method returns <code>null</code> for territories that don't 118 * have a currency, such as Antarctica. 119 * 120 * @param locale the locale for whose country a <code>Currency</code> 121 * instance is needed 122 * @return the <code>Currency</code> instance for the country of the given 123 * locale, or null 124 * @exception NullPointerException if <code>locale</code> or its country 125 * code is null 126 * @exception IllegalArgumentException if the country of the given locale 127 * is not a supported ISO 3166 country code. 128 */ getInstance(Locale locale)129 public static Currency getInstance(Locale locale) { 130 android.icu.util.Currency icuInstance = 131 android.icu.util.Currency.getInstance(locale); 132 String variant = locale.getVariant(); 133 String country = locale.getCountry(); 134 if (!variant.isEmpty() && (variant.equals("EURO") || variant.equals("HK") || 135 variant.equals("PREEURO"))) { 136 country = country + "_" + variant; 137 } 138 String currencyCode = ICU.getCurrencyCode(country); 139 if (currencyCode == null) { 140 throw new IllegalArgumentException("Unsupported ISO 3166 country: " + locale); 141 } 142 if (icuInstance == null || icuInstance.getCurrencyCode().equals("XXX")) { 143 return null; 144 } 145 return getInstance(currencyCode); 146 } 147 148 /** 149 * Gets the set of available currencies. The returned set of currencies 150 * contains all of the available currencies, which may include currencies 151 * that represent obsolete ISO 4217 codes. The set can be modified 152 * without affecting the available currencies in the runtime. 153 * 154 * @return the set of available currencies. If there is no currency 155 * available in the runtime, the returned set is empty. 156 * @since 1.7 157 */ getAvailableCurrencies()158 public static Set<Currency> getAvailableCurrencies() { 159 synchronized (Currency.class) { 160 if (available == null) { 161 Set<android.icu.util.Currency> icuAvailableCurrencies 162 = android.icu.util.Currency.getAvailableCurrencies(); 163 available = new HashSet<>(); 164 for (android.icu.util.Currency icuCurrency : icuAvailableCurrencies) { 165 Currency currency = getInstance(icuCurrency.getCurrencyCode()); 166 if (currency == null) { 167 currency = new Currency(icuCurrency); 168 instances.put(currency.currencyCode, currency); 169 } 170 available.add(currency); 171 } 172 } 173 return (Set<Currency>) available.clone(); 174 } 175 } 176 177 /** 178 * Gets the ISO 4217 currency code of this currency. 179 * 180 * @return the ISO 4217 currency code of this currency. 181 */ getCurrencyCode()182 public String getCurrencyCode() { 183 return currencyCode; 184 } 185 186 /** 187 * Gets the symbol of this currency for the default locale. 188 * For example, for the US Dollar, the symbol is "$" if the default 189 * locale is the US, while for other locales it may be "US$". If no 190 * symbol can be determined, the ISO 4217 currency code is returned. 191 * 192 * @return the symbol of this currency for the default locale 193 */ getSymbol()194 public String getSymbol() { 195 return icuCurrency.getSymbol(); 196 } 197 198 /** 199 * Gets the symbol of this currency for the specified locale. 200 * For example, for the US Dollar, the symbol is "$" if the specified 201 * locale is the US, while for other locales it may be "US$". If no 202 * symbol can be determined, the ISO 4217 currency code is returned. 203 * 204 * @param locale the locale for which a display name for this currency is 205 * needed 206 * @return the symbol of this currency for the specified locale 207 * @exception NullPointerException if <code>locale</code> is null 208 */ getSymbol(Locale locale)209 public String getSymbol(Locale locale) { 210 if (locale == null) { 211 throw new NullPointerException("locale == null"); 212 } 213 return icuCurrency.getSymbol(locale); 214 } 215 216 /** 217 * Gets the default number of fraction digits used with this currency. 218 * For example, the default number of fraction digits for the Euro is 2, 219 * while for the Japanese Yen it's 0. 220 * In the case of pseudo-currencies, such as IMF Special Drawing Rights, 221 * -1 is returned. 222 * 223 * @return the default number of fraction digits used with this currency 224 */ getDefaultFractionDigits()225 public int getDefaultFractionDigits() { 226 if (icuCurrency.getCurrencyCode().equals("XXX")) { 227 return -1; 228 } 229 return icuCurrency.getDefaultFractionDigits(); 230 } 231 232 /** 233 * Returns the ISO 4217 numeric code of this currency. 234 * 235 * @return the ISO 4217 numeric code of this currency 236 * @since 1.7 237 */ getNumericCode()238 public int getNumericCode() { 239 return icuCurrency.getNumericCode(); 240 } 241 242 /** 243 * Gets the name that is suitable for displaying this currency for 244 * the default locale. If there is no suitable display name found 245 * for the default locale, the ISO 4217 currency code is returned. 246 * 247 * @return the display name of this currency for the default locale 248 * @since 1.7 249 */ getDisplayName()250 public String getDisplayName() { 251 return icuCurrency.getDisplayName(); 252 } 253 254 /** 255 * Gets the name that is suitable for displaying this currency for 256 * the specified locale. If there is no suitable display name found 257 * for the specified locale, the ISO 4217 currency code is returned. 258 * 259 * @param locale the locale for which a display name for this currency is 260 * needed 261 * @return the display name of this currency for the specified locale 262 * @exception NullPointerException if <code>locale</code> is null 263 * @since 1.7 264 */ getDisplayName(Locale locale)265 public String getDisplayName(Locale locale) { 266 return icuCurrency.getDisplayName(locale); 267 } 268 269 /** 270 * Returns the ISO 4217 currency code of this currency. 271 * 272 * @return the ISO 4217 currency code of this currency 273 */ toString()274 public String toString() { 275 return icuCurrency.toString(); 276 } 277 278 /** 279 * Resolves instances being deserialized to a single instance per currency. 280 */ readResolve()281 private Object readResolve() { 282 return getInstance(currencyCode); 283 } 284 } 285