1 package org.apidesign.apifest08.currency;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashSet;
8 import org.apidesign.apifest08.currency.Computer.ComputerRequest;
9 import org.apidesign.apifest08.currency.Computer.ComputerResponse;
14 * In Task 1's version provides conversion between currency values
15 * with amount stored in integer or double, that are identified
16 * with string value. Exchange rates are immutable.
18 * In Task2's version provides support for multiple exchange rates
19 * between different currencies & merging exchange rates from
20 * existing convertors into new convertor's instance.
21 * No time for javadoc these features, sorry.
25 public final class Convertor<AmountType, IdentifierType> {
27 Computer<AmountType> computer;
28 List<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates = new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
31 Computer<AmountType> computer,
32 Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
33 this.computer = computer;
35 for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
38 exchangeRate.getCurrencyA().getIdentifier(),
39 exchangeRate.getCurrencyB().getIdentifier()) != null) {
40 throw new IllegalArgumentException("Duplicate exchange rate!");
42 this.exchangeRates.add(exchangeRate);
46 private ExchangeRateValue<AmountType, IdentifierType> findExchangeRate(
47 Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates,
48 IdentifierType currencyA,
49 IdentifierType currencyB) {
50 for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
51 if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) ||
52 (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) {
60 * Convert an amount of the one currency to an amount of the another one currency
61 * with respect to previously specified exchange rates.
63 * @param targetCurrency an identifier of the requested currency
64 * @param currencyValue an amount of the another one currency
65 * @return an amount of the requested currency
67 public CurrencyValue<AmountType, IdentifierType> convert(
68 IdentifierType targetCurrency,
69 CurrencyValue<AmountType, IdentifierType> currencyValue) {
70 ExchangeRateValue<AmountType, IdentifierType> exchangeRate =
71 findExchangeRate(exchangeRates, currencyValue.getIdentifier(), targetCurrency);
72 if (exchangeRate == null) {
73 throw new IllegalArgumentException("Inappropriate currencies to convert!");
76 ComputerRequest<AmountType> computerRequest = new ComputerRequest<AmountType>();
77 computerRequest.setInput(currencyValue.getAmount());
79 IdentifierType targetCurrencyRef; // just for backward compatibility :-(
80 if (exchangeRate.getCurrencyA().getIdentifier().equals(targetCurrency)) {
81 computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
82 computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
83 targetCurrencyRef = exchangeRate.getCurrencyA().getIdentifier();
85 computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
86 computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
87 targetCurrencyRef = exchangeRate.getCurrencyB().getIdentifier();
90 ComputerResponse<AmountType> computerResponse = computer.compute(computerRequest);
91 return CurrencyValue.getCurrencyValue(
92 computerResponse.getResult(),
99 static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
100 Computer<AmountType> computer,
101 Collection<Convertor<AmountType, IdentifierType>> convertors) {
102 Set<ExchangeRateValue<AmountType, IdentifierType>> exchangeRatesSet = new HashSet<ExchangeRateValue<AmountType, IdentifierType>>();
103 for (Convertor<AmountType, IdentifierType> convertor : convertors) {
104 exchangeRatesSet.addAll(convertor.exchangeRates);
106 return getConvertor(computer, exchangeRatesSet);
109 static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
110 Computer<AmountType> computer,
111 Convertor<AmountType, IdentifierType> convertorA,
112 Convertor<AmountType, IdentifierType> convertorB) {
113 Collection<Convertor<AmountType, IdentifierType>> convertors =
114 new ArrayList<Convertor<AmountType, IdentifierType>>();
115 convertors.add(convertorA);
116 convertors.add(convertorB);
117 return mergeConvertors(computer, convertors);
120 public static Convertor<Double, String> mergeConvertorsDoubleString(
121 Collection<Convertor<Double, String>> convertors) {
122 return mergeConvertors(DoubleComputer, convertors);
125 public static Convertor<Double, String> mergeConvertorsDoubleString(
126 Convertor<Double, String> convertorA,
127 Convertor<Double, String> convertorB) {
128 return mergeConvertors(DoubleComputer, convertorA, convertorB);
131 public static Convertor<Integer, String> mergeConvertorsIntegerString(
132 Collection<Convertor<Integer, String>> convertors) {
133 return mergeConvertors(IntegerComputer, convertors);
136 public static Convertor<Integer, String> mergeConvertorsIntegerString(
137 Convertor<Integer, String> convertorA,
138 Convertor<Integer, String> convertorB) {
139 return mergeConvertors(IntegerComputer, convertorA, convertorB);
145 static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
146 Computer<AmountType> computer, Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
147 return new Convertor<AmountType, IdentifierType>(computer, exchangeRates);
150 static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
151 Computer<AmountType> computer, ExchangeRateValue<AmountType, IdentifierType> exchangeRate) {
152 Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates =
153 new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
154 exchangeRates.add(exchangeRate);
155 return getConvertor(computer, exchangeRates);
158 public static Convertor<Double, String> getConvertorDoubleString(
159 Collection<ExchangeRateValue<Double, String>> exchangeRates) {
160 return getConvertor(DoubleComputer, exchangeRates);
163 public static Convertor<Double, String> getConvertorDoubleString(
164 ExchangeRateValue<Double, String> exchangeRate) {
165 return getConvertor(DoubleComputer, exchangeRate);
168 public static Convertor<Integer, String> getConvertorIntegerString(
169 Collection<ExchangeRateValue<Integer, String>> exchangeRates) {
170 return getConvertor(IntegerComputer, exchangeRates);
173 public static Convertor<Integer, String> getConvertorIntegerString(
174 ExchangeRateValue<Integer, String> exchangeRate) {
175 return getConvertor(IntegerComputer, exchangeRate);
179 // BACKWARD COMPATIBILITY - CREATION
182 * Creates convertor for Double|String values with specified exchange rate
183 * between two currencies.
185 * @param firstCurrencyExchangeRate first currency
186 * @param secondCurrencyExchangeRate second currency
189 public static Convertor<Double, String> getConvertorDoubleString(
190 CurrencyValue<Double, String> firstCurrencyExchangeRate,
191 CurrencyValue<Double, String> secondCurrencyExchangeRate) {
192 return getConvertorDoubleString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
196 * Creates convertor for Integer|String values with specified exchange rate
197 * between two currencies.
199 * @param firstCurrencyExchangeRate first currency
200 * @param secondCurrencyExchangeRate second currency
203 public static Convertor<Integer, String> getConvertorIntegerString(
204 CurrencyValue<Integer, String> firstCurrencyExchangeRate,
205 CurrencyValue<Integer, String> secondCurrencyExchangeRate) {
206 return getConvertorIntegerString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
212 static final Computer<Double> DoubleComputer = new Computer<Double>() {
214 public ComputerResponse<Double> compute(ComputerRequest<Double> request) {
215 ComputerResponse<Double> response = new ComputerResponse<Double>();
216 response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());
220 static final Computer<Integer> IntegerComputer = new Computer<Integer>() {
222 public ComputerResponse<Integer> compute(ComputerRequest<Integer> request) {
223 ComputerResponse<Integer> response = new ComputerResponse<Integer>();
224 response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());