All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.tsl2.nano.currency.CurrencyUtil Maven / Gradle / Ivy

Go to download

TSL2 Framework Descriptor (currency-handling, generic formatter, descriptors for beans, collections, actions and values)

There is a newer version: 2.5.1
Show newest version
/*
 * File: $HeadURL$
 * Id  : $Id$
 * 
 * created by: Thomas Schneider
 * created on: Apr 16, 2012
 * 
 * Copyright: (c) Thomas Schneider, all rights reserved
 */
package de.tsl2.nano.currency;

import java.io.File;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.Format;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Currency;
import java.util.Date;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.logging.Log;

import de.tsl2.nano.bean.BeanUtil;
import de.tsl2.nano.collection.CollectionUtil;
import de.tsl2.nano.core.IPredicate;
import de.tsl2.nano.core.log.LogFactory;
import de.tsl2.nano.core.util.FileUtil;
import de.tsl2.nano.core.util.MapUtil;
import de.tsl2.nano.core.util.Period;

/**
 * The jdk implementation (until 1.6) {@link Currency} does not provide needed features like giving historized currency
 * codes. This is done by ICU - International Components for Unicode - Project. But, no factor for calculating the new
 * currency value is given, the implementation is heavy (7MB) and has to initialize a lot of overhead (several seconds).
 * 

* This class encapsulates and simplifies the use of historic currencies through {@link CurrencyUnit}s. The * {@link CurrencyUnit} wraps the standard {@link Currency} extending historizing and calculating aspects. The file * 'historical-currencies.csv' should define all historic currencies - the list is not complete! For a complete list, see * http://de.wikipedia.org/wiki/ISO_4217. * * @author ts * @version $Revision$ */ public class CurrencyUtil { private static final String HISTORICAL_CURRENCIES_FILE_NAME = "historical-currencies.csv"; /** historic Currency-Units read from csv file */ static final Collection historicCurrencyUnits = new ArrayList(); /** cache of already loaded currencies and their units */ static final Map currencyUnits = new Hashtable(); private static final Log LOG = LogFactory.getLog(CurrencyUtil.class); // public static final Currency getCurrency(Locale loc, Date date) { // ULocale uLocale = new ULocale(loc.getISO3Country(), loc.getISO3Language()); // String[] currencyCodes = com.ibm.icu.util.Currency.getAvailableCurrencyCodes(uLocale, date); // LOG.debug("Currencies for locale " + loc + " and date " + date + ": " + StringUtil.toString(currencyCodes, 80)); // return Currency.getInstance(currencyCodes[0]); //} /** * getCurrency * * @return default currency unit */ public static final CurrencyUnit getCurrency() { return getCurrency(Locale.getDefault()); } /** * getCurrency * * @param loc locale to get the currency for * @return currency unit for given locale */ public static final CurrencyUnit getCurrency(Locale loc) { Currency c = Currency.getInstance(loc); CurrencyUnit unit = currencyUnits.get(c); if (unit == null) { unit = new CurrencyUnit(loc.getCountry(), c.getCurrencyCode(), null, null, 1.0); currencyUnits.put(c, unit); } return unit; } /** * getCurrency * * @param date validation date for the default currency * @return default currency, valid for the given date */ public static final CurrencyUnit getCurrency(Date date) { return getCurrency(Locale.getDefault(), date); } public static final CurrencyUnit getCurrencyUnit(final Currency c) { if (c == null) { return null; } if (historicCurrencyUnits.isEmpty()) { initializeCurrencyUnits(); } Collection currencies = CollectionUtil.getFilteredCollection(historicCurrencyUnits, new IPredicate() { @Override public boolean eval(CurrencyUnit arg0) { CurrencyUnit cu = arg0; return cu.getCurrencyCode().equals(c.getCurrencyCode()); } }); return currencies.iterator().next(); } /** * getCurrency * * @param loc locale to get the currency for * @param date validation date for the default currency * @return default currency, valid for the given date */ public static final CurrencyUnit getCurrency(final Locale loc, final Date date) { if (historicCurrencyUnits.isEmpty()) { initializeCurrencyUnits(); } Collection currencies = CollectionUtil.getFilteredCollection(historicCurrencyUnits, new IPredicate() { @Override public boolean eval(CurrencyUnit arg0) { CurrencyUnit cu = arg0; return cu.getCountryCode().equals(loc.getCountry()) && new Period(cu.getValidFrom(), cu.getValidUntil()).contains(new Period(date, date)); } }); if (currencies.size() == 0) {//no historical entry found - use standard currency LOG.warn("no historical entry found for " + date + " -> using standard currency!"); return getCurrency(loc); } else if (currencies.size() != 1) { LOG.warn("not exactly one currency found for " + loc + ", " + date); } return currencies.iterator().next(); } /** * convenience to get the value for the actual default currency (depends on current locale). * * @param value historic value * @param currencyDate date of value and its currency * @return calculated and rounded value for the actual currency */ public static BigDecimal getActualValue(float value, Date currencyDate) { return getActualValue(value, getCurrency(currencyDate)); } /** * calculates the value for the given (perhaps historic) unit to actual default unit (depends on current locale). * The result is round to the currencies default fraction digits. Please see hints of * {@link BigDecimal#BigDecimal(double)} to see problems on construction with a double value. * * @param value historic value * @param unit currency unit * @return actual rounded value */ public static BigDecimal getActualValue(float value, CurrencyUnit unit) { BigDecimal bd = BigDecimal.valueOf(value / unit.getFactor()); return bd.setScale(unit.getCurrency().getDefaultFractionDigits(), BigDecimal.ROUND_HALF_UP); } /** * convenience to get the factor from historic currency to actual currency (depends on current locale). * * @param currencyDate date of value and its currency * @return historic factor or null */ public static final Double getFactor(Date historicCurrencyDate) { return getFactor(Locale.getDefault(), historicCurrencyDate); } /** * convenience to get the factor from historic currency to actual currency. * * @param loc locale of currency * @param currencyDate date of value and its currency * @return historic factor or null */ public static final Double getFactor(Locale loc, Date historicCurrencyDate) { return getCurrency(loc, historicCurrencyDate).factor; } /** * evaluates the currency symbol of the given date and formats the value plus symbol. see * {@link #getFormattedValue(Number, String)}. */ public static String getFormattedValue(Number value, Date dateOfCurrency) { return getFormattedValue(value, getCurrency(dateOfCurrency).getCurrency().getSymbol()); } /** * see {@link #getFormattedValue(Number, String)}. */ public static String getFormattedValue(Number value, CurrencyUnit unit) { return getFormattedValue(value, unit.getCurrency().getSymbol()); } /** * formats the given value to fulfill the current locale - appending the given symbol * * @param value value to format * @param currencySymbol symbol to append * @return string representation */ public static String getFormattedValue(Number value, String currencySymbol) { return value != null ? MessageFormat.format("{0} {1}", value, currencySymbol) : ""; } /** * creates a NumberFormat for BigDecimals with currency code and fractionDigits * * @param currencyCode (optional) currency code (see {@link Currency#getInstance(String)} and {@link http * ://de.wikipedia.org/wiki/ISO_4217} - or null. * @param fractionDigits number of fraction digits (precision) * @return new numberformat instance */ public static final NumberFormat getFormat(String currencyCode, int fractionDigits) { final DecimalFormat numberFormat = (DecimalFormat) (currencyCode != null ? NumberFormat.getCurrencyInstance() : NumberFormat.getInstance()); if (currencyCode != null) { numberFormat.setCurrency(Currency.getInstance(currencyCode)); } numberFormat.setMinimumFractionDigits(fractionDigits); numberFormat.setMaximumFractionDigits(fractionDigits); numberFormat.setGroupingUsed(true); numberFormat.setParseBigDecimal(true); return numberFormat; } /** * delegates to {@link #getFormat(Locale, Date)} with default locale */ public static NumberFormat getFormat(Date historicCurrencyDate) { return getFormat(Locale.getDefault(), historicCurrencyDate); } /** * formatter for given perhaps historic currency * @param loc locale * @param historicCurrencyDate date of currency * @return formatter */ public static NumberFormat getFormat(Locale loc, Date historicCurrencyDate) { CurrencyUnit currency = getCurrency(loc, historicCurrencyDate); return getFormat(currency.getCurrencyCode(), currency.getCurrency().getDefaultFractionDigits()); } /** * initializeCurrencyUnits */ private static void initializeCurrencyUnits() { String filePath = null; InputStreamReader reader = null; final File file = new File(System.getProperty("user.dir") + File.separator + HISTORICAL_CURRENCIES_FILE_NAME); if (file.exists() && file.canRead()) { filePath = file.getPath(); reader = new InputStreamReader(FileUtil.getFile(filePath)); } if (filePath == null) { //loading from resource in a jar needs a path separator '/' final String ppath = CurrencyUnit.class.getPackage().getName().replace('.', '/'); filePath = ppath + "/" + HISTORICAL_CURRENCIES_FILE_NAME; reader = new InputStreamReader(FileUtil.getResource(filePath)); } Format df = new SimpleDateFormat("yyyy-MM-dd"); Map formats = MapUtil.asMap("validFrom", df, "validUntil", df, "factor", NumberFormat.getInstance(Locale.US)); Collection c = BeanUtil.fromFlatFile(reader, "\t", CurrencyUnit.class, formats, "countryCode", "currencyCode", "validFrom", "validUntil", "factor"); for (CurrencyUnit cu : c) { historicCurrencyUnits.add(cu); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy