japod@6: package org.apidesign.apifest08.currency; japod@6: japod@37: import java.util.ArrayList; japod@37: import java.util.Collection; japod@37: import java.util.HashSet; japod@37: import java.util.List; japod@37: import java.util.Set; japod@6: import org.apidesign.apifest08.currency.Computer.ComputerRequest; japod@6: import org.apidesign.apifest08.currency.Computer.ComputerResponse; japod@6: japod@6: /** japod@6: * Convertor. japod@6: * japod@6: * In Task 1's version provides conversion between currency values japod@6: * with amount stored in integer or double, that are identified japod@6: * with string value. Exchange rates are immutable. japod@6: * japod@37: * In Task2's version provides support for multiple exchange rates japod@37: * between different currencies & merging exchange rates from japod@37: * existing convertors into new convertor's instance. japod@37: * No time for javadoc these features, sorry. japod@37: * japod@53: * In Task3's version supports reading of current exchange rates japod@53: * from data sources. Data sources are merged during convertors' merging japod@53: * as well as static exchange rates. japod@53: * No time for javadoc, again. japod@53: * japod@6: * @author ked japod@6: */ japod@6: public final class Convertor { japod@6: japod@6: Computer computer; japod@53: // each static exchange rate could be a special case of an exchange rate data source japod@37: List> exchangeRates = new ArrayList>(); japod@53: List> exchangeRateDataSources = new ArrayList>(); japod@6: japod@53: Convertor(Computer computer) { japod@37: this.computer = computer; japod@53: } japod@53: japod@53: void addExchangeRates(Collection> exchangeRates) { japod@37: for (ExchangeRateValue exchangeRate : exchangeRates) { japod@53: if (isExchangeRate( japod@37: exchangeRate.getCurrencyA().getIdentifier(), japod@53: exchangeRate.getCurrencyB().getIdentifier())) { japod@37: throw new IllegalArgumentException("Duplicate exchange rate!"); japod@37: } japod@37: this.exchangeRates.add(exchangeRate); japod@19: } japod@37: } japod@53: japod@53: void addExchangeRateDataSources(Collection> exchangeRateDataSources) { japod@53: for (ExchangeRateDataSource exchangeRateDataSource : exchangeRateDataSources) { japod@53: if (isExchangeRate( japod@53: exchangeRateDataSource.getCurrencyAIdentifier(), japod@53: exchangeRateDataSource.getCurrencyBIdentifier())) { japod@53: throw new IllegalArgumentException("Duplicate exchange rate!"); japod@53: } japod@53: this.exchangeRateDataSources.add(exchangeRateDataSource); japod@53: } japod@53: } japod@53: japod@53: ExchangeRateValue findExchangeRate( japod@37: IdentifierType currencyA, japod@37: IdentifierType currencyB) { japod@37: for (ExchangeRateValue exchangeRate : exchangeRates) { japod@37: if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) || japod@37: (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) { japod@37: return exchangeRate; japod@37: } japod@37: } japod@53: for (ExchangeRateDataSource exchangeRateDataSource : exchangeRateDataSources) { japod@53: if ((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) || japod@53: (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) { japod@53: return exchangeRateDataSource.getExchangeRate(); japod@53: } japod@53: } japod@37: return null; japod@6: } japod@53: japod@53: boolean isExchangeRate( japod@53: IdentifierType currencyA, japod@53: IdentifierType currencyB) { japod@53: for (ExchangeRateValue exchangeRate : exchangeRates) { japod@53: if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) || japod@53: (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) { japod@53: return true; japod@53: } japod@53: } japod@53: for (ExchangeRateDataSource exchangeRateDataSource : exchangeRateDataSources) { japod@53: if ((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) || japod@53: (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) { japod@53: return true; japod@53: } japod@53: } japod@53: return false; japod@53: } japod@6: japod@6: /** japod@6: * Convert an amount of the one currency to an amount of the another one currency japod@37: * with respect to previously specified exchange rates. japod@6: * japod@19: * @param targetCurrency an identifier of the requested currency japod@19: * @param currencyValue an amount of the another one currency japod@19: * @return an amount of the requested currency japod@6: */ japod@19: public CurrencyValue convert( japod@19: IdentifierType targetCurrency, japod@19: CurrencyValue currencyValue) { japod@37: ExchangeRateValue exchangeRate = japod@53: findExchangeRate(currencyValue.getIdentifier(), targetCurrency); japod@37: if (exchangeRate == null) { japod@19: throw new IllegalArgumentException("Inappropriate currencies to convert!"); japod@6: } japod@37: japod@37: ComputerRequest computerRequest = new ComputerRequest(); japod@37: computerRequest.setInput(currencyValue.getAmount()); japod@37: japod@37: IdentifierType targetCurrencyRef; // just for backward compatibility :-( japod@37: if (exchangeRate.getCurrencyA().getIdentifier().equals(targetCurrency)) { japod@37: computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyB().getAmount()); japod@37: computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyA().getAmount()); japod@37: targetCurrencyRef = exchangeRate.getCurrencyA().getIdentifier(); japod@37: } else { japod@37: computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyA().getAmount()); japod@37: computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyB().getAmount()); japod@37: targetCurrencyRef = exchangeRate.getCurrencyB().getIdentifier(); japod@37: } japod@37: japod@53: ComputerResponse computerResponse = new ComputerResponse(); japod@53: computer.compute(computerRequest, computerResponse); japod@53: japod@37: return CurrencyValue.getCurrencyValue( japod@37: computerResponse.getResult(), japod@37: targetCurrencyRef); japod@37: } japod@37: japod@37: // --- japod@37: // MERGING japod@37: // --- japod@37: static Convertor mergeConvertors( japod@37: Computer computer, japod@37: Collection> convertors) { japod@37: Set> exchangeRatesSet = new HashSet>(); japod@53: Set> exchangeRateDataSourcesSet = new HashSet>(); japod@37: for (Convertor convertor : convertors) { japod@37: exchangeRatesSet.addAll(convertor.exchangeRates); japod@37: } japod@53: for (Convertor convertor : convertors) { japod@53: exchangeRateDataSourcesSet.addAll(convertor.exchangeRateDataSources); japod@53: } japod@53: japod@53: Convertor c = new Convertor(computer); japod@53: c.addExchangeRates(exchangeRatesSet); japod@53: c.addExchangeRateDataSources(exchangeRateDataSourcesSet); japod@53: return c; japod@37: } japod@37: japod@37: static Convertor mergeConvertors( japod@37: Computer computer, japod@37: Convertor convertorA, japod@37: Convertor convertorB) { japod@37: Collection> convertors = japod@37: new ArrayList>(); japod@37: convertors.add(convertorA); japod@37: convertors.add(convertorB); japod@37: return mergeConvertors(computer, convertors); japod@37: } japod@37: japod@37: public static Convertor mergeConvertorsDoubleString( japod@37: Collection> convertors) { japod@37: return mergeConvertors(DoubleComputer, convertors); japod@37: } japod@37: japod@37: public static Convertor mergeConvertorsDoubleString( japod@37: Convertor convertorA, japod@37: Convertor convertorB) { japod@37: return mergeConvertors(DoubleComputer, convertorA, convertorB); japod@37: } japod@37: japod@37: public static Convertor mergeConvertorsIntegerString( japod@37: Collection> convertors) { japod@37: return mergeConvertors(IntegerComputer, convertors); japod@37: } japod@37: japod@37: public static Convertor mergeConvertorsIntegerString( japod@37: Convertor convertorA, japod@37: Convertor convertorB) { japod@37: return mergeConvertors(IntegerComputer, convertorA, convertorB); japod@37: } japod@37: japod@37: // --- japod@37: // CREATION japod@37: // --- japod@37: static Convertor getConvertor( japod@37: Computer computer, Collection> exchangeRates) { japod@53: Convertor c = new Convertor(computer); japod@53: c.addExchangeRates(exchangeRates); japod@53: return c; japod@6: } japod@6: japod@53: static Convertor getConvertorDataSource( japod@53: Computer computer, Collection> exchangeRateDataSources) { japod@53: Convertor c = new Convertor(computer); japod@53: c.addExchangeRateDataSources(exchangeRateDataSources); japod@53: return c; japod@53: } japod@53: japod@6: static Convertor getConvertor( japod@37: Computer computer, ExchangeRateValue exchangeRate) { japod@37: Collection> exchangeRates = japod@37: new ArrayList>(); japod@37: exchangeRates.add(exchangeRate); japod@37: return getConvertor(computer, exchangeRates); japod@6: } japod@6: japod@53: static Convertor getConvertorDataSource( japod@53: Computer computer, ExchangeRateDataSource exchangeRateDataSource) { japod@53: Collection> exchangeRateDataSources = japod@53: new ArrayList>(); japod@53: exchangeRateDataSources.add(exchangeRateDataSource); japod@53: return getConvertorDataSource(computer, exchangeRateDataSources); japod@53: } japod@53: japod@37: public static Convertor getConvertorDoubleString( japod@37: Collection> exchangeRates) { japod@37: return getConvertor(DoubleComputer, exchangeRates); japod@37: } japod@6: japod@37: public static Convertor getConvertorDoubleString( japod@37: ExchangeRateValue exchangeRate) { japod@37: return getConvertor(DoubleComputer, exchangeRate); japod@37: } japod@53: japod@53: public static Convertor getConvertorDataSourceDoubleString( japod@53: Collection> exchangeRateDataSources) { japod@53: return getConvertorDataSource(DoubleComputer, exchangeRateDataSources); japod@53: } japod@6: japod@53: public static Convertor getConvertorDataSourceDoubleString( japod@53: ExchangeRateDataSource exchangeRateDataSource) { japod@53: return getConvertorDataSource(DoubleComputer, exchangeRateDataSource); japod@53: } japod@53: japod@37: public static Convertor getConvertorIntegerString( japod@37: Collection> exchangeRates) { japod@37: return getConvertor(IntegerComputer, exchangeRates); japod@37: } japod@37: japod@37: public static Convertor getConvertorIntegerString( japod@37: ExchangeRateValue exchangeRate) { japod@37: return getConvertor(IntegerComputer, exchangeRate); japod@37: } japod@53: japod@53: public static Convertor getConvertorDataSourceIntegerString( japod@53: Collection> exchangeRateDataSources) { japod@53: return getConvertorDataSource(IntegerComputer, exchangeRateDataSources); japod@53: } japod@53: japod@53: public static Convertor getConvertorDataSourceIntegerString( japod@53: ExchangeRateDataSource exchangeRateDataSource) { japod@53: return getConvertorDataSource(IntegerComputer, exchangeRateDataSource); japod@53: } japod@37: japod@37: // --- japod@37: // BACKWARD COMPATIBILITY - CREATION japod@37: // --- japod@6: /** japod@6: * Creates convertor for Double|String values with specified exchange rate japod@6: * between two currencies. japod@6: * japod@6: * @param firstCurrencyExchangeRate first currency japod@6: * @param secondCurrencyExchangeRate second currency japod@6: * @return convertor japod@6: */ japod@6: public static Convertor getConvertorDoubleString( japod@6: CurrencyValue firstCurrencyExchangeRate, japod@6: CurrencyValue secondCurrencyExchangeRate) { japod@37: return getConvertorDoubleString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate)); japod@6: } japod@6: japod@6: /** japod@6: * Creates convertor for Integer|String values with specified exchange rate japod@6: * between two currencies. japod@6: * japod@6: * @param firstCurrencyExchangeRate first currency japod@6: * @param secondCurrencyExchangeRate second currency japod@6: * @return convertor japod@6: */ japod@6: public static Convertor getConvertorIntegerString( japod@6: CurrencyValue firstCurrencyExchangeRate, japod@6: CurrencyValue secondCurrencyExchangeRate) { japod@37: return getConvertorIntegerString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate)); japod@6: } japod@37: japod@37: // --- japod@37: // COMPUTERS japod@37: // --- japod@37: static final Computer DoubleComputer = new Computer() { japod@37: japod@53: public void compute(ComputerRequest request, ComputerResponse response) { japod@37: response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio()); japod@37: } japod@37: }; japod@37: static final Computer IntegerComputer = new Computer() { japod@37: japod@53: public void compute(ComputerRequest request, ComputerResponse response) { japod@37: response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio()); japod@37: } japod@37: }; japod@6: }