# HG changeset patch # User japod@localhost # Date 1222769066 -7200 # Node ID 7ca97f802b5ade82ea0c821afb53fdcff25f63fc # Parent 45e6a2d1ffd16d9f2052c18134cfc1aa9ede79ea updating solution 12 to 1.5 diff -r 45e6a2d1ffd1 -r 7ca97f802b5a task1/solution12/src/org/apidesign/apifest08/currency/Convertor.java --- a/task1/solution12/src/org/apidesign/apifest08/currency/Convertor.java Tue Sep 30 12:01:18 2008 +0200 +++ b/task1/solution12/src/org/apidesign/apifest08/currency/Convertor.java Tue Sep 30 12:04:26 2008 +0200 @@ -1,6 +1,11 @@ package org.apidesign.apifest08.currency; import java.util.Currency; +import java.util.Hashtable; + +import org.apidesign.apifest08.currency.exceptions.ConvertorException; +import org.apidesign.apifest08.currency.exceptions.InvalidCurrencyException; +import org.apidesign.apifest08.currency.exceptions.UnknownConvertorException; /** * This is the skeleton class for your API. You need to make it public, so it is accessible to your client code @@ -11,12 +16,56 @@ */ public class Convertor { - private Currency currency1; - private Currency currency2; + private static Hashtable exchangeRates; - private Convertor(Currency currency1, Currency currency2) { - this.currency1 = currency1; - this.currency2 = currency2; + private ExchangeRate exchangeRate12; + private ExchangeRate exchangeRate21; + + private Convertor(Currency currency1, Currency currency2) throws UnknownConvertorException { + String key12 = currency1.getCurrencyCode() + currency2.getCurrencyCode(); + String key21 = currency2.getCurrencyCode() + currency1.getCurrencyCode(); + + if (!(exchangeRates.containsKey(key12) && exchangeRates.containsKey(key21))) { + throw new UnknownConvertorException("Selected convertor (" + currency1.getCurrencyCode() + "->" + + currency2.getCurrencyCode() + ") has not defined any rates!!!"); + } + + this.exchangeRate12 = exchangeRates.get(key12); + this.exchangeRate21 = exchangeRates.get(key21); + } + + /** + * Sets convertor rate for selected currencies. + * @param currency1 + * one of the currencies we want to convert to/from + * @param currency2 + * the other currency + * @param rate + * exchange rate from currency1 to currency2 + * @param unit + * unit of exchangeRate (USD->CZK - unit=1, you exchange one dollar, SKK->CZK unit=100, exchange rate is for + * 100SKK) + */ + public static void setConvertorRates(Currency currency1, Currency currency2, double rate, double unit) { + if (currency1 == null || currency2 == null) { + throw new ConvertorException("None of the currencies should be null!!!"); + } + + if (rate <= 0 || unit <= 0) { + throw new ConvertorException("Rate(" + rate + ") and unit(" + unit + ") has to be grater then zero!!!"); + } + + if (exchangeRates == null) { + exchangeRates = new Hashtable(); + } + + String key12 = currency1.getCurrencyCode() + currency2.getCurrencyCode(); + String key21 = currency2.getCurrencyCode() + currency1.getCurrencyCode(); + double recountedRate = (unit / rate) * unit; + + exchangeRates.put(key12, new ExchangeRate(currency1, currency2, rate, unit)); + exchangeRates.put(key21, new ExchangeRate(currency2, currency1, recountedRate, unit)); + } /** @@ -26,10 +75,13 @@ * @param currency2 * the other currency * @return new instance of convertor + * @throws UnknownConvertorException + * thrown if convertor for selected currencies has not been defined */ - public static Convertor getConvertorInstance(Currency currency1, Currency currency2) { - if (currency1 == null || currency2 == null) + public static Convertor getConvertorInstance(Currency currency1, Currency currency2) throws UnknownConvertorException { + if (currency1 == null || currency2 == null) { throw new ConvertorException("None of the currencies should be null!!!"); + } return new Convertor(currency1, currency2); } @@ -37,30 +89,32 @@ * Converts selected amout of selected currency to other currency of this convertor instance. * @param amount * amount to convert - * @param actualCurrency + * @param originalCurrency * currency of this amount + * @param newCurrency + * currency to which we want convert * @return converted amount + * @throws InvalidCurrencyException + * while one or both currencies doesn't fit for this convertor */ - public double convert(double amount, Currency actualCurrency) { - ExchangeRate exchangeRate = null; + public double convert(double amount, Currency originalCurrency, Currency newCurrency) throws InvalidCurrencyException { + ExchangeRate actualyUsedExchangeRate = null; - if (actualCurrency == null) { - throw new ConvertorException("Selected currency is null!!!"); + if (originalCurrency == null) { + throw new ConvertorException("Original currency is null!!!"); } - if (currency1.getSymbol().equals(actualCurrency.getSymbol()) - || currency2.getSymbol().equals(actualCurrency.getSymbol())) { - exchangeRate = getExchangeRate(actualCurrency); - } else { - throw new ConvertorException("This convertor could not be used for selected currency(" - + actualCurrency.getCurrencyCode() + ") " + this + "!!!"); + if (newCurrency == null) { + throw new ConvertorException("Destination currency is null!!!"); } - return countResult(exchangeRate, amount); + actualyUsedExchangeRate = getExchangeRate(originalCurrency, newCurrency); + + return countResult(actualyUsedExchangeRate, amount); } - private double countResult(ExchangeRate exchangeRate, double amount) { - return amount * exchangeRate.getRate() / exchangeRate.getUnit(); + private double countResult(ExchangeRate actualyUsedExchangeRate, double amount) { + return amount * actualyUsedExchangeRate.getRate() / actualyUsedExchangeRate.getUnit(); } /** @@ -69,42 +123,27 @@ * actual currency we want to convert * @return actual exchange rate of this convertor for selected currency */ - private ExchangeRate getExchangeRate(Currency actualCurrency) { - ExchangeRate exchangeRate = null; + private ExchangeRate getExchangeRate(Currency originalCurrency, Currency newCurrency) throws InvalidCurrencyException { + ExchangeRate actualyUsedExchangeRate = null; - if (actualCurrency.getCurrencyCode().equals(currency1.getCurrencyCode())) { - exchangeRate = getExchangeRateInstance(actualCurrency, currency2); - } else if (actualCurrency.getCurrencyCode().equals(currency2.getCurrencyCode())) { - exchangeRate = getExchangeRateInstance(actualCurrency, currency1); + if (originalCurrency.getCurrencyCode().equals(exchangeRate12.getOriginalCurrency().getCurrencyCode()) + && newCurrency.getCurrencyCode().equals(exchangeRate12.getNewCurrency().getCurrencyCode())) { + actualyUsedExchangeRate = exchangeRate12; + } else if (originalCurrency.getCurrencyCode().equals(exchangeRate21.getOriginalCurrency().getCurrencyCode()) + && newCurrency.getCurrencyCode().equals(exchangeRate21.getNewCurrency().getCurrencyCode())) { + actualyUsedExchangeRate = exchangeRate21; + } else { + throw new InvalidCurrencyException("This convertor " + this + + " could not be used for converting selected currencies (" + originalCurrency.getCurrencyCode() + "->" + + newCurrency.getCurrencyCode() + ") !!!"); } - return exchangeRate; - } - - /** - * Returns actual exchange rate between original and destination currency. - * @param originalCurrency - * original currency, from which we want to convert - * @param newCurrency - * destination currency, to which we want to convert - * @return exchange rate between this two currencies - */ - private ExchangeRate getExchangeRateInstance(Currency originalCurrency, Currency newCurrency) { - if ("USD".equals(originalCurrency.getCurrencyCode()) && "CZK".equals(newCurrency.getCurrencyCode())) { - return new ExchangeRate(originalCurrency, newCurrency, 17d, 1d); - } else if ("CZK".equals(originalCurrency.getCurrencyCode()) && "USD".equals(newCurrency.getCurrencyCode())) { - return new ExchangeRate(originalCurrency, newCurrency, 1d / 17d, 1d); - } else if ("SKK".equals(originalCurrency.getCurrencyCode()) && "CZK".equals(newCurrency.getCurrencyCode())) { - return new ExchangeRate(originalCurrency, newCurrency, 80d, 100d); - } else if ("CZK".equals(originalCurrency.getCurrencyCode()) && "SKK".equals(newCurrency.getCurrencyCode())) { - return new ExchangeRate(originalCurrency, newCurrency, 100d / (80d / 100d), 100d); - } else { - throw new ConvertorException("Defined currencies don't have secified rates [" - + originalCurrency.getCurrencyCode() + ", " + newCurrency.getCurrencyCode() + "]!!!"); - } + return actualyUsedExchangeRate; } public String toString() { - return "Converter [" + currency1.getCurrencyCode() + ", " + currency2.getCurrencyCode() + "]"; + String currency1Code = exchangeRate12.getOriginalCurrency().getCurrencyCode(); + String currency2Code = exchangeRate12.getNewCurrency().getCurrencyCode(); + return "Converter [" + currency1Code + "->" + currency2Code + ", " + currency2Code + "->" + currency1Code + "]"; } } diff -r 45e6a2d1ffd1 -r 7ca97f802b5a task1/solution12/src/org/apidesign/apifest08/currency/exceptions/ConvertorException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/task1/solution12/src/org/apidesign/apifest08/currency/exceptions/ConvertorException.java Tue Sep 30 12:04:26 2008 +0200 @@ -0,0 +1,20 @@ +package org.apidesign.apifest08.currency.exceptions; + +public class ConvertorException extends RuntimeException { + + public ConvertorException() { + } + + public ConvertorException(String message) { + super(message); + } + + public ConvertorException(Throwable cause) { + super(cause); + } + + public ConvertorException(String message, Throwable cause) { + super(message, cause); + } + +} diff -r 45e6a2d1ffd1 -r 7ca97f802b5a task1/solution12/src/org/apidesign/apifest08/currency/exceptions/InvalidCurrencyException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/task1/solution12/src/org/apidesign/apifest08/currency/exceptions/InvalidCurrencyException.java Tue Sep 30 12:04:26 2008 +0200 @@ -0,0 +1,20 @@ +package org.apidesign.apifest08.currency.exceptions; + +public class InvalidCurrencyException extends Exception { + + public InvalidCurrencyException() { + } + + public InvalidCurrencyException(String message) { + super(message); + } + + public InvalidCurrencyException(Throwable cause) { + super(cause); + } + + public InvalidCurrencyException(String message, Throwable cause) { + super(message, cause); + } + +} diff -r 45e6a2d1ffd1 -r 7ca97f802b5a task1/solution12/src/org/apidesign/apifest08/currency/exceptions/UnknownConvertorException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/task1/solution12/src/org/apidesign/apifest08/currency/exceptions/UnknownConvertorException.java Tue Sep 30 12:04:26 2008 +0200 @@ -0,0 +1,20 @@ +package org.apidesign.apifest08.currency.exceptions; + +public class UnknownConvertorException extends Exception { + + public UnknownConvertorException() { + } + + public UnknownConvertorException(String message) { + super(message); + } + + public UnknownConvertorException(Throwable cause) { + super(cause); + } + + public UnknownConvertorException(String message, Throwable cause) { + super(message, cause); + } + +} diff -r 45e6a2d1ffd1 -r 7ca97f802b5a task1/solution12/test/org/apidesign/apifest08/test/Task1Test.java --- a/task1/solution12/test/org/apidesign/apifest08/test/Task1Test.java Tue Sep 30 12:01:18 2008 +0200 +++ b/task1/solution12/test/org/apidesign/apifest08/test/Task1Test.java Tue Sep 30 12:04:26 2008 +0200 @@ -5,6 +5,8 @@ import junit.framework.TestCase; import org.apidesign.apifest08.currency.Convertor; +import org.apidesign.apifest08.currency.exceptions.InvalidCurrencyException; +import org.apidesign.apifest08.currency.exceptions.UnknownConvertorException; /** * Finish the Convertor API, and then write bodies of methods inside of this class to match the given tasks. To fullfil @@ -24,40 +26,81 @@ protected void tearDown() throws Exception { } + // + // Imagine 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 design such API + // + /** - * Create convertor that understands two currencies, CZK and USD. Make 1 USD == 17 CZK. Creation of the convertor - * shall not require subclassing of any class or interface on the client side. + * Create convertor that understands two currencies, CZK and USD. Make 1 USD == 17 CZK. This is a method provided for + * #1 group - e.g. those that know the exchange rate. They somehow need to create the objects from the API and tell + * them the exchange rate. The API itself knows nothing about any rates, before the createCZKtoUSD method is called. + * Creation of the convertor shall not require subclassing of any class or interface on the client side. * @return prepared convertor ready for converting USD to CZK and CZK to USD */ public static Convertor createCZKtoUSD() { - return Convertor.getConvertorInstance(Currency.getInstance("CZK"), Currency.getInstance("USD")); + // set exchange rates + Convertor.setConvertorRates(Currency.getInstance("USD"), Currency.getInstance("CZK"), 17d, 1d); + + // create new instance + Convertor convertor = null; + try { + convertor = Convertor.getConvertorInstance(Currency.getInstance("USD"), Currency.getInstance("CZK")); + } catch (UnknownConvertorException e) { + e.printStackTrace(); + } + + return convertor; } /** - * Create convertor that understands two currencies, CZK and SKK. Make 100 SKK == 80 CZK. Creation of the convertor - * shall not require subclassing of any class or interface on the client side. + * Create convertor that understands two currencies, CZK and SKK. Make 100 SKK == 80 CZK. Again this is method for the + * #1 group - it 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. Creation of the convertor shall not require subclassing of + * any class or interface on the client side. * @return prepared convertor ready for converting SKK to CZK and CZK to SKK */ public static Convertor createSKKtoCZK() { - return Convertor.getConvertorInstance(Currency.getInstance("SKK"), Currency.getInstance("CZK")); + // set exchange rates + Convertor.setConvertorRates(Currency.getInstance("SKK"), Currency.getInstance("CZK"), 80d, 100d); + + // create new instance + Convertor convertor = null; + try { + convertor = Convertor.getConvertorInstance(Currency.getInstance("SKK"), Currency.getInstance("CZK")); + } catch (UnknownConvertorException e) { + e.printStackTrace(); + } + + return convertor; } + // + // now the methods for group #2 follow: + // this group knows nothing about exchange rates, but knows how to use + // the API to do conversions. It somehow (by calling one of the factory + // methods) gets objects from the API and uses them to do the conversions. + // + /** * Use the convertor from createCZKtoUSD method and do few conversions with it. */ public void testCurrencyCZKUSD() throws Exception { Convertor c = createCZKtoUSD(); - // convert $5 to CZK using c: - double result = c.convert(5, Currency.getInstance("USD")); + double result = c.convert(5, Currency.getInstance("USD"), Currency.getInstance("CZK")); assertEquals("Result is not 85 CZK", 85.0, result); // convert $8 to CZK - result = c.convert(8, Currency.getInstance("USD")); + result = c.convert(8, Currency.getInstance("USD"), Currency.getInstance("CZK")); assertEquals("Result is not 136 CZK", 136.0, result); // convert 1003CZK to USD - result = c.convert(1003, Currency.getInstance("CZK")); + result = c.convert(1003, Currency.getInstance("CZK"), Currency.getInstance("USD")); assertEquals("Result is not 59 USD", 59.0, result); } @@ -68,11 +111,64 @@ Convertor c = createSKKtoCZK(); // convert 16CZK using c: - double result = c.convert(16, Currency.getInstance("CZK")); + double result = c.convert(16, Currency.getInstance("CZK"), Currency.getInstance("SKK")); assertEquals("Result is not 20 SKK", 20.0, result); // convert 500SKK to CZK - result = c.convert(500, Currency.getInstance("SKK")); + result = c.convert(500, Currency.getInstance("SKK"), Currency.getInstance("CZK")); assertEquals("Result is not 400 CZK", 400.0, result); } + + /** + * Verify that the CZK to USD convertor knows nothing about SKK. + */ + public void testCannotConvertToSKKwithCZKUSDConvertor() throws Exception { + Convertor c = createCZKtoUSD(); + boolean exceptionThrown = false; + + // convert $5 to SKK, the API shall say this is not possible + try { + c.convert(5, Currency.getInstance("USD"), Currency.getInstance("SKK")); + exceptionThrown = false; + } catch (InvalidCurrencyException e) { + exceptionThrown = true; + } + assertEquals("It should be impossible to convert to SKK with USD->CZK convertor", true, exceptionThrown); + + // convert 500 SKK to CZK, the API shall say this is not possible + try { + c.convert(500, Currency.getInstance("SKK"), Currency.getInstance("CZK")); + exceptionThrown = false; + } catch (InvalidCurrencyException e) { + exceptionThrown = true; + } + assertEquals("It should be impossible to convert from SKK with USD->CZK convertor", true, exceptionThrown); + + } + + /** + * Verify that the CZK to SKK convertor knows nothing about USD. + */ + public void testCannotConvertToSKKwithSKKCZKConvertor() throws Exception { + Convertor c = createSKKtoCZK(); + boolean exceptionThrown = false; + + // convert $5 to SKK, the API shall say this is not possible + try { + c.convert(5, Currency.getInstance("USD"), Currency.getInstance("SKK")); + exceptionThrown = false; + } catch (InvalidCurrencyException e) { + exceptionThrown = true; + } + assertEquals("It should be impossible to convert form USD with SKK->CZK convertor", true, exceptionThrown); + + // convert 500 CZK to USD, the API shall say this is not possible + try { + c.convert(500, Currency.getInstance("CZK"), Currency.getInstance("USD")); + exceptionThrown = false; + } catch (InvalidCurrencyException e) { + exceptionThrown = true; + } + assertEquals("It should be impossible to convert to USD with SKK->CZK convertor", true, exceptionThrown); + } }