# HG changeset patch # User japod@localhost # Date 1223335103 -7200 # Node ID a7e6f84fb07831c7044774586fc342d32fcbb8e9 # Parent e6cd39d9b6a24c2108b76d299434a7302795dd53 adding solution13 for task2 diff -r e6cd39d9b6a2 -r a7e6f84fb078 task2/solution13/src/org/apidesign/apifest08/currency/ConversionNotSupportedException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/task2/solution13/src/org/apidesign/apifest08/currency/ConversionNotSupportedException.java Tue Oct 07 01:18:23 2008 +0200 @@ -0,0 +1,85 @@ +package org.apidesign.apifest08.currency; + +/** + * Conversion not suported exception. This expecption may optionaly describe which conversion was required and failed. + * Required conversion can be found in {@link #getFromCurrecyCode() } and {@link #getToCurrecyCode() }. + * + * @author arnostvalicek + * @since version2 + */ +public class ConversionNotSupportedException extends ConvertorException { + String from; + String to; + boolean reversed; + + public ConversionNotSupportedException() { + super(); + } + + public ConversionNotSupportedException(String message) { + super(message); + } + + public ConversionNotSupportedException(String message, Throwable cause) { + super(message, cause); + } + + public ConversionNotSupportedException(Throwable cause) { + super(cause); + } + + /** + * Create exception witd additional information about currencies which are not supported in coversion. + * @param from Code of source currency. + * @param to Code of target currency. + * @param twoWay Set to false if From->To is not supported. + * Set to true if both ways From->To and To->From conversions are not supported. + * + */ + public ConversionNotSupportedException(String from, String to, boolean twoWay) { + this.from = from; + this.to = to; + this.reversed = true; + } + + @Override + public String toString() { + if (from!=null && to !=null) { + if (reversed) { + return "Neither onversion nor reverted conversion from " + from + " to " + to + " is not supported,"; + } else { + return "Conversion from " + from + " to " + to + " is not supported,"; + } + } else { + return super.toString(); + } + } + + /** + * Returns code of source currency. This value may be null. + * @return Returns code of source currency. + */ + public String getFromCurrecyCode() { + return from; + } + + /** + * Returns code of target currency. This value may be null. + * @return Returns code of target currency. + */ public String getToCurrecyCode() { + return to; + } + + /** + * Returns if one way of two way conversion is not supported. + * + * Value false means one way conversion is not supported. Value true means + * that two way conversio is not supported. + * + * @return Returs false for one way conversion, true for two way conversion. + */ + public boolean getTwoWayConversion() { + return reversed; + } + +} diff -r e6cd39d9b6a2 -r a7e6f84fb078 task2/solution13/src/org/apidesign/apifest08/currency/ConversionResult.java --- a/task2/solution13/src/org/apidesign/apifest08/currency/ConversionResult.java Tue Oct 07 00:47:25 2008 +0200 +++ b/task2/solution13/src/org/apidesign/apifest08/currency/ConversionResult.java Tue Oct 07 01:18:23 2008 +0200 @@ -6,8 +6,8 @@ /** * Result of currency conversion. Holds converted value and remainder. *

- * Converter describes value converted to target value. Remainder describes - * how much from original amount was not possible to convert. Converted never loses any (small) money + * Converted describes value converted to target currenty. Remainder describes + * how much from original amount was not possible to convert. Convertor never loses any (small) money * in conversion error (rounding), but instead of rounding is converts only as much as possible and keeps rest as remainder. * * @author arnostvalicek diff -r e6cd39d9b6a2 -r a7e6f84fb078 task2/solution13/src/org/apidesign/apifest08/currency/Convertor.java --- a/task2/solution13/src/org/apidesign/apifest08/currency/Convertor.java Tue Oct 07 00:47:25 2008 +0200 +++ b/task2/solution13/src/org/apidesign/apifest08/currency/Convertor.java Tue Oct 07 01:18:23 2008 +0200 @@ -5,23 +5,54 @@ import java.math.RoundingMode; /** Convertor able to convert amount from one currency to other currency. + *

+ * Conversion method are: + *

* * Exchange rate is provided by {@link ExchangeRateProvider}. */ public class Convertor { - boolean remainderAllowed = false; //if false, remained is not allowed (should be true ideally, but can't handle it now) + private Convertor[] convertors; + + /** Create new Convertor as merge of provided convertors. Merged convertor will use + * provided convertors to convert between currencies. + *

+ * Only one should be able to provide conversion between currencies. If more than one convertos + * are able to convert currency, one of conversions will be used (it is not defined which). + * + * @since version 2 + * @param convertors Convertor used to create merge-convertor. + * @return Returns new convertor instance. + */ + public static Convertor createConvertorAsMerge(Convertor[] convertors) { + return new Convertor(convertors); + } + + boolean remainderAllowed = true; //if false, remained is not allowed (should be true ideally, but can't handle it now) ExchangeRateProvider exchangeRateProvider; + /** Create simle convertor. + */ private Convertor() { - + this.convertors=new Convertor[0]; + } + + /** Create merge convertor. + */ + private Convertor(Convertor[] convertors) { + this.convertors = convertors; } /** - * Static method used to create convertor. + * Create new Convertor using ExchangeRateProvider. * * @param exchangeRateProvider {@link ExchangeRateProvider} used to get exchange rate. * * @return Returns Convertor which can be used to convert money. + * @since version1 */ public static Convertor createConvertor(ExchangeRateProvider exchangeRateProvider) { Convertor c = new Convertor(); @@ -36,9 +67,11 @@ * * @param amount Amount which should be converted. Can't be negative value (can be zero or positive). * @return Return ConversionResult which holds conversion result. + * @since version1 + * @deprecated since version2. Use {@link #convert(ConvertorCurrency, ConvertorCurrency, BigDecimal) } - explicitly specify conversion currencies. */ public ConversionResult convert(BigDecimal amount) { - return convertValue(amount, false); + return convertValue(exchangeRateProvider.getFromCurrency(), exchangeRateProvider.getToCurrency(),amount, false,false); } /** @@ -47,32 +80,44 @@ * * @param amount Amount which should be converted. Can't be negative value (can be zero or positive). * @return Return ConversionResult which holds conversion result. + * @since version1 + * @deprecated since version2. Use {@link #convert(ConvertorCurrency, ConvertorCurrency, BigDecimal) } - explicitly specify conversion currencies. */ public ConversionResult convertBack(BigDecimal amount) { - return convertValue(amount, true); + return convertValue(exchangeRateProvider.getFromCurrency(), exchangeRateProvider.getToCurrency(),amount, true,false); } - private ConversionResult convertValue(BigDecimal amount, boolean convertBack) throws RuntimeException { + private ConversionResult convertUsingSimpleConvertor(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency, boolean reversibleExRate, BigDecimal amount, boolean convertBack) throws ConversionNotSupportedException, RuntimeException { ConversionResult result = new ConversionResult(); - - ExchangeRate rate = exchangeRateProvider.getExchangeRate(); - int fromFranctionDigits = exchangeRateProvider.getFromCurrency().getDefaultFractionDigits(); - int toFractionDigits = exchangeRateProvider.getToCurrency().getDefaultFractionDigits(); - - if (toFractionDigits!=2) { - throw new RuntimeException("Can't process currency with defaultFractionDigits!=2, "+exchangeRateProvider.getToCurrency()+" has "+toFractionDigits+" defaultFractionDigits"); + + //ExchangeRate rate = exchangeRateProvider.getExchangeRate(); + ExchangeRate rate; + if (reversibleExRate) { + rate = exchangeRateProvider.getReversibleExchangeRate(fromCurrency, toCurrency); + } else { + rate = exchangeRateProvider.getExchangeRate(fromCurrency, toCurrency); } - if (fromFranctionDigits!=2) { - throw new RuntimeException("Can't process currency with defaultFractionDigits!=2, "+exchangeRateProvider.getFromCurrency()+" has "+fromFranctionDigits+" defaultFractionDigits"); + if (rate == null) { + return null; } - if (amount.signum()==-1) { - throw new RuntimeException("Can convert only non-negative value, current value is "+amount); + int fromFranctionDigits = fromCurrency.getDefaultFractionDigits(); + int toFractionDigits = toCurrency.getDefaultFractionDigits(); + + if (toFractionDigits != 2) { + throw new ConvertorException("Can't process currency with defaultFractionDigits!=2, " + exchangeRateProvider.getToCurrency() + " has " + toFractionDigits + " defaultFractionDigits"); } - - + if (fromFranctionDigits != 2) { + throw new ConvertorException("Can't process currency with defaultFractionDigits!=2, " + exchangeRateProvider.getFromCurrency() + " has " + fromFranctionDigits + " defaultFractionDigits"); + } + + if (amount.signum() == -1) { + throw new RuntimeException("Can convert only non-negative value, current value is " + amount); + } + + MathContext context = new MathContext(0, RoundingMode.DOWN); - + BigDecimal from; BigDecimal to; if (convertBack) { @@ -80,26 +125,89 @@ to = rate.getFromValue(); from = rate.getToValue(); } else { - //converting in mornak way + //converting in normal way from = rate.getFromValue(); to = rate.getToValue(); } BigDecimal amountCent = amount.movePointRight(2); - - final BigDecimal multiplied = amountCent.multiply(to,context); - BigDecimal[] division = multiplied.divideAndRemainder(from,context); + + final BigDecimal multiplied = amountCent.multiply(to, context); + BigDecimal[] division = multiplied.divideAndRemainder(from, context); if (!remainderAllowed && !(BigDecimal.ZERO.equals(division[1]))) { - throw new RuntimeException("Remained is not allowed - remaining amount is " + division[1]+ " cents"); + throw new RuntimeException("Remained is not allowed - remaining amount is " + division[1] + " cents"); } else { result.setRemainder(BigDecimal.ZERO); } - - final BigDecimal converted = division[0].movePointLeft(2); + + final BigDecimal converted = division[0].movePointLeft(2); result.setConverted(converted); //result.setRemainder(...); - return result; } + + + private ConversionResult convertValue(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency,BigDecimal amount, boolean convertBack,boolean reversibleExRate) throws RuntimeException { + //result.setRemainder(...); + if (convertors.length==0) { + return convertUsingSimpleConvertor(fromCurrency, toCurrency, reversibleExRate, amount, convertBack); + } else { + ConversionResult result = null; + for (int i = 0;ivalue from fromCurrency to toCurrency. + *

+ * Exchange rate is provided by exchange rate provider which was specified when Convertor was created. + * This method is using only exchange rate from->to and not trying to use reverted excange rate to->from. + * + * @param fromCurrency Source currency to convert from. + * @param toCurrency Target currency to convert to. + * @param value Value in source currency which should be converted. + * @return Return conversion result. + * @since version2 + * @throws ConversionNotSupportedException If conversion from fromCurrency to toCurrency is not supported. + */ + public ConversionResult convert(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency, BigDecimal value) { + ConversionResult result = convertValue(fromCurrency, toCurrency, value, false,false); + if (result==null) { + //throw new ConversionNotSupportedException("Conversion from " + fromCurrency + " to " + toCurrency + " is not supported"); + throw new ConversionNotSupportedException(fromCurrency.getCurrencyCode(),toCurrency.getCurrencyCode(),false); + } + return result; + } + + /** + * Convert value from fromCurrency to toCurrency. + * Exchange rate is provided by exchange rate provider which was specified when Convertor was created. + *

+ * This method is using only exchange rate from->to and if not found, it is trying to use reverted excange rate to->from. + * + * @param fromCurrency Source currency to convert from. + * @param toCurrency Target currency to convert to. + * @param value Value in source currency which should be converted. + * @return Return conversion result. + * @since version2 + * @throws ConversionNotSupportedException If conversion from fromCurrency to toCurrency + * is not supported and neither conversion from toCurrency to fromCurrency is not supported. + */ + public ConversionResult convertWithReversibleRates(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency, BigDecimal value) { + ConversionResult result = convertValue(fromCurrency, toCurrency, value, false,true); + if (result==null) { + //throw new ConversionNotSupportedException("Neither onversion nor reverted conversion from " + fromCurrency + " to " + toCurrency + " is not supported,"); + throw new ConversionNotSupportedException(fromCurrency.getCurrencyCode(),toCurrency.getCurrencyCode(),true); + } + return result; + } + } diff -r e6cd39d9b6a2 -r a7e6f84fb078 task2/solution13/src/org/apidesign/apifest08/currency/ConvertorCurrency.java --- a/task2/solution13/src/org/apidesign/apifest08/currency/ConvertorCurrency.java Tue Oct 07 00:47:25 2008 +0200 +++ b/task2/solution13/src/org/apidesign/apifest08/currency/ConvertorCurrency.java Tue Oct 07 01:18:23 2008 +0200 @@ -40,7 +40,24 @@ } @Override + public boolean equals(Object obj) { + boolean result; + if (obj instanceof ConvertorCurrency) { + ConvertorCurrency that = (ConvertorCurrency) obj; + result = currency.equals(that.currency); + } else { + result = false; + } + return result; + } + + + @Override public String toString() { - return getClass() + " based on " + (currency != null ? currency.toString() : "NO-BASE-CURRENCY"); + return "ConvertorCurrency[" + (currency != null ? currency.toString() : "NO-BASE-CURRENCY")+"]"; + } + + String getCurrencyCode() { + return currency.getCurrencyCode(); } } diff -r e6cd39d9b6a2 -r a7e6f84fb078 task2/solution13/src/org/apidesign/apifest08/currency/ConvertorException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/task2/solution13/src/org/apidesign/apifest08/currency/ConvertorException.java Tue Oct 07 01:18:23 2008 +0200 @@ -0,0 +1,25 @@ +package org.apidesign.apifest08.currency; + +/** + * Common Convertor exception. + * + * @author arnostvalicek + */ +public class ConvertorException extends RuntimeException { + + public ConvertorException(Throwable cause) { + super(cause); + } + + public ConvertorException(String message, Throwable cause) { + super(message, cause); + } + + public ConvertorException(String message) { + super(message); + } + + public ConvertorException() { + } + +} diff -r e6cd39d9b6a2 -r a7e6f84fb078 task2/solution13/src/org/apidesign/apifest08/currency/ExchangeRate.java --- a/task2/solution13/src/org/apidesign/apifest08/currency/ExchangeRate.java Tue Oct 07 00:47:25 2008 +0200 +++ b/task2/solution13/src/org/apidesign/apifest08/currency/ExchangeRate.java Tue Oct 07 01:18:23 2008 +0200 @@ -12,20 +12,47 @@ private BigDecimal numberFor; private BigDecimal numberGet; + /** + * Constructor for new exchange rate holding two values - from value and to value + * @param fromValue Exchange rate from value + * @param toValue Exchange rate to value + */ public ExchangeRate(BigDecimal fromValue, BigDecimal toValue) { this.numberFor = fromValue; this.numberGet = toValue; } + + /** + * Create new instance of ExchangeRate based on provided exchange rate, but swapping its + * from and to value. + *

+ * Provided exchange rate is not chaged, this method returns different instance describing reverted exchange rate. + * + * @param rate Exchange rate which describes rate to be reverted. + * @return Instance of reverted rate. + */ + public static ExchangeRate createRevertedRate(ExchangeRate rate) { + ExchangeRate reverted = new ExchangeRate(rate.getToValue(), rate.getFromValue()); + return reverted; + } @Override public String toString() { return "for "+numberFor+" recieve "+numberGet+" @"+getClass().getName(); } + /** + * Return exchange rate from value stored in this object. + * @return Returns from value for this exchange rate. + */ public BigDecimal getFromValue() { return numberFor; } + /** + * Return exchange rate to value stored in this object. + * @return Returns to value for this exchange rate. + */ public BigDecimal getToValue() { return numberGet; } diff -r e6cd39d9b6a2 -r a7e6f84fb078 task2/solution13/src/org/apidesign/apifest08/currency/ExchangeRateProvider.java --- a/task2/solution13/src/org/apidesign/apifest08/currency/ExchangeRateProvider.java Tue Oct 07 00:47:25 2008 +0200 +++ b/task2/solution13/src/org/apidesign/apifest08/currency/ExchangeRateProvider.java Tue Oct 07 01:18:23 2008 +0200 @@ -3,27 +3,33 @@ import java.math.BigDecimal; import java.util.Date; +import java.util.HashMap; +import java.util.Map; /** - * Exchange rate provider - can provide fixed exchange rate which does not depend - * on date (method {@link #getExchangeRate()} ) or exchange rate based on date (method {@link #getExchangeRate(java.util.Date) }). + * Exchange rate provider. Provides fixed exchange rate which does not depend + * on date (method {@link #getExchangeRate()} ). * + * Date dependend exchange rate to be implemented. * * @author arnostvalicek */ public class ExchangeRateProvider { BigDecimal fromValue, toValue; ConvertorCurrency fromCurrency, toCurrency; + + Map exchangeRateMap = new HashMap(); /** * Simple constructor for ExchangeRateProviderM which can provide fixed exchange rate. * - * Describes conversion from to to currency. + * Describes conversion from ONE to to ONE currency. * * @param fromValue From value. BigDecimal value, precision should be set to currency precision. * @param fromCurrency From currency. * @param toValue To value. BigDecimal value, precision should be set to currency precision. * @param toCurrency To currency. + * @deprecated deprecated since task2. Use {@link #createExchangeRateProvider() } instead of this constructor. */ public ExchangeRateProvider(BigDecimal fromValue, ConvertorCurrency fromCurrency, BigDecimal toValue, ConvertorCurrency toCurrency) { this.fromValue = fromValue; @@ -32,18 +38,89 @@ this.toCurrency = toCurrency; } + private ExchangeRateProvider() { + + } + + /** + * Static method to create new exchange rate provider. This exchange rate provider does not contain + * any exchange rates (this is difference to public constructor). + * @return New ExchangeRateProvider + */ + public static ExchangeRateProvider createExchangeRateProvider() { + ExchangeRateProvider provider = new ExchangeRateProvider(); + return provider; + } + + /** + * Add new exchange rate to to this exchange rate provider. + *

+ * Example of specifiing conversion rate: 100 SKK == 80 CZK:
+ * addFixedCurencyRate(ConvertorCurrency.getInstance("SKK"), new BigDecimal(100), ConvertorCurrency.getInstance("CZK"), new BigDecimal(80)); + *

+ * + * @param fromCurrency Source currency. + * @param fromValue Valye for from currency. + * @param toCurrency Target currency. + * @param toValue Value for target currency. + */ + public synchronized void addFixedCurencyRate(ConvertorCurrency fromCurrency, BigDecimal fromValue, ConvertorCurrency toCurrency, BigDecimal toValue) { + if (fromValue==null) { + throw new NullPointerException("fromValue can't be null"); + } + if (toValue==null) { + throw new NullPointerException("toValue can't be null"); + } + Map map2 = (Map) exchangeRateMap.get(fromCurrency); + if (map2==null) { + map2 = new HashMap(); + exchangeRateMap.put(fromCurrency, map2); + } + + ExchangeRate rate = new ExchangeRate(fromValue, toValue); + map2.put(toCurrency, rate); + } + /** * Get fixed exange rate for currencies (from->to). * @return Returns exchange rate. + * @deprecated deprecated since task2. Use {@link #getExchangeRate(ConvertorCurrency, ConvertorCurrency) } */ public ExchangeRate getExchangeRate() { return new ExchangeRate(fromValue, toValue); } + + + /** + * Get fixed exange rate for currencies (from->to). + * @return Returns exchange rate or null if exchange rate not found. + */ + public ExchangeRate getExchangeRate(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency) { + return getExchangeRateImpl(fromCurrency, toCurrency); + } + + /** + * Get fixed exange rate for currencies (from->to) or reversed exchange rate (to->from). + * @return Returns exchange rate or null if exchange rate not found. + */ + public ExchangeRate getReversibleExchangeRate(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency) { + ExchangeRate rate = getExchangeRateImpl(fromCurrency, toCurrency); + if (rate==null) { + ExchangeRate revertedRate = getExchangeRateImpl(toCurrency, fromCurrency); + if (revertedRate!=null) { + rate = ExchangeRate.createRevertedRate(revertedRate); + } + } + return rate; + } + + /** * Get exchange rate for currencies (from->to) based on provided date. * @param date Date for which exchange rate should be provided. * @return Returns exchange rate + * @deprecated deprecated since task2. No real implementation in version2. */ public ExchangeRate getExchangeRate(Date date) { return new ExchangeRate(fromValue, toValue); @@ -57,6 +134,19 @@ ConvertorCurrency getToCurrency() { return toCurrency; } + + private ExchangeRate getExchangeRateImpl(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency) { + if (fromValue != null && toValue != null && fromCurrency.equals(this.fromCurrency) && toCurrency.equals(this.toCurrency)) { + return new ExchangeRate(fromValue, toValue); + } + //return new ExchangeRate(fromValue, toValue); + Map map2 = (Map) exchangeRateMap.get(fromCurrency); + if (map2 == null) { + return null; + } + ExchangeRate result = (ExchangeRate) map2.get(toCurrency); + return result; + } } diff -r e6cd39d9b6a2 -r a7e6f84fb078 task2/solution13/test/org/apidesign/apifest08/test/Task1Test.java --- a/task2/solution13/test/org/apidesign/apifest08/test/Task1Test.java Tue Oct 07 00:47:25 2008 +0200 +++ b/task2/solution13/test/org/apidesign/apifest08/test/Task1Test.java Tue Oct 07 01:18:23 2008 +0200 @@ -6,6 +6,7 @@ import org.apidesign.apifest08.currency.Convertor; import org.apidesign.apifest08.currency.ConvertorCurrency; import org.apidesign.apifest08.currency.ExchangeRateProvider; +import org.apidesign.apifest08.currency.ConversionNotSupportedException; /** Finish the Convertor API, and then write bodies of methods inside * of this class to match the given tasks. To fullfil your task, use the @@ -34,7 +35,7 @@ * * @return prepared convertor ready for converting USD to CZK and CZK to USD */ - public Convertor createCZKtoUSD() { + public static Convertor createCZKtoUSD() { ConvertorCurrency fromCurrency = ConvertorCurrency.getInstance("CZK"); ConvertorCurrency toCurrency = ConvertorCurrency.getInstance("USD"); ExchangeRateProvider exchangeRateProvider = new ExchangeRateProvider(new BigDecimal(17), fromCurrency, new BigDecimal(1), toCurrency); @@ -50,7 +51,7 @@ * * @return prepared convertor ready for converting SKK to CZK and CZK to SKK */ - public Convertor createSKKtoCZK() { + public static Convertor createSKKtoCZK() { ConvertorCurrency fromCurrency = ConvertorCurrency.getInstance("SKK"); ConvertorCurrency toCurrency = ConvertorCurrency.getInstance("CZK"); ExchangeRateProvider exchangeRateProvider = new ExchangeRateProvider(new BigDecimal(100), fromCurrency, new BigDecimal(80), toCurrency); @@ -59,7 +60,7 @@ } - public Convertor createCZKtoYEN() { + public static Convertor createCZKtoYEN() { ConvertorCurrency fromCurrency = ConvertorCurrency.getInstance("CZK"); ConvertorCurrency toCurrency = ConvertorCurrency.getInstance("JPY"); ExchangeRateProvider exchangeRateProvider = new ExchangeRateProvider(new BigDecimal(1), fromCurrency, new BigDecimal(1), toCurrency); @@ -200,8 +201,21 @@ public void testCannotConvertToSKKwithCZKUSDConvertor() throws Exception { Convertor c = createCZKtoUSD(); // convert $5 to SKK, the API shall say this is not possible + try { + c.convert(ConvertorCurrency.getInstance("USD"), ConvertorCurrency.getInstance("SKK"), new BigDecimal(5)); + fail(); + } catch (ConversionNotSupportedException e) { + //expected error; + assertEquals("Exception From USD", "USD",e.getFromCurrecyCode()); + assertEquals("Exception To SKK", "SKK",e.getToCurrecyCode()); + } // convert 500 SKK to CZK, the API shall say this is not possible - // ... no api for required call, should be here? + try { + c.convert(ConvertorCurrency.getInstance("SKK"), ConvertorCurrency.getInstance("CZK"), new BigDecimal(500)); + fail(); + } catch (ConversionNotSupportedException e) { + assertEquals("Exception From USD", "SKK",e.getFromCurrecyCode()); + assertEquals("Exception To SKK", "CZK",e.getToCurrecyCode()); } } diff -r e6cd39d9b6a2 -r a7e6f84fb078 task2/solution13/test/org/apidesign/apifest08/test/Task2Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/task2/solution13/test/org/apidesign/apifest08/test/Task2Test.java Tue Oct 07 01:18:23 2008 +0200 @@ -0,0 +1,136 @@ +package org.apidesign.apifest08.test; + +import java.math.BigDecimal; +import junit.framework.TestCase; +import org.apidesign.apifest08.currency.Convertor; +import org.apidesign.apifest08.currency.ConvertorCurrency; +import org.apidesign.apifest08.currency.ExchangeRateProvider; + +/** There are many currencies around the world and many banks manipulate + * with more than one or two at the same time. As banks are usually the + * best paying clients, which is true even in case of your Convertor API, + * it is reasonable to listen to their requests. + *

+ * The quest for today is to enhance your existing convertor API to hold + * information about many currencies and allow conversions between any of them. + * Also, as conversion rates for diferent currencies usually arise from various + * bank departments, there is another important need. There is a need to + * compose two convertors into one by merging all the information about + * currencies they know about. + */ +public class Task2Test extends TestCase { + private static ConvertorCurrency currencyCZK = ConvertorCurrency.getInstance("CZK"); + private static ConvertorCurrency currencySKK = ConvertorCurrency.getInstance("SKK"); + private static ConvertorCurrency currencyUSD = ConvertorCurrency.getInstance("USD"); + + public Task2Test(String testName) { + super(testName); + } + + @Override + protected void setUp() throws Exception { + + } + + @Override + protected void tearDown() throws Exception { + } + + public static Convertor createUsdToSkkConvertor() { + ConvertorCurrency fromCurrency = currencyUSD; + ConvertorCurrency toCurrency = currencyUSD; + ExchangeRateProvider exchangeRateProvider = new ExchangeRateProvider(new BigDecimal(1), fromCurrency, new BigDecimal(20), toCurrency); + + return Convertor.createConvertor(exchangeRateProvider); + + } + + // As in Task1Test, keep in mind, that there are three parts + // of the whole system: + // 1. there is someone who knows the current exchange rate + // 2. there is someone who wants to do the conversion + // 3. there is the API between 1. and 2. which allows them to communicate + // + // Please backward compatibly enhance your existing API to support following + // usecases: + // + + /** Create convertor that understands two currencies, CZK and + * SKK. Make 100 SKK == 75 CZK. This is method for the group of users that + * knows the exchange rate, and needs to use the API to create objects + * with the exchange rate. Anyone shall be ready to call this method without + * any other method being called previously. The API itself shall know + * nothing about any rates, before this method is called. + */ + public static Convertor createTripleConvertor() { + ExchangeRateProvider exRateProvider = ExchangeRateProvider.createExchangeRateProvider(); + + // Rates: 1USD = 15CZK + exRateProvider.addFixedCurencyRate(currencyUSD, new BigDecimal(1),currencyCZK, new BigDecimal(15)); + + // Rates: 1USD = 20SKK + exRateProvider.addFixedCurencyRate(currencyUSD, new BigDecimal(1), currencySKK, new BigDecimal(20)); + + // Rates: 75CZK = 100SKK + exRateProvider.addFixedCurencyRate(currencyCZK, new BigDecimal(75), currencySKK, new BigDecimal(100)); + + Convertor c = Convertor.createConvertor(exRateProvider); + + return c; + } + + /** Define convertor that understands three currencies. Use it. + */ + public void testConvertorForUSDandCZKandSKK() throws Exception { + Convertor c = createTripleConvertor(); + + // convert $5 to CZK using c: + assertEquals("Result is 75 CZK",new BigDecimal("75.00"),c.convertWithReversibleRates(currencyUSD, currencyCZK, new BigDecimal(5)).getConverted()); + + + // convert $5 to SKK using c: + assertEquals("Result is 100 SKK",new BigDecimal("100.00"),c.convertWithReversibleRates(currencyUSD, currencySKK, new BigDecimal(5)).getConverted()); + + // convert 200SKK to CZK using c: + assertEquals("Result is 150 CZK",new BigDecimal("150.00"),c.convertWithReversibleRates(currencySKK, currencyCZK, new BigDecimal(200)).getConverted()); + + // convert 200SKK to USK using c: + // assertEquals("Result is 10 USD"); + } + + /** Merge all currency rates of convertor 1 with convertor 2. + * Implement this using your API, preferably this method just delegates + * into some API method which does the actual work, without requiring + * API clients to code anything complex. + */ + public static Convertor merge(Convertor one, Convertor two) { + return Convertor.createConvertorAsMerge(new Convertor[]{one, two}); + } + + /** Join the convertors from previous task, Task1Test and show that it + * can be used to do reasonable conversions. + */ + public void testConvertorComposition() throws Exception { + Convertor c = merge( + Task1Test.createCZKtoUSD(), + Task1Test.createSKKtoCZK() + ); + + // convert $5 to CZK using c: + assertEquals("Result is 85 CZK",new BigDecimal("85.00"),c.convertWithReversibleRates(currencyUSD, currencyCZK, new BigDecimal(5)).getConverted()); + + // convert $8 to CZK using c: + // assertEquals("Result is 136 CZK"); + assertEquals("Result is 136 CZK",new BigDecimal("136.00"),c.convertWithReversibleRates(currencyUSD, currencyCZK, new BigDecimal(8)).getConverted()); + + // convert 1003CZK to USD using c: + assertEquals("Result is 59 USD",new BigDecimal("59.00"),c.convertWithReversibleRates(currencyCZK, currencyUSD, new BigDecimal(1003)).getConverted()); + + // convert 16CZK using c: + assertEquals("Result is 20 SKK",new BigDecimal("20.00"),c.convertWithReversibleRates(currencyCZK, currencySKK, new BigDecimal(16)).getConverted()); + + // convert 500SKK to CZK using c: + assertEquals("Result is 400 CZK",new BigDecimal("400.00"),c.convertWithReversibleRates(currencySKK, currencyCZK, new BigDecimal(500)).getConverted()); + + } +}