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.
23 * In Task3's version supports reading of current exchange rates
24 * from data sources. Data sources are merged during convertors' merging
25 * as well as static exchange rates.
26 * No time for javadoc, again.
30 public final class Convertor<AmountType, IdentifierType> {
32 Computer<AmountType> computer;
33 // each static exchange rate could be a special case of an exchange rate data source
34 List<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates = new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
35 List<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources = new ArrayList<ExchangeRateDataSource<AmountType, IdentifierType>>();
37 Convertor(Computer<AmountType> computer) {
38 this.computer = computer;
41 void addExchangeRates(Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
42 for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
44 exchangeRate.getCurrencyA().getIdentifier(),
45 exchangeRate.getCurrencyB().getIdentifier())) {
46 throw new IllegalArgumentException("Duplicate exchange rate!");
48 this.exchangeRates.add(exchangeRate);
52 void addExchangeRateDataSources(Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources) {
53 for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : exchangeRateDataSources) {
55 exchangeRateDataSource.getCurrencyAIdentifier(),
56 exchangeRateDataSource.getCurrencyBIdentifier())) {
57 throw new IllegalArgumentException("Duplicate exchange rate!");
59 this.exchangeRateDataSources.add(exchangeRateDataSource);
63 ExchangeRateValue<AmountType, IdentifierType> findExchangeRate(
64 IdentifierType currencyA,
65 IdentifierType currencyB) {
66 for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
67 if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) ||
68 (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) {
72 for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : exchangeRateDataSources) {
73 if ((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) ||
74 (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) {
75 return exchangeRateDataSource.getExchangeRate();
81 boolean isExchangeRate(
82 IdentifierType currencyA,
83 IdentifierType currencyB) {
84 for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
85 if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) ||
86 (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) {
90 for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : exchangeRateDataSources) {
91 if ((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) ||
92 (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) {
100 * Convert an amount of the one currency to an amount of the another one currency
101 * with respect to previously specified exchange rates.
103 * @param targetCurrency an identifier of the requested currency
104 * @param currencyValue an amount of the another one currency
105 * @return an amount of the requested currency
107 public CurrencyValue<AmountType, IdentifierType> convert(
108 IdentifierType targetCurrency,
109 CurrencyValue<AmountType, IdentifierType> currencyValue) {
110 ExchangeRateValue<AmountType, IdentifierType> exchangeRate =
111 findExchangeRate(currencyValue.getIdentifier(), targetCurrency);
112 if (exchangeRate == null) {
113 throw new IllegalArgumentException("Inappropriate currencies to convert!");
116 ComputerRequest<AmountType> computerRequest = new ComputerRequest<AmountType>();
117 computerRequest.setInput(currencyValue.getAmount());
119 IdentifierType targetCurrencyRef; // just for backward compatibility :-(
120 if (exchangeRate.getCurrencyA().getIdentifier().equals(targetCurrency)) {
121 computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
122 computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
123 targetCurrencyRef = exchangeRate.getCurrencyA().getIdentifier();
125 computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
126 computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
127 targetCurrencyRef = exchangeRate.getCurrencyB().getIdentifier();
130 ComputerResponse<AmountType> computerResponse = new ComputerResponse<AmountType>();
131 computer.compute(computerRequest, computerResponse);
133 return CurrencyValue.getCurrencyValue(
134 computerResponse.getResult(),
141 static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
142 Computer<AmountType> computer,
143 Collection<Convertor<AmountType, IdentifierType>> convertors) {
144 Set<ExchangeRateValue<AmountType, IdentifierType>> exchangeRatesSet = new HashSet<ExchangeRateValue<AmountType, IdentifierType>>();
145 Set<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSourcesSet = new HashSet<ExchangeRateDataSource<AmountType, IdentifierType>>();
146 for (Convertor<AmountType, IdentifierType> convertor : convertors) {
147 exchangeRatesSet.addAll(convertor.exchangeRates);
149 for (Convertor<AmountType, IdentifierType> convertor : convertors) {
150 exchangeRateDataSourcesSet.addAll(convertor.exchangeRateDataSources);
153 Convertor<AmountType, IdentifierType> c = new Convertor<AmountType, IdentifierType>(computer);
154 c.addExchangeRates(exchangeRatesSet);
155 c.addExchangeRateDataSources(exchangeRateDataSourcesSet);
159 static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
160 Computer<AmountType> computer,
161 Convertor<AmountType, IdentifierType> convertorA,
162 Convertor<AmountType, IdentifierType> convertorB) {
163 Collection<Convertor<AmountType, IdentifierType>> convertors =
164 new ArrayList<Convertor<AmountType, IdentifierType>>();
165 convertors.add(convertorA);
166 convertors.add(convertorB);
167 return mergeConvertors(computer, convertors);
170 public static Convertor<Double, String> mergeConvertorsDoubleString(
171 Collection<Convertor<Double, String>> convertors) {
172 return mergeConvertors(DoubleComputer, convertors);
175 public static Convertor<Double, String> mergeConvertorsDoubleString(
176 Convertor<Double, String> convertorA,
177 Convertor<Double, String> convertorB) {
178 return mergeConvertors(DoubleComputer, convertorA, convertorB);
181 public static Convertor<Integer, String> mergeConvertorsIntegerString(
182 Collection<Convertor<Integer, String>> convertors) {
183 return mergeConvertors(IntegerComputer, convertors);
186 public static Convertor<Integer, String> mergeConvertorsIntegerString(
187 Convertor<Integer, String> convertorA,
188 Convertor<Integer, String> convertorB) {
189 return mergeConvertors(IntegerComputer, convertorA, convertorB);
195 static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
196 Computer<AmountType> computer, Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
197 Convertor<AmountType, IdentifierType> c = new Convertor<AmountType, IdentifierType>(computer);
198 c.addExchangeRates(exchangeRates);
202 static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertorDataSource(
203 Computer<AmountType> computer, Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources) {
204 Convertor<AmountType, IdentifierType> c = new Convertor<AmountType, IdentifierType>(computer);
205 c.addExchangeRateDataSources(exchangeRateDataSources);
209 static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
210 Computer<AmountType> computer, ExchangeRateValue<AmountType, IdentifierType> exchangeRate) {
211 Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates =
212 new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
213 exchangeRates.add(exchangeRate);
214 return getConvertor(computer, exchangeRates);
217 static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertorDataSource(
218 Computer<AmountType> computer, ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource) {
219 Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources =
220 new ArrayList<ExchangeRateDataSource<AmountType, IdentifierType>>();
221 exchangeRateDataSources.add(exchangeRateDataSource);
222 return getConvertorDataSource(computer, exchangeRateDataSources);
225 public static Convertor<Double, String> getConvertorDoubleString(
226 Collection<ExchangeRateValue<Double, String>> exchangeRates) {
227 return getConvertor(DoubleComputer, exchangeRates);
230 public static Convertor<Double, String> getConvertorDoubleString(
231 ExchangeRateValue<Double, String> exchangeRate) {
232 return getConvertor(DoubleComputer, exchangeRate);
235 public static Convertor<Double, String> getConvertorDataSourceDoubleString(
236 Collection<ExchangeRateDataSource<Double, String>> exchangeRateDataSources) {
237 return getConvertorDataSource(DoubleComputer, exchangeRateDataSources);
240 public static Convertor<Double, String> getConvertorDataSourceDoubleString(
241 ExchangeRateDataSource<Double, String> exchangeRateDataSource) {
242 return getConvertorDataSource(DoubleComputer, exchangeRateDataSource);
245 public static Convertor<Integer, String> getConvertorIntegerString(
246 Collection<ExchangeRateValue<Integer, String>> exchangeRates) {
247 return getConvertor(IntegerComputer, exchangeRates);
250 public static Convertor<Integer, String> getConvertorIntegerString(
251 ExchangeRateValue<Integer, String> exchangeRate) {
252 return getConvertor(IntegerComputer, exchangeRate);
255 public static Convertor<Integer, String> getConvertorDataSourceIntegerString(
256 Collection<ExchangeRateDataSource<Integer, String>> exchangeRateDataSources) {
257 return getConvertorDataSource(IntegerComputer, exchangeRateDataSources);
260 public static Convertor<Integer, String> getConvertorDataSourceIntegerString(
261 ExchangeRateDataSource<Integer, String> exchangeRateDataSource) {
262 return getConvertorDataSource(IntegerComputer, exchangeRateDataSource);
266 // BACKWARD COMPATIBILITY - CREATION
269 * Creates convertor for Double|String values with specified exchange rate
270 * between two currencies.
272 * @param firstCurrencyExchangeRate first currency
273 * @param secondCurrencyExchangeRate second currency
276 public static Convertor<Double, String> getConvertorDoubleString(
277 CurrencyValue<Double, String> firstCurrencyExchangeRate,
278 CurrencyValue<Double, String> secondCurrencyExchangeRate) {
279 return getConvertorDoubleString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
283 * Creates convertor for Integer|String values with specified exchange rate
284 * between two currencies.
286 * @param firstCurrencyExchangeRate first currency
287 * @param secondCurrencyExchangeRate second currency
290 public static Convertor<Integer, String> getConvertorIntegerString(
291 CurrencyValue<Integer, String> firstCurrencyExchangeRate,
292 CurrencyValue<Integer, String> secondCurrencyExchangeRate) {
293 return getConvertorIntegerString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
299 static final Computer<Double> DoubleComputer = new Computer<Double>() {
301 public void compute(ComputerRequest<Double> request, ComputerResponse<Double> response) {
302 response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());
305 static final Computer<Integer> IntegerComputer = new Computer<Integer>() {
307 public void compute(ComputerRequest<Integer> request, ComputerResponse<Integer> response) {
308 response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());