1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/task3/solution11/src/org/apidesign/apifest08/currency/Convertor.java Tue Oct 07 11:05:34 2008 +0200
1.3 @@ -0,0 +1,228 @@
1.4 +package org.apidesign.apifest08.currency;
1.5 +
1.6 +import java.util.ArrayList;
1.7 +import java.util.Collection;
1.8 +import java.util.HashSet;
1.9 +import java.util.List;
1.10 +import java.util.Set;
1.11 +import org.apidesign.apifest08.currency.Computer.ComputerRequest;
1.12 +import org.apidesign.apifest08.currency.Computer.ComputerResponse;
1.13 +
1.14 +/**
1.15 + * Convertor.
1.16 + *
1.17 + * In Task 1's version provides conversion between currency values
1.18 + * with amount stored in integer or double, that are identified
1.19 + * with string value. Exchange rates are immutable.
1.20 + *
1.21 + * In Task2's version provides support for multiple exchange rates
1.22 + * between different currencies & merging exchange rates from
1.23 + * existing convertors into new convertor's instance.
1.24 + * No time for javadoc these features, sorry.
1.25 + *
1.26 + * @author ked
1.27 + */
1.28 +public final class Convertor<AmountType, IdentifierType> {
1.29 +
1.30 + Computer<AmountType> computer;
1.31 + List<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates = new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
1.32 +
1.33 + Convertor(
1.34 + Computer<AmountType> computer,
1.35 + Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
1.36 + this.computer = computer;
1.37 +
1.38 + for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
1.39 + if (findExchangeRate(
1.40 + this.exchangeRates,
1.41 + exchangeRate.getCurrencyA().getIdentifier(),
1.42 + exchangeRate.getCurrencyB().getIdentifier()) != null) {
1.43 + throw new IllegalArgumentException("Duplicate exchange rate!");
1.44 + }
1.45 + this.exchangeRates.add(exchangeRate);
1.46 + }
1.47 + }
1.48 +
1.49 + private ExchangeRateValue<AmountType, IdentifierType> findExchangeRate(
1.50 + Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates,
1.51 + IdentifierType currencyA,
1.52 + IdentifierType currencyB) {
1.53 + for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
1.54 + if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) ||
1.55 + (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) {
1.56 + return exchangeRate;
1.57 + }
1.58 + }
1.59 + return null;
1.60 + }
1.61 +
1.62 + /**
1.63 + * Convert an amount of the one currency to an amount of the another one currency
1.64 + * with respect to previously specified exchange rates.
1.65 + *
1.66 + * @param targetCurrency an identifier of the requested currency
1.67 + * @param currencyValue an amount of the another one currency
1.68 + * @return an amount of the requested currency
1.69 + */
1.70 + public CurrencyValue<AmountType, IdentifierType> convert(
1.71 + IdentifierType targetCurrency,
1.72 + CurrencyValue<AmountType, IdentifierType> currencyValue) {
1.73 + ExchangeRateValue<AmountType, IdentifierType> exchangeRate =
1.74 + findExchangeRate(exchangeRates, currencyValue.getIdentifier(), targetCurrency);
1.75 + if (exchangeRate == null) {
1.76 + throw new IllegalArgumentException("Inappropriate currencies to convert!");
1.77 + }
1.78 +
1.79 + ComputerRequest<AmountType> computerRequest = new ComputerRequest<AmountType>();
1.80 + computerRequest.setInput(currencyValue.getAmount());
1.81 +
1.82 + IdentifierType targetCurrencyRef; // just for backward compatibility :-(
1.83 + if (exchangeRate.getCurrencyA().getIdentifier().equals(targetCurrency)) {
1.84 + computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
1.85 + computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
1.86 + targetCurrencyRef = exchangeRate.getCurrencyA().getIdentifier();
1.87 + } else {
1.88 + computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
1.89 + computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
1.90 + targetCurrencyRef = exchangeRate.getCurrencyB().getIdentifier();
1.91 + }
1.92 +
1.93 + ComputerResponse<AmountType> computerResponse = computer.compute(computerRequest);
1.94 + return CurrencyValue.getCurrencyValue(
1.95 + computerResponse.getResult(),
1.96 + targetCurrencyRef);
1.97 + }
1.98 +
1.99 + // ---
1.100 + // MERGING
1.101 + // ---
1.102 + static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
1.103 + Computer<AmountType> computer,
1.104 + Collection<Convertor<AmountType, IdentifierType>> convertors) {
1.105 + Set<ExchangeRateValue<AmountType, IdentifierType>> exchangeRatesSet = new HashSet<ExchangeRateValue<AmountType, IdentifierType>>();
1.106 + for (Convertor<AmountType, IdentifierType> convertor : convertors) {
1.107 + exchangeRatesSet.addAll(convertor.exchangeRates);
1.108 + }
1.109 + return getConvertor(computer, exchangeRatesSet);
1.110 + }
1.111 +
1.112 + static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
1.113 + Computer<AmountType> computer,
1.114 + Convertor<AmountType, IdentifierType> convertorA,
1.115 + Convertor<AmountType, IdentifierType> convertorB) {
1.116 + Collection<Convertor<AmountType, IdentifierType>> convertors =
1.117 + new ArrayList<Convertor<AmountType, IdentifierType>>();
1.118 + convertors.add(convertorA);
1.119 + convertors.add(convertorB);
1.120 + return mergeConvertors(computer, convertors);
1.121 + }
1.122 +
1.123 + public static Convertor<Double, String> mergeConvertorsDoubleString(
1.124 + Collection<Convertor<Double, String>> convertors) {
1.125 + return mergeConvertors(DoubleComputer, convertors);
1.126 + }
1.127 +
1.128 + public static Convertor<Double, String> mergeConvertorsDoubleString(
1.129 + Convertor<Double, String> convertorA,
1.130 + Convertor<Double, String> convertorB) {
1.131 + return mergeConvertors(DoubleComputer, convertorA, convertorB);
1.132 + }
1.133 +
1.134 + public static Convertor<Integer, String> mergeConvertorsIntegerString(
1.135 + Collection<Convertor<Integer, String>> convertors) {
1.136 + return mergeConvertors(IntegerComputer, convertors);
1.137 + }
1.138 +
1.139 + public static Convertor<Integer, String> mergeConvertorsIntegerString(
1.140 + Convertor<Integer, String> convertorA,
1.141 + Convertor<Integer, String> convertorB) {
1.142 + return mergeConvertors(IntegerComputer, convertorA, convertorB);
1.143 + }
1.144 +
1.145 + // ---
1.146 + // CREATION
1.147 + // ---
1.148 + static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
1.149 + Computer<AmountType> computer, Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
1.150 + return new Convertor<AmountType, IdentifierType>(computer, exchangeRates);
1.151 + }
1.152 +
1.153 + static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
1.154 + Computer<AmountType> computer, ExchangeRateValue<AmountType, IdentifierType> exchangeRate) {
1.155 + Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates =
1.156 + new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
1.157 + exchangeRates.add(exchangeRate);
1.158 + return getConvertor(computer, exchangeRates);
1.159 + }
1.160 +
1.161 + public static Convertor<Double, String> getConvertorDoubleString(
1.162 + Collection<ExchangeRateValue<Double, String>> exchangeRates) {
1.163 + return getConvertor(DoubleComputer, exchangeRates);
1.164 + }
1.165 +
1.166 + public static Convertor<Double, String> getConvertorDoubleString(
1.167 + ExchangeRateValue<Double, String> exchangeRate) {
1.168 + return getConvertor(DoubleComputer, exchangeRate);
1.169 + }
1.170 +
1.171 + public static Convertor<Integer, String> getConvertorIntegerString(
1.172 + Collection<ExchangeRateValue<Integer, String>> exchangeRates) {
1.173 + return getConvertor(IntegerComputer, exchangeRates);
1.174 + }
1.175 +
1.176 + public static Convertor<Integer, String> getConvertorIntegerString(
1.177 + ExchangeRateValue<Integer, String> exchangeRate) {
1.178 + return getConvertor(IntegerComputer, exchangeRate);
1.179 + }
1.180 +
1.181 + // ---
1.182 + // BACKWARD COMPATIBILITY - CREATION
1.183 + // ---
1.184 + /**
1.185 + * Creates convertor for Double|String values with specified exchange rate
1.186 + * between two currencies.
1.187 + *
1.188 + * @param firstCurrencyExchangeRate first currency
1.189 + * @param secondCurrencyExchangeRate second currency
1.190 + * @return convertor
1.191 + */
1.192 + public static Convertor<Double, String> getConvertorDoubleString(
1.193 + CurrencyValue<Double, String> firstCurrencyExchangeRate,
1.194 + CurrencyValue<Double, String> secondCurrencyExchangeRate) {
1.195 + return getConvertorDoubleString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
1.196 + }
1.197 +
1.198 + /**
1.199 + * Creates convertor for Integer|String values with specified exchange rate
1.200 + * between two currencies.
1.201 + *
1.202 + * @param firstCurrencyExchangeRate first currency
1.203 + * @param secondCurrencyExchangeRate second currency
1.204 + * @return convertor
1.205 + */
1.206 + public static Convertor<Integer, String> getConvertorIntegerString(
1.207 + CurrencyValue<Integer, String> firstCurrencyExchangeRate,
1.208 + CurrencyValue<Integer, String> secondCurrencyExchangeRate) {
1.209 + return getConvertorIntegerString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
1.210 + }
1.211 +
1.212 + // ---
1.213 + // COMPUTERS
1.214 + // ---
1.215 + static final Computer<Double> DoubleComputer = new Computer<Double>() {
1.216 +
1.217 + public ComputerResponse<Double> compute(ComputerRequest<Double> request) {
1.218 + ComputerResponse<Double> response = new ComputerResponse<Double>();
1.219 + response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());
1.220 + return response;
1.221 + }
1.222 + };
1.223 + static final Computer<Integer> IntegerComputer = new Computer<Integer>() {
1.224 +
1.225 + public ComputerResponse<Integer> compute(ComputerRequest<Integer> request) {
1.226 + ComputerResponse<Integer> response = new ComputerResponse<Integer>();
1.227 + response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());
1.228 + return response;
1.229 + }
1.230 + };
1.231 +}