1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/task3/solution06/src/org/apidesign/apifest08/currency/Convertor.java Tue Oct 07 11:05:34 2008 +0200
1.3 @@ -0,0 +1,124 @@
1.4 +package org.apidesign.apifest08.currency;
1.5 +
1.6 +import static org.apidesign.apifest08.currency.Assert.notNull;
1.7 +
1.8 +import java.math.BigDecimal;
1.9 +import java.math.RoundingMode;
1.10 +import java.util.ArrayList;
1.11 +import java.util.Currency;
1.12 +import java.util.List;
1.13 +
1.14 +public final class Convertor {
1.15 +
1.16 + private List<ConvertorDelegate> convertorDelegates = new ArrayList<ConvertorDelegate>();
1.17 +
1.18 +
1.19 + /**
1.20 + * Create new instance of the converter for the given currencies and its rate.
1.21 + *
1.22 + * @param rateValue the rate between the first and the second currency
1.23 + * @param currencyFirst the first currency
1.24 + * @param currencySecond the second currency
1.25 + */
1.26 + public Convertor(BigDecimal rateValue, Currency currencyFirst, Currency currencySecond) {
1.27 + notNull(currencyFirst, "currencyFirst");
1.28 + notNull(currencySecond, "currencySecond");
1.29 + notNull(rateValue, "rateValue");
1.30 + convertorDelegates.add(new ConvertorDelegate(rateValue, currencyFirst, currencySecond));
1.31 + }
1.32 +
1.33 + /**
1.34 + * Create new instance of the convertor from the given convertors.
1.35 + * @param convertors the convertors
1.36 + */
1.37 + public Convertor(Convertor... convertors) {
1.38 + notNull(convertors, "convertors");
1.39 + if(convertors.length == 0) {
1.40 + throw new IllegalArgumentException("There must be at least one converter.");
1.41 + }
1.42 +
1.43 + for(Convertor convertor: convertors) {
1.44 + if(convertor != null) {
1.45 + convertorDelegates.addAll(convertor.convertorDelegates);
1.46 + }
1.47 + }
1.48 + }
1.49 +
1.50 + /**
1.51 + * Converts an amount value between the two currencies of this converter.
1.52 + *
1.53 + * @param amount an amount
1.54 + * @param fromCurrency an amount currency
1.55 + * @param toCurrency to a target currency
1.56 + * @return a converted amount value
1.57 + *
1.58 + * @throws ConversionException if the conversion fails
1.59 + * @throws UnsupportedConversionException if the conversion between a given currencies is not supported.
1.60 + */
1.61 + public Amount convert(BigDecimal amount, Currency fromCurrency, Currency toCurrency) throws ConversionException {
1.62 + notNull(amount, "amount");
1.63 + notNull(fromCurrency, "fromCurrency");
1.64 + notNull(toCurrency, "toCurrency");
1.65 + ConvertorDelegate appropriateDelegate = null;
1.66 +
1.67 + //try find an appropriate delegate for conversion
1.68 + for(ConvertorDelegate delegate : convertorDelegates) {
1.69 + if(delegate.isConversionSupported(fromCurrency, toCurrency)) {
1.70 + appropriateDelegate = delegate;
1.71 + break;
1.72 + }
1.73 + }
1.74 +
1.75 + if(appropriateDelegate == null) {
1.76 + throw new UnsupportedConversionException(fromCurrency, toCurrency);
1.77 + }
1.78 +
1.79 + return appropriateDelegate.convert(amount, fromCurrency, toCurrency);
1.80 + }
1.81 +
1.82 + /**
1.83 + * Internal delegate implements a logic for conversion between two currencies
1.84 + * and vice versa.
1.85 + * @see #isConversionSupported(Currency, Currency)
1.86 + */
1.87 + private static class ConvertorDelegate {
1.88 + private final Currency first;
1.89 + private final Currency second;
1.90 + private final BigDecimal rateValue; // a rate between the first currency and the second currency
1.91 + public static final BigDecimal one = new BigDecimal(1);
1.92 +
1.93 + private ConvertorDelegate(BigDecimal rateValue, Currency currencyFirst, Currency currencySecond) {
1.94 + this.rateValue = rateValue;
1.95 + this.first = currencyFirst;
1.96 + this.second = currencySecond;
1.97 + }
1.98 +
1.99 + private Amount convert(BigDecimal amount, Currency fromCurrency, Currency toCurrency) throws ConversionException {
1.100 + BigDecimal rateValue = getRateValue(fromCurrency, toCurrency);
1.101 + BigDecimal result = rateValue.multiply(amount);
1.102 + return new Amount(result, toCurrency);
1.103 + }
1.104 +
1.105 + private BigDecimal getRateValue(Currency fromCurrency, Currency toCurrency) {
1.106 +
1.107 + BigDecimal retVal;
1.108 +
1.109 + if(first == fromCurrency) {
1.110 + retVal = rateValue;
1.111 + } else {
1.112 + //reverse rate
1.113 + retVal = one.divide(rateValue, 10 ,RoundingMode.HALF_UP);
1.114 + }
1.115 +
1.116 + return retVal;
1.117 + }
1.118 +
1.119 + /**
1.120 + * @return <code>true</code> if the delegate is able to convert from the given currency
1.121 + * to the given currency and vice versa otherwise <code>false</code>.
1.122 + */
1.123 + private boolean isConversionSupported(Currency fromCurrency, Currency toCurrency) {
1.124 + return ((fromCurrency == first || fromCurrency == second) && (toCurrency == first || toCurrency == second));
1.125 + }
1.126 + }
1.127 +}