1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/task4/solution11/src/org/apidesign/apifest08/currency/Convertor.java Sat Oct 11 23:38:46 2008 +0200
1.3 @@ -0,0 +1,311 @@
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 + * In Task3's version supports reading of current exchange rates
1.27 + * from data sources. Data sources are merged during convertors' merging
1.28 + * as well as static exchange rates.
1.29 + * No time for javadoc, again.
1.30 + *
1.31 + * @author ked
1.32 + */
1.33 +public final class Convertor<AmountType, IdentifierType> {
1.34 +
1.35 + Computer<AmountType> computer;
1.36 + // each static exchange rate could be a special case of an exchange rate data source
1.37 + List<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates = new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
1.38 + List<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources = new ArrayList<ExchangeRateDataSource<AmountType, IdentifierType>>();
1.39 +
1.40 + Convertor(Computer<AmountType> computer) {
1.41 + this.computer = computer;
1.42 + }
1.43 +
1.44 + void addExchangeRates(Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
1.45 + for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
1.46 + if (isExchangeRate(
1.47 + exchangeRate.getCurrencyA().getIdentifier(),
1.48 + exchangeRate.getCurrencyB().getIdentifier())) {
1.49 + throw new IllegalArgumentException("Duplicate exchange rate!");
1.50 + }
1.51 + this.exchangeRates.add(exchangeRate);
1.52 + }
1.53 + }
1.54 +
1.55 + void addExchangeRateDataSources(Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources) {
1.56 + for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : exchangeRateDataSources) {
1.57 + if (isExchangeRate(
1.58 + exchangeRateDataSource.getCurrencyAIdentifier(),
1.59 + exchangeRateDataSource.getCurrencyBIdentifier())) {
1.60 + throw new IllegalArgumentException("Duplicate exchange rate!");
1.61 + }
1.62 + this.exchangeRateDataSources.add(exchangeRateDataSource);
1.63 + }
1.64 + }
1.65 +
1.66 + ExchangeRateValue<AmountType, IdentifierType> findExchangeRate(
1.67 + IdentifierType currencyA,
1.68 + IdentifierType currencyB) {
1.69 + for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
1.70 + if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) ||
1.71 + (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) {
1.72 + return exchangeRate;
1.73 + }
1.74 + }
1.75 + for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : exchangeRateDataSources) {
1.76 + if ((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) ||
1.77 + (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) {
1.78 + return exchangeRateDataSource.getExchangeRate();
1.79 + }
1.80 + }
1.81 + return null;
1.82 + }
1.83 +
1.84 + boolean isExchangeRate(
1.85 + IdentifierType currencyA,
1.86 + IdentifierType currencyB) {
1.87 + for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
1.88 + if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) ||
1.89 + (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) {
1.90 + return true;
1.91 + }
1.92 + }
1.93 + for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : exchangeRateDataSources) {
1.94 + if ((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) ||
1.95 + (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) {
1.96 + return true;
1.97 + }
1.98 + }
1.99 + return false;
1.100 + }
1.101 +
1.102 + /**
1.103 + * Convert an amount of the one currency to an amount of the another one currency
1.104 + * with respect to previously specified exchange rates.
1.105 + *
1.106 + * @param targetCurrency an identifier of the requested currency
1.107 + * @param currencyValue an amount of the another one currency
1.108 + * @return an amount of the requested currency
1.109 + */
1.110 + public CurrencyValue<AmountType, IdentifierType> convert(
1.111 + IdentifierType targetCurrency,
1.112 + CurrencyValue<AmountType, IdentifierType> currencyValue) {
1.113 + ExchangeRateValue<AmountType, IdentifierType> exchangeRate =
1.114 + findExchangeRate(currencyValue.getIdentifier(), targetCurrency);
1.115 + if (exchangeRate == null) {
1.116 + throw new IllegalArgumentException("Inappropriate currencies to convert!");
1.117 + }
1.118 +
1.119 + ComputerRequest<AmountType> computerRequest = new ComputerRequest<AmountType>();
1.120 + computerRequest.setInput(currencyValue.getAmount());
1.121 +
1.122 + IdentifierType targetCurrencyRef; // just for backward compatibility :-(
1.123 + if (exchangeRate.getCurrencyA().getIdentifier().equals(targetCurrency)) {
1.124 + computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
1.125 + computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
1.126 + targetCurrencyRef = exchangeRate.getCurrencyA().getIdentifier();
1.127 + } else {
1.128 + computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
1.129 + computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
1.130 + targetCurrencyRef = exchangeRate.getCurrencyB().getIdentifier();
1.131 + }
1.132 +
1.133 + ComputerResponse<AmountType> computerResponse = new ComputerResponse<AmountType>();
1.134 + computer.compute(computerRequest, computerResponse);
1.135 +
1.136 + return CurrencyValue.getCurrencyValue(
1.137 + computerResponse.getResult(),
1.138 + targetCurrencyRef);
1.139 + }
1.140 +
1.141 + // ---
1.142 + // MERGING
1.143 + // ---
1.144 + static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
1.145 + Computer<AmountType> computer,
1.146 + Collection<Convertor<AmountType, IdentifierType>> convertors) {
1.147 + Set<ExchangeRateValue<AmountType, IdentifierType>> exchangeRatesSet = new HashSet<ExchangeRateValue<AmountType, IdentifierType>>();
1.148 + Set<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSourcesSet = new HashSet<ExchangeRateDataSource<AmountType, IdentifierType>>();
1.149 + for (Convertor<AmountType, IdentifierType> convertor : convertors) {
1.150 + exchangeRatesSet.addAll(convertor.exchangeRates);
1.151 + }
1.152 + for (Convertor<AmountType, IdentifierType> convertor : convertors) {
1.153 + exchangeRateDataSourcesSet.addAll(convertor.exchangeRateDataSources);
1.154 + }
1.155 +
1.156 + Convertor<AmountType, IdentifierType> c = new Convertor<AmountType, IdentifierType>(computer);
1.157 + c.addExchangeRates(exchangeRatesSet);
1.158 + c.addExchangeRateDataSources(exchangeRateDataSourcesSet);
1.159 + return c;
1.160 + }
1.161 +
1.162 + static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
1.163 + Computer<AmountType> computer,
1.164 + Convertor<AmountType, IdentifierType> convertorA,
1.165 + Convertor<AmountType, IdentifierType> convertorB) {
1.166 + Collection<Convertor<AmountType, IdentifierType>> convertors =
1.167 + new ArrayList<Convertor<AmountType, IdentifierType>>();
1.168 + convertors.add(convertorA);
1.169 + convertors.add(convertorB);
1.170 + return mergeConvertors(computer, convertors);
1.171 + }
1.172 +
1.173 + public static Convertor<Double, String> mergeConvertorsDoubleString(
1.174 + Collection<Convertor<Double, String>> convertors) {
1.175 + return mergeConvertors(DoubleComputer, convertors);
1.176 + }
1.177 +
1.178 + public static Convertor<Double, String> mergeConvertorsDoubleString(
1.179 + Convertor<Double, String> convertorA,
1.180 + Convertor<Double, String> convertorB) {
1.181 + return mergeConvertors(DoubleComputer, convertorA, convertorB);
1.182 + }
1.183 +
1.184 + public static Convertor<Integer, String> mergeConvertorsIntegerString(
1.185 + Collection<Convertor<Integer, String>> convertors) {
1.186 + return mergeConvertors(IntegerComputer, convertors);
1.187 + }
1.188 +
1.189 + public static Convertor<Integer, String> mergeConvertorsIntegerString(
1.190 + Convertor<Integer, String> convertorA,
1.191 + Convertor<Integer, String> convertorB) {
1.192 + return mergeConvertors(IntegerComputer, convertorA, convertorB);
1.193 + }
1.194 +
1.195 + // ---
1.196 + // CREATION
1.197 + // ---
1.198 + static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
1.199 + Computer<AmountType> computer, Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
1.200 + Convertor<AmountType, IdentifierType> c = new Convertor<AmountType, IdentifierType>(computer);
1.201 + c.addExchangeRates(exchangeRates);
1.202 + return c;
1.203 + }
1.204 +
1.205 + static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertorDataSource(
1.206 + Computer<AmountType> computer, Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources) {
1.207 + Convertor<AmountType, IdentifierType> c = new Convertor<AmountType, IdentifierType>(computer);
1.208 + c.addExchangeRateDataSources(exchangeRateDataSources);
1.209 + return c;
1.210 + }
1.211 +
1.212 + static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
1.213 + Computer<AmountType> computer, ExchangeRateValue<AmountType, IdentifierType> exchangeRate) {
1.214 + Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates =
1.215 + new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
1.216 + exchangeRates.add(exchangeRate);
1.217 + return getConvertor(computer, exchangeRates);
1.218 + }
1.219 +
1.220 + static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertorDataSource(
1.221 + Computer<AmountType> computer, ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource) {
1.222 + Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources =
1.223 + new ArrayList<ExchangeRateDataSource<AmountType, IdentifierType>>();
1.224 + exchangeRateDataSources.add(exchangeRateDataSource);
1.225 + return getConvertorDataSource(computer, exchangeRateDataSources);
1.226 + }
1.227 +
1.228 + public static Convertor<Double, String> getConvertorDoubleString(
1.229 + Collection<ExchangeRateValue<Double, String>> exchangeRates) {
1.230 + return getConvertor(DoubleComputer, exchangeRates);
1.231 + }
1.232 +
1.233 + public static Convertor<Double, String> getConvertorDoubleString(
1.234 + ExchangeRateValue<Double, String> exchangeRate) {
1.235 + return getConvertor(DoubleComputer, exchangeRate);
1.236 + }
1.237 +
1.238 + public static Convertor<Double, String> getConvertorDataSourceDoubleString(
1.239 + Collection<ExchangeRateDataSource<Double, String>> exchangeRateDataSources) {
1.240 + return getConvertorDataSource(DoubleComputer, exchangeRateDataSources);
1.241 + }
1.242 +
1.243 + public static Convertor<Double, String> getConvertorDataSourceDoubleString(
1.244 + ExchangeRateDataSource<Double, String> exchangeRateDataSource) {
1.245 + return getConvertorDataSource(DoubleComputer, exchangeRateDataSource);
1.246 + }
1.247 +
1.248 + public static Convertor<Integer, String> getConvertorIntegerString(
1.249 + Collection<ExchangeRateValue<Integer, String>> exchangeRates) {
1.250 + return getConvertor(IntegerComputer, exchangeRates);
1.251 + }
1.252 +
1.253 + public static Convertor<Integer, String> getConvertorIntegerString(
1.254 + ExchangeRateValue<Integer, String> exchangeRate) {
1.255 + return getConvertor(IntegerComputer, exchangeRate);
1.256 + }
1.257 +
1.258 + public static Convertor<Integer, String> getConvertorDataSourceIntegerString(
1.259 + Collection<ExchangeRateDataSource<Integer, String>> exchangeRateDataSources) {
1.260 + return getConvertorDataSource(IntegerComputer, exchangeRateDataSources);
1.261 + }
1.262 +
1.263 + public static Convertor<Integer, String> getConvertorDataSourceIntegerString(
1.264 + ExchangeRateDataSource<Integer, String> exchangeRateDataSource) {
1.265 + return getConvertorDataSource(IntegerComputer, exchangeRateDataSource);
1.266 + }
1.267 +
1.268 + // ---
1.269 + // BACKWARD COMPATIBILITY - CREATION
1.270 + // ---
1.271 + /**
1.272 + * Creates convertor for Double|String values with specified exchange rate
1.273 + * between two currencies.
1.274 + *
1.275 + * @param firstCurrencyExchangeRate first currency
1.276 + * @param secondCurrencyExchangeRate second currency
1.277 + * @return convertor
1.278 + */
1.279 + public static Convertor<Double, String> getConvertorDoubleString(
1.280 + CurrencyValue<Double, String> firstCurrencyExchangeRate,
1.281 + CurrencyValue<Double, String> secondCurrencyExchangeRate) {
1.282 + return getConvertorDoubleString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
1.283 + }
1.284 +
1.285 + /**
1.286 + * Creates convertor for Integer|String values with specified exchange rate
1.287 + * between two currencies.
1.288 + *
1.289 + * @param firstCurrencyExchangeRate first currency
1.290 + * @param secondCurrencyExchangeRate second currency
1.291 + * @return convertor
1.292 + */
1.293 + public static Convertor<Integer, String> getConvertorIntegerString(
1.294 + CurrencyValue<Integer, String> firstCurrencyExchangeRate,
1.295 + CurrencyValue<Integer, String> secondCurrencyExchangeRate) {
1.296 + return getConvertorIntegerString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
1.297 + }
1.298 +
1.299 + // ---
1.300 + // COMPUTERS
1.301 + // ---
1.302 + static final Computer<Double> DoubleComputer = new Computer<Double>() {
1.303 +
1.304 + public void compute(ComputerRequest<Double> request, ComputerResponse<Double> response) {
1.305 + response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());
1.306 + }
1.307 + };
1.308 + static final Computer<Integer> IntegerComputer = new Computer<Integer>() {
1.309 +
1.310 + public void compute(ComputerRequest<Integer> request, ComputerResponse<Integer> response) {
1.311 + response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());
1.312 + }
1.313 + };
1.314 +}