1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/task1/solution13/src/org/apidesign/apifest08/currency/Convertor.java Tue Sep 30 13:42:03 2008 +0200
1.3 @@ -0,0 +1,105 @@
1.4 +package org.apidesign.apifest08.currency;
1.5 +
1.6 +import java.math.BigDecimal;
1.7 +import java.math.MathContext;
1.8 +import java.math.RoundingMode;
1.9 +
1.10 +/** Convertor able to convert amount from one currency to other currency.
1.11 + *
1.12 + * Exchange rate is provided by {@link ExchangeRateProvider}.
1.13 + */
1.14 +public class Convertor {
1.15 + boolean remainderAllowed = false; //if false, remained is not allowed (should be true ideally, but can't handle it now)
1.16 + ExchangeRateProvider exchangeRateProvider;
1.17 +
1.18 + private Convertor() {
1.19 +
1.20 + }
1.21 +
1.22 + /**
1.23 + * Static method used to create convertor.
1.24 + *
1.25 + * @param exchangeRateProvider {@link ExchangeRateProvider} used to get exchange rate.
1.26 + *
1.27 + * @return Returns <code>Convertor</code> which can be used to convert money.
1.28 + */
1.29 + public static Convertor createConvertor(ExchangeRateProvider exchangeRateProvider) {
1.30 + Convertor c = new Convertor();
1.31 +
1.32 + c.exchangeRateProvider = exchangeRateProvider;
1.33 + return c;
1.34 + }
1.35 +
1.36 + /**
1.37 + * Convert <code>amount</code> from <code>fromCurrency</code> to <code>toCurrency</code> as specified
1.38 + * in <code>ExchangeRateProvider</code>.
1.39 + *
1.40 + * @param amount Amount which should be converted. Can't be negative value (can be zero or positive).
1.41 + * @return Return <code>ConversionResult</code> which holds conversion result.
1.42 + */
1.43 + public ConversionResult convert(BigDecimal amount) {
1.44 + return convertValue(amount, false);
1.45 + }
1.46 +
1.47 + /**
1.48 + * Convert <code>amount</code> from <code>toCurrency</code> to <code>fromCurrency</code> as specified
1.49 + * in <code>ExchangeRateProvider</code>. This is <em>reverted</em> order than suggested by names of currency fields in <code>ExchangeRate</code>.
1.50 + *
1.51 + * @param amount Amount which should be converted. Can't be negative value (can be zero or positive).
1.52 + * @return Return <code>ConversionResult</code> which holds conversion result.
1.53 + */
1.54 + public ConversionResult convertBack(BigDecimal amount) {
1.55 + return convertValue(amount, true);
1.56 + }
1.57 +
1.58 + private ConversionResult convertValue(BigDecimal amount, boolean convertBack) throws RuntimeException {
1.59 + ConversionResult result = new ConversionResult();
1.60 +
1.61 + ExchangeRate rate = exchangeRateProvider.getExchangeRate();
1.62 + int fromFranctionDigits = exchangeRateProvider.getFromCurrency().getDefaultFractionDigits();
1.63 + int toFractionDigits = exchangeRateProvider.getToCurrency().getDefaultFractionDigits();
1.64 +
1.65 + if (toFractionDigits!=2) {
1.66 + throw new RuntimeException("Can't process currency with defaultFractionDigits!=2, "+exchangeRateProvider.getToCurrency()+" has "+toFractionDigits+" defaultFractionDigits");
1.67 + }
1.68 + if (fromFranctionDigits!=2) {
1.69 + throw new RuntimeException("Can't process currency with defaultFractionDigits!=2, "+exchangeRateProvider.getFromCurrency()+" has "+fromFranctionDigits+" defaultFractionDigits");
1.70 + }
1.71 +
1.72 + if (amount.signum()==-1) {
1.73 + throw new RuntimeException("Can convert only non-negative value, current value is "+amount);
1.74 + }
1.75 +
1.76 +
1.77 + MathContext context = new MathContext(0, RoundingMode.DOWN);
1.78 +
1.79 + BigDecimal from;
1.80 + BigDecimal to;
1.81 + if (convertBack) {
1.82 + //converting in reverted way
1.83 + to = rate.getFromValue();
1.84 + from = rate.getToValue();
1.85 + } else {
1.86 + //converting in mornak way
1.87 + from = rate.getFromValue();
1.88 + to = rate.getToValue();
1.89 + }
1.90 +
1.91 + BigDecimal amountCent = amount.movePointRight(2);
1.92 +
1.93 + final BigDecimal multiplied = amountCent.multiply(to,context);
1.94 + BigDecimal[] division = multiplied.divideAndRemainder(from,context);
1.95 +
1.96 + if (!remainderAllowed && !(BigDecimal.ZERO.equals(division[1]))) {
1.97 + throw new RuntimeException("Remained is not allowed - remaining amount is " + division[1]+ " cents");
1.98 + } else {
1.99 + result.setRemainder(BigDecimal.ZERO);
1.100 + }
1.101 +
1.102 + final BigDecimal converted = division[0].movePointLeft(2);
1.103 + result.setConverted(converted);
1.104 + //result.setRemainder(...);
1.105 +
1.106 + return result;
1.107 + }
1.108 +}