/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.basics.currency; import java.io.Serializable; import java.util.Locale; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.regex.Pattern; import org.joda.convert.FromString; import org.joda.convert.ToString; import com.google.common.collect.ImmutableSet; import com.opengamma.collect.ArgChecker; /** * A unit of currency. * <p> * This class represents a unit of currency such as the British Pound, Euro or US Dollar. * Any three letter code may be used, however it is intended to use codes based on ISO-4217. * <p> * This class is immutable and thread-safe. */ public final class Currency implements Comparable<Currency>, Serializable { /** Serialization version. */ private static final long serialVersionUID = 1L; /** * A cache of instances. */ private static final ConcurrentMap<String, Currency> CACHE = new ConcurrentHashMap<>(); /** * The valid regex for schemes. * Three ASCII upper case letters. */ private static final Pattern REGEX_CODE = Pattern.compile("[A-Z]{3}"); // a selection of commonly traded, stable currencies /** * The currency 'USD' - United States Dollar. */ public static final Currency USD = of("USD"); /** * The currency 'EUR' - Euro. */ public static final Currency EUR = of("EUR"); /** * The currency 'JPY' - Japanese Yen. */ public static final Currency JPY = of("JPY"); /** * The currency 'GBP' - British pound. */ public static final Currency GBP = of("GBP"); /** * The currency 'EUR' - Swiss Franc. */ public static final Currency CHF = of("CHF"); /** * The currency 'AUD' - Australian Dollar. */ public static final Currency AUD = of("AUD"); /** * The currency 'CAD' - Canadian Dollar. */ public static final Currency CAD = of("CAD"); // a selection of other currencies /** * The currency 'ARS' - Argentine Peso. */ public static final Currency ARS = of("ARS"); /** * The currency 'BRL' - Brazil Dollar. */ public static final Currency BRL = of("BRL"); /** * The currency 'CLP' - Chilean Peso. */ public static final Currency CLP = of("CLP"); /** * The currency 'CNY' - Chinese Yuan. */ public static final Currency CNY = of("CNY"); /** * The currency 'CZK' - Czeck Krona. */ public static final Currency CZK = of("CZK"); /** * The currency 'DKK' - Danish Krone. */ public static final Currency DKK = of("DKK"); /** * The currency 'EGP' - Egyptian Pound. */ public static final Currency EGP = of("EGP"); /** * The currency 'HKD' - Hong Kong Dollar. */ public static final Currency HKD = of("HKD"); /** * The currency 'HUF' = Hugarian Forint. */ public static final Currency HUF = of("HUF"); /** * The currency 'IDR' = Indonesian Rupiah. */ public static final Currency IDR = of("IDR"); /** * The currency 'ILS' = Israeli Shekel. */ public static final Currency ILS = of("ILS"); /** * The currency 'KRW' = South Korean Won. */ public static final Currency KRW = of("KRW"); /** * The currency 'INR' = Indian Rupee. */ public static final Currency INR = of("INR"); /** * The currency 'ISK' = Icelandic Krone. */ public static final Currency ISK = of("ISK"); /** * The currency 'MXN' - Mexican Peso. */ public static final Currency MXN = of("MXN"); /** * The currency 'MYR' - Malaysian Ringgit. */ public static final Currency MYR = of("MYR"); /** * The currency 'NOK' - Norwegian Krone. */ public static final Currency NOK = of("NOK"); /** * The currency 'NZD' - New Zealand Dollar. */ public static final Currency NZD = of("NZD"); /** * The currency 'PLN' - Polish Zloty. */ public static final Currency PLN = of("PLN"); /** * The currency 'RUB' - Russian Ruble. */ public static final Currency RUB = of("RUB"); /** * The currency 'SAR' - Saudi Riyal. */ public static final Currency SAR = of("SAR"); /** * The currency 'SEK' - Swedish Krona. */ public static final Currency SEK = of("SEK"); /** * The currency 'SGD' - Singapore Dollar. */ public static final Currency SGD = of("SGD"); /** * The currency 'SKK' - Slovak Korona. */ public static final Currency SKK = of("SKK"); /** * The currency 'THB' - Thai Baht. */ public static final Currency THB = of("THB"); /** * The currency 'TRY' - Turkish Lira. */ public static final Currency TRY = of("TRY"); /** * The currency 'ZAR' - South African Rand. */ public static final Currency ZAR = of("ZAR"); // a selection of historic currencies /** * The historic currency 'BEF' - Belgian Franc. */ public static final Currency BEF = of("BEF"); /** * The historic currency 'DEM' - Deutsche Mark. */ public static final Currency DEM = of("DEM"); /** * The historic currency 'ESP' - Spanish Peseta. */ public static final Currency ESP = of("ESP"); /** * The historic currency 'FRF' - French Franc. */ public static final Currency FRF = of("FRF"); /** * The historic currency 'GRD' - Greek Drachma. */ public static final Currency GRD = of("GRD"); /** * The historic currency 'IEP' - Irish Pound. */ public static final Currency IEP = of("IEP"); /** * The historic currency 'ITL' - Italian Lira. */ public static final Currency ITL = of("ITL"); /** * The historic currency 'NLG' - Dutch Guilder. */ public static final Currency NLG = of("NLG"); /** * The historic currency 'PTE' - Portuguese Escudo. */ public static final Currency PTE = of("PTE"); /** * The currency code. */ private final String code; /** * The cached hash code. */ private final int cachedHashCode; //------------------------------------------------------------------------- /** * Obtains the set of available currencies. * <p> * This contains all the currencies that have been defined at the point * that the method is called. * * @return an immutable set containing all registered currencies */ public static Set<Currency> getAvailableCurrencies() { return ImmutableSet.copyOf(CACHE.values()); } //------------------------------------------------------------------------- /** * Obtains an instance of {@code Currency} for the specified ISO-4217 * three letter currency code dynamically creating a currency if necessary. * <p> * A currency is uniquely identified by ISO-4217 three letter code. * This method creates the currency if it is not known. * * @param currencyCode the three letter currency code, ASCII and upper case * @return the singleton instance * @throws IllegalArgumentException if the currency code is invalid */ @FromString public static Currency of(String currencyCode) { ArgChecker.matches(REGEX_CODE, currencyCode, "currencyCode"); return CACHE.computeIfAbsent(currencyCode, Currency::new); } //------------------------------------------------------------------------- /** * Obtains an instance of {@code Currency} matching the specified JDK currency. * <p> * This converts the JDK currency instance to a currency unit using the code. * * @param currency the currency * @return the singleton instance * @throws IllegalArgumentException if the currency cannot be converted */ public static Currency fromJdk(java.util.Currency currency) { ArgChecker.notNull(currency, "currency"); return Currency.of(currency.getCurrencyCode()); } //------------------------------------------------------------------------- /** * Parses a string to obtain a {@code Currency}. * <p> * The parse is identical to {@link #of(String)} except that it will convert * letters to upper case first. * * @param currencyCode the three letter currency code, ASCII * @return the singleton instance * @throws IllegalArgumentException if the currency code is invalid */ public static Currency parse(String currencyCode) { ArgChecker.notNull(currencyCode, "currencyCode"); return of(currencyCode.toUpperCase(Locale.ENGLISH)); } //------------------------------------------------------------------------- /** * Restricted constructor. * * @param code the three letter currency code */ private Currency(String code) { this.code = code; // total universe is (26 * 26 * 26) codes, which can provide a unique hash code this.cachedHashCode = ((code.charAt(0) - 64) << 16) + ((code.charAt(1) - 64) << 8) + (code.charAt(2) - 64); } /** * Ensure singleton on deserialization. * * @return the singleton */ private Object readResolve() { return Currency.of(code); } //------------------------------------------------------------------------- /** * Gets the three letter ISO code. * * @return the three letter ISO code */ public String getCode() { return code; } //------------------------------------------------------------------------- /** * Gets the JDK currency instance equivalent to this currency. * <p> * This attempts to convert a {@code Currency} to a JDK {@code Currency}. * * @return the JDK currency instance * @throws IllegalArgumentException if no matching currency exists in the JDK */ public java.util.Currency toJdk() { return java.util.Currency.getInstance(code); } //------------------------------------------------------------------------- /** * Compares this currency to another. * <p> * The comparison sorts alphabetically by the three letter currency code. * * @param other the other currency * @return negative if less, zero if equal, positive if greater */ @Override public int compareTo(Currency other) { // hash code is unique and ordered so can be used for compareTo return cachedHashCode - other.cachedHashCode; } /** * Checks if this currency equals another currency. * <p> * The comparison checks the three letter currency code. * * @param obj the other currency, null returns false * @return true if equal */ @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof Currency) { return equals((Currency) obj); } return false; } // called by CurrencyAmount boolean equals(Currency other) { // hash code is unique so can be used for equals return other.cachedHashCode == cachedHashCode; } /** * Returns a suitable hash code for the currency. * * @return the hash code */ @Override public int hashCode() { return cachedHashCode; } //------------------------------------------------------------------------- /** * Returns a string representation of the currency, which is the three letter code. * * @return the three letter currency code */ @Override @ToString public String toString() { return code; } }