task2/solution11/src/org/apidesign/apifest08/currency/Convertor.java
author japod@localhost
Tue, 07 Oct 2008 00:25:53 +0200
changeset 37 d333e45f6df1
parent 29 f6073056b9fe
permissions -rw-r--r--
adding solution11 for task 2
japod@6
     1
package org.apidesign.apifest08.currency;
japod@6
     2
japod@37
     3
import java.util.ArrayList;
japod@37
     4
import java.util.Collection;
japod@37
     5
import java.util.HashSet;
japod@37
     6
import java.util.List;
japod@37
     7
import java.util.Set;
japod@6
     8
import org.apidesign.apifest08.currency.Computer.ComputerRequest;
japod@6
     9
import org.apidesign.apifest08.currency.Computer.ComputerResponse;
japod@6
    10
japod@6
    11
/**
japod@6
    12
 * Convertor.
japod@6
    13
 * 
japod@6
    14
 * In Task 1's version provides conversion between currency values
japod@6
    15
 * with amount stored in integer or double, that are identified
japod@6
    16
 * with string value. Exchange rates are immutable.
japod@6
    17
 * 
japod@37
    18
 * In Task2's version provides support for multiple exchange rates
japod@37
    19
 * between different currencies & merging exchange rates from
japod@37
    20
 * existing convertors into new convertor's instance.
japod@37
    21
 * No time for javadoc these features, sorry.
japod@37
    22
 * 
japod@6
    23
 * @author ked
japod@6
    24
 */
japod@6
    25
public final class Convertor<AmountType, IdentifierType> {
japod@6
    26
japod@6
    27
    Computer<AmountType> computer;
japod@37
    28
    List<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates = new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
japod@6
    29
japod@6
    30
    Convertor(
japod@6
    31
            Computer<AmountType> computer,
japod@37
    32
            Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
japod@37
    33
        this.computer = computer;
japod@37
    34
japod@37
    35
        for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
japod@37
    36
            if (findExchangeRate(
japod@37
    37
                    this.exchangeRates,
japod@37
    38
                    exchangeRate.getCurrencyA().getIdentifier(),
japod@37
    39
                    exchangeRate.getCurrencyB().getIdentifier()) != null) {
japod@37
    40
                throw new IllegalArgumentException("Duplicate exchange rate!");
japod@37
    41
            }
japod@37
    42
            this.exchangeRates.add(exchangeRate);
japod@19
    43
        }
japod@37
    44
    }
japod@37
    45
japod@37
    46
    private ExchangeRateValue<AmountType, IdentifierType> findExchangeRate(
japod@37
    47
            Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates,
japod@37
    48
            IdentifierType currencyA,
japod@37
    49
            IdentifierType currencyB) {
japod@37
    50
        for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
japod@37
    51
            if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) ||
japod@37
    52
                    (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) {
japod@37
    53
                return exchangeRate;
japod@37
    54
            }
japod@37
    55
        }
japod@37
    56
        return null;
japod@6
    57
    }
japod@6
    58
japod@6
    59
    /**
japod@6
    60
     * Convert an amount of the one currency to an amount of the another one currency
japod@37
    61
     * with respect to previously specified exchange rates.
japod@6
    62
     * 
japod@19
    63
     * @param targetCurrency an identifier of the requested currency
japod@19
    64
     * @param currencyValue an amount of the another one currency
japod@19
    65
     * @return an amount of the requested currency
japod@6
    66
     */
japod@19
    67
    public CurrencyValue<AmountType, IdentifierType> convert(
japod@19
    68
            IdentifierType targetCurrency,
japod@19
    69
            CurrencyValue<AmountType, IdentifierType> currencyValue) {
japod@37
    70
        ExchangeRateValue<AmountType, IdentifierType> exchangeRate =
japod@37
    71
                findExchangeRate(exchangeRates, currencyValue.getIdentifier(), targetCurrency);
japod@37
    72
        if (exchangeRate == null) {
japod@19
    73
            throw new IllegalArgumentException("Inappropriate currencies to convert!");
japod@6
    74
        }
japod@37
    75
japod@37
    76
        ComputerRequest<AmountType> computerRequest = new ComputerRequest<AmountType>();
japod@37
    77
        computerRequest.setInput(currencyValue.getAmount());
japod@37
    78
japod@37
    79
        IdentifierType targetCurrencyRef; // just for backward compatibility :-(
japod@37
    80
        if (exchangeRate.getCurrencyA().getIdentifier().equals(targetCurrency)) {
japod@37
    81
            computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
japod@37
    82
            computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
japod@37
    83
            targetCurrencyRef = exchangeRate.getCurrencyA().getIdentifier();
japod@37
    84
        } else {
japod@37
    85
            computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
japod@37
    86
            computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
japod@37
    87
            targetCurrencyRef = exchangeRate.getCurrencyB().getIdentifier();
japod@37
    88
        }
japod@37
    89
japod@37
    90
        ComputerResponse<AmountType> computerResponse = computer.compute(computerRequest);
japod@37
    91
        return CurrencyValue.getCurrencyValue(
japod@37
    92
                computerResponse.getResult(),
japod@37
    93
                targetCurrencyRef);
japod@37
    94
    }
japod@37
    95
japod@37
    96
    // ---
japod@37
    97
    // MERGING
japod@37
    98
    // ---
japod@37
    99
    static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
japod@37
   100
            Computer<AmountType> computer,
japod@37
   101
            Collection<Convertor<AmountType, IdentifierType>> convertors) {
japod@37
   102
        Set<ExchangeRateValue<AmountType, IdentifierType>> exchangeRatesSet = new HashSet<ExchangeRateValue<AmountType, IdentifierType>>();
japod@37
   103
        for (Convertor<AmountType, IdentifierType> convertor : convertors) {
japod@37
   104
            exchangeRatesSet.addAll(convertor.exchangeRates);
japod@37
   105
        }
japod@37
   106
        return getConvertor(computer, exchangeRatesSet);
japod@37
   107
    }
japod@37
   108
japod@37
   109
    static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
japod@37
   110
            Computer<AmountType> computer,
japod@37
   111
            Convertor<AmountType, IdentifierType> convertorA,
japod@37
   112
            Convertor<AmountType, IdentifierType> convertorB) {
japod@37
   113
        Collection<Convertor<AmountType, IdentifierType>> convertors =
japod@37
   114
                new ArrayList<Convertor<AmountType, IdentifierType>>();
japod@37
   115
        convertors.add(convertorA);
japod@37
   116
        convertors.add(convertorB);
japod@37
   117
        return mergeConvertors(computer, convertors);
japod@37
   118
    }
japod@37
   119
japod@37
   120
    public static Convertor<Double, String> mergeConvertorsDoubleString(
japod@37
   121
            Collection<Convertor<Double, String>> convertors) {
japod@37
   122
        return mergeConvertors(DoubleComputer, convertors);
japod@37
   123
    }
japod@37
   124
japod@37
   125
    public static Convertor<Double, String> mergeConvertorsDoubleString(
japod@37
   126
            Convertor<Double, String> convertorA,
japod@37
   127
            Convertor<Double, String> convertorB) {
japod@37
   128
        return mergeConvertors(DoubleComputer, convertorA, convertorB);
japod@37
   129
    }
japod@37
   130
japod@37
   131
    public static Convertor<Integer, String> mergeConvertorsIntegerString(
japod@37
   132
            Collection<Convertor<Integer, String>> convertors) {
japod@37
   133
        return mergeConvertors(IntegerComputer, convertors);
japod@37
   134
    }
japod@37
   135
japod@37
   136
    public static Convertor<Integer, String> mergeConvertorsIntegerString(
japod@37
   137
            Convertor<Integer, String> convertorA,
japod@37
   138
            Convertor<Integer, String> convertorB) {
japod@37
   139
        return mergeConvertors(IntegerComputer, convertorA, convertorB);
japod@37
   140
    }
japod@37
   141
japod@37
   142
    // ---
japod@37
   143
    // CREATION
japod@37
   144
    // ---
japod@37
   145
    static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
japod@37
   146
            Computer<AmountType> computer, Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
japod@37
   147
        return new Convertor<AmountType, IdentifierType>(computer, exchangeRates);
japod@6
   148
    }
japod@6
   149
japod@6
   150
    static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
japod@37
   151
            Computer<AmountType> computer, ExchangeRateValue<AmountType, IdentifierType> exchangeRate) {
japod@37
   152
        Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates =
japod@37
   153
                new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
japod@37
   154
        exchangeRates.add(exchangeRate);
japod@37
   155
        return getConvertor(computer, exchangeRates);
japod@6
   156
    }
japod@6
   157
    
japod@37
   158
    public static Convertor<Double, String> getConvertorDoubleString(
japod@37
   159
            Collection<ExchangeRateValue<Double, String>> exchangeRates) {
japod@37
   160
        return getConvertor(DoubleComputer, exchangeRates);
japod@37
   161
    }
japod@6
   162
japod@37
   163
    public static Convertor<Double, String> getConvertorDoubleString(
japod@37
   164
            ExchangeRateValue<Double, String> exchangeRate) {
japod@37
   165
        return getConvertor(DoubleComputer, exchangeRate);
japod@37
   166
    }
japod@6
   167
japod@37
   168
    public static Convertor<Integer, String> getConvertorIntegerString(
japod@37
   169
            Collection<ExchangeRateValue<Integer, String>> exchangeRates) {
japod@37
   170
        return getConvertor(IntegerComputer, exchangeRates);
japod@37
   171
    }
japod@37
   172
japod@37
   173
    public static Convertor<Integer, String> getConvertorIntegerString(
japod@37
   174
            ExchangeRateValue<Integer, String> exchangeRate) {
japod@37
   175
        return getConvertor(IntegerComputer, exchangeRate);
japod@37
   176
    }
japod@37
   177
japod@37
   178
    // ---
japod@37
   179
    // BACKWARD COMPATIBILITY - CREATION
japod@37
   180
    // ---
japod@6
   181
    /**
japod@6
   182
     * Creates convertor for Double|String values with specified exchange rate
japod@6
   183
     * between two currencies.
japod@6
   184
     * 
japod@6
   185
     * @param firstCurrencyExchangeRate first currency
japod@6
   186
     * @param secondCurrencyExchangeRate second currency
japod@6
   187
     * @return convertor
japod@6
   188
     */
japod@6
   189
    public static Convertor<Double, String> getConvertorDoubleString(
japod@6
   190
            CurrencyValue<Double, String> firstCurrencyExchangeRate,
japod@6
   191
            CurrencyValue<Double, String> secondCurrencyExchangeRate) {
japod@37
   192
        return getConvertorDoubleString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
japod@6
   193
    }
japod@6
   194
japod@6
   195
    /**
japod@6
   196
     * Creates convertor for Integer|String values with specified exchange rate
japod@6
   197
     * between two currencies.
japod@6
   198
     * 
japod@6
   199
     * @param firstCurrencyExchangeRate first currency
japod@6
   200
     * @param secondCurrencyExchangeRate second currency
japod@6
   201
     * @return convertor
japod@6
   202
     */
japod@6
   203
    public static Convertor<Integer, String> getConvertorIntegerString(
japod@6
   204
            CurrencyValue<Integer, String> firstCurrencyExchangeRate,
japod@6
   205
            CurrencyValue<Integer, String> secondCurrencyExchangeRate) {
japod@37
   206
        return getConvertorIntegerString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
japod@6
   207
    }
japod@37
   208
    
japod@37
   209
    // ---
japod@37
   210
    // COMPUTERS
japod@37
   211
    // ---
japod@37
   212
    static final Computer<Double> DoubleComputer = new Computer<Double>() {
japod@37
   213
japod@37
   214
        public ComputerResponse<Double> compute(ComputerRequest<Double> request) {
japod@37
   215
            ComputerResponse<Double> response = new ComputerResponse<Double>();
japod@37
   216
            response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());
japod@37
   217
            return response;
japod@37
   218
        }
japod@37
   219
    };
japod@37
   220
    static final Computer<Integer> IntegerComputer = new Computer<Integer>() {
japod@37
   221
japod@37
   222
        public ComputerResponse<Integer> compute(ComputerRequest<Integer> request) {
japod@37
   223
            ComputerResponse<Integer> response = new ComputerResponse<Integer>();
japod@37
   224
            response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());
japod@37
   225
            return response;
japod@37
   226
        }
japod@37
   227
    };
japod@6
   228
}