task2/solution13/src/org/apidesign/apifest08/currency/Convertor.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 01 Oct 2008 10:43:05 +0200
changeset 29 f6073056b9fe
parent 23 task1/solution13/src/org/apidesign/apifest08/currency/Convertor.java@f4b4f95ae1bd
child 41 a7e6f84fb078
permissions -rw-r--r--
Getting ready for task2: copying all solutions to new locations
japod@23
     1
package org.apidesign.apifest08.currency;
japod@23
     2
japod@23
     3
import java.math.BigDecimal;
japod@23
     4
import java.math.MathContext;
japod@23
     5
import java.math.RoundingMode;
japod@23
     6
japod@23
     7
/** Convertor able to convert amount from one currency to other currency.
japod@23
     8
 * 
japod@23
     9
 * Exchange rate is provided by {@link ExchangeRateProvider}.
japod@23
    10
 */
japod@23
    11
public class Convertor {
japod@23
    12
    boolean remainderAllowed = false; //if false, remained is not allowed (should be true ideally, but can't handle it now)
japod@23
    13
    ExchangeRateProvider exchangeRateProvider; 
japod@23
    14
    
japod@23
    15
    private Convertor() {
japod@23
    16
        
japod@23
    17
    }
japod@23
    18
    
japod@23
    19
    /**
japod@23
    20
     * Static method used to create convertor.
japod@23
    21
     * 
japod@23
    22
     * @param exchangeRateProvider {@link ExchangeRateProvider} used to get exchange rate.
japod@23
    23
     * 
japod@23
    24
     * @return Returns <code>Convertor</code> which can be used to convert money.
japod@23
    25
     */
japod@23
    26
    public static Convertor createConvertor(ExchangeRateProvider exchangeRateProvider) {
japod@23
    27
        Convertor c = new Convertor();
japod@23
    28
japod@23
    29
        c.exchangeRateProvider = exchangeRateProvider;
japod@23
    30
        return c;
japod@23
    31
    }
japod@23
    32
    
japod@23
    33
    /**
japod@23
    34
     * Convert <code>amount</code> from <code>fromCurrency</code> to <code>toCurrency</code> as specified
japod@23
    35
     * in <code>ExchangeRateProvider</code>.
japod@23
    36
     * 
japod@23
    37
     * @param amount Amount which should be converted. Can't be negative value (can be zero or positive).
japod@23
    38
     * @return Return <code>ConversionResult</code> which holds conversion result.
japod@23
    39
     */
japod@23
    40
    public ConversionResult convert(BigDecimal amount) {
japod@23
    41
        return convertValue(amount, false);
japod@23
    42
    }
japod@23
    43
    
japod@23
    44
    /**
japod@23
    45
     * Convert <code>amount</code> from <code>toCurrency</code> to <code>fromCurrency</code> as specified
japod@23
    46
     * in <code>ExchangeRateProvider</code>. This is <em>reverted</em> order than suggested by  names of currency fields in <code>ExchangeRate</code>.
japod@23
    47
     * 
japod@23
    48
     * @param amount Amount which should be converted. Can't be negative value (can be zero or positive).
japod@23
    49
     * @return Return <code>ConversionResult</code> which holds conversion result.
japod@23
    50
     */
japod@23
    51
    public ConversionResult convertBack(BigDecimal amount) {
japod@23
    52
        return convertValue(amount, true);
japod@23
    53
    }
japod@23
    54
japod@23
    55
    private ConversionResult convertValue(BigDecimal amount, boolean convertBack) throws RuntimeException {
japod@23
    56
        ConversionResult result = new ConversionResult();
japod@23
    57
        
japod@23
    58
        ExchangeRate rate = exchangeRateProvider.getExchangeRate();
japod@23
    59
        int fromFranctionDigits = exchangeRateProvider.getFromCurrency().getDefaultFractionDigits();
japod@23
    60
        int toFractionDigits = exchangeRateProvider.getToCurrency().getDefaultFractionDigits();
japod@23
    61
         
japod@23
    62
        if (toFractionDigits!=2) {
japod@23
    63
            throw new RuntimeException("Can't process currency with defaultFractionDigits!=2, "+exchangeRateProvider.getToCurrency()+" has "+toFractionDigits+" defaultFractionDigits");
japod@23
    64
        }
japod@23
    65
        if (fromFranctionDigits!=2) {
japod@23
    66
            throw new RuntimeException("Can't process currency with defaultFractionDigits!=2, "+exchangeRateProvider.getFromCurrency()+" has "+fromFranctionDigits+" defaultFractionDigits");
japod@23
    67
        }
japod@23
    68
        
japod@23
    69
        if (amount.signum()==-1) {
japod@23
    70
            throw new RuntimeException("Can convert only non-negative value, current value is "+amount);
japod@23
    71
        }
japod@23
    72
        
japod@23
    73
        
japod@23
    74
        MathContext context = new MathContext(0, RoundingMode.DOWN);
japod@23
    75
        
japod@23
    76
        BigDecimal from;
japod@23
    77
        BigDecimal to;
japod@23
    78
        if (convertBack) {
japod@23
    79
            //converting in reverted way
japod@23
    80
            to = rate.getFromValue();
japod@23
    81
            from = rate.getToValue();
japod@23
    82
        } else {
japod@23
    83
            //converting in mornak way
japod@23
    84
            from = rate.getFromValue();
japod@23
    85
            to = rate.getToValue();
japod@23
    86
        }
japod@23
    87
japod@23
    88
        BigDecimal amountCent = amount.movePointRight(2);
japod@23
    89
        
japod@23
    90
        final BigDecimal multiplied = amountCent.multiply(to,context);
japod@23
    91
        BigDecimal[] division = multiplied.divideAndRemainder(from,context);
japod@23
    92
japod@23
    93
        if (!remainderAllowed && !(BigDecimal.ZERO.equals(division[1]))) {
japod@23
    94
            throw new RuntimeException("Remained is not allowed - remaining amount is " + division[1]+ " cents");
japod@23
    95
        } else {
japod@23
    96
            result.setRemainder(BigDecimal.ZERO);
japod@23
    97
        }
japod@23
    98
        
japod@23
    99
        final BigDecimal converted = division[0].movePointLeft(2);        
japod@23
   100
        result.setConverted(converted);
japod@23
   101
        //result.setRemainder(...);
japod@23
   102
japod@23
   103
        return result;
japod@23
   104
    }
japod@23
   105
}