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