# HG changeset patch # User japod@localhost # Date 1222768209 -7200 # Node ID 37c9921c653e4801c1696ba1a41af0111ada8424 # Parent 2864c6d744c0b220358efb4bacf48df53e23dfde updating solution 04 to 1.5 diff -r 2864c6d744c0 -r 37c9921c653e task1/solution04/src/org/apidesign/apifest08/currency/ConverterImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/task1/solution04/src/org/apidesign/apifest08/currency/ConverterImpl.java Tue Sep 30 11:50:09 2008 +0200 @@ -0,0 +1,159 @@ +package org.apidesign.apifest08.currency; + + +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; +import java.util.Currency; + + +/** + * Convert between two currencies. + * + * @author D'Arcy Smith + * @version 1.0 + */ +final class ConvertorImpl + implements Convertor +{ + /** + * The currency to cvonvert from. + */ + private final Currency currencyA; + + /** + * The currency to cvonvert from. + */ + private final Currency currencyB; + + /** + * The echange rate between a and b. + */ + private final BigDecimal currencyARate; + + /** + * The echange rate between b and a. + */ + private final BigDecimal currencyBRate; + + /** + * Constructs a convertor with the specified currencies. + * + * @param a the currency to convert from. + * @param aRate the exchage rage between from and to. + * @param b the currency to convert to. + * @param bRate the exchage rage between to and from. + * @throws IllegalArgumentException if either any of the arguments are null or if either rate <= 0. + */ + public ConvertorImpl(final Currency a, + final BigDecimal aRate, + final Currency b, + final BigDecimal bRate) + { + if(a == null) + { + throw new IllegalArgumentException("a cannot be null"); + } + + if(b == null) + { + throw new IllegalArgumentException("b cannot be null"); + } + + if(aRate == null) + { + throw new IllegalArgumentException("aRate cannot be null"); + } + + if(bRate == null) + { + throw new IllegalArgumentException("bRate cannot be null"); + } + + if(aRate.compareTo(BigDecimal.ZERO) <= 0) + { + throw new IllegalArgumentException("aRate must be > 0, was: " + aRate); + } + + if(bRate.compareTo(BigDecimal.ZERO) <= 0) + { + throw new IllegalArgumentException("bRate must be > 0, was: " + bRate); + } + + currencyA = a; + currencyB = b; + currencyARate = aRate; + currencyBRate = bRate; + } + + /** + * Convert an amount from one currency to another. + * + * @param from the currency to convert from. + * @param to the currency to convert to. + * @param amount the amount to convert. + * @return the converted amount. + * @throws IllegalArgumentException if any of the arguments are null. + * @throws InvalidConversionException if either from or to are not equal to the currencies passed to the constructor. + */ + public BigDecimal convert(final Currency from, + final Currency to, + final BigDecimal amount) + throws InvalidConversionException + { + final BigDecimal result; + + if(amount == null) + { + throw new IllegalArgumentException("amount cannot be null"); + } + + if(from == null) + { + throw new IllegalArgumentException("from cannot be null"); + } + + if(to == null) + { + throw new IllegalArgumentException("to cannot be null"); + } + + if(!(from.equals(currencyA)) && (!(from.equals(currencyB)))) + { + throw new InvalidConversionException("cannot convert from: " + from.getCurrencyCode(), from, currencyA, currencyB); + } + + if(!(to.equals(currencyA)) && (!(to.equals(currencyB)))) + { + throw new InvalidConversionException("cannot convert to: " + to.getCurrencyCode(), to, currencyA, currencyB); + } + + // converting between the same currency is no converstion at all. + if(from.equals(to)) + { + result = amount; + } + else + { + final BigDecimal rateX; + final BigDecimal rateY; + final BigDecimal temp; + + if(from.equals(currencyA)) + { + rateX = currencyARate; + rateY = currencyBRate; + } + else + { + rateX = currencyBRate; + rateY = currencyARate; + } + + temp = amount.divide(rateX, MathContext.DECIMAL32); + result = temp.multiply(rateY); + } + + return (result.setScale(2, RoundingMode.HALF_DOWN)); + } +} diff -r 2864c6d744c0 -r 37c9921c653e task1/solution04/src/org/apidesign/apifest08/currency/Convertor.java --- a/task1/solution04/src/org/apidesign/apifest08/currency/Convertor.java Tue Sep 30 11:47:02 2008 +0200 +++ b/task1/solution04/src/org/apidesign/apifest08/currency/Convertor.java Tue Sep 30 11:50:09 2008 +0200 @@ -2,8 +2,6 @@ import java.math.BigDecimal; -import java.math.MathContext; -import java.math.RoundingMode; import java.util.Currency; @@ -13,93 +11,20 @@ * @author D'Arcy Smith * @version 1.0 */ -public final class Convertor +public interface Convertor { /** - * The currency to cvonvert from. - */ - private final Currency currencyA; - - /** - * The currency to cvonvert from. - */ - private final Currency currencyB; - - /** - * Constructs a convertor with the specified currencies. + * Convert an amount from one currency to another. * - * @param a the currency to convert from. - * @param b the currency to convert to. - * @throws IllegalArgumentException if either a or b are null. - */ - public Convertor(final Currency a, - final Currency b) - { - if(a == null) - { - throw new IllegalArgumentException("a cannot be null"); - } - - if(b == null) - { - throw new IllegalArgumentException("a cannot be null"); - } - - currencyA = a; - currencyB = b; - } - - /** - * Convert from currency "b" to currency "a". - * + * @param from the currency to convert from. + * @param to the currency to convert to. * @param amount the amount to convert. * @return the converted amount. - * @throws IllegalArgumentException if amount is null. + * @throws IllegalArgumentException if any of the arguments are null. + * @throws InvalidConversionException if either from or to are not valid for the convertor. */ - public BigDecimal convertFrom(final BigDecimal amount) - { - final BigDecimal aInUSD; - final BigDecimal bInUSD; - final BigDecimal temp; - final BigDecimal result; - - if(amount == null) - { - throw new IllegalArgumentException("amount cannot be null"); - } - - aInUSD = CurrencyValues.getValue(currencyA); - bInUSD = CurrencyValues.getValue(currencyB); - temp = amount.divide(bInUSD, MathContext.DECIMAL32); - result = temp.multiply(aInUSD); - - return (result.setScale(2, RoundingMode.HALF_DOWN)); - } - - /** - * Convert from currency "a" to currency "b". - * - * @param amount the amount to convert. - * @return the converted amount. - * @throws IllegalArgumentException if amount is null. - */ - public BigDecimal convertTo(final BigDecimal amount) - { - final BigDecimal aInUSD; - final BigDecimal bInUSD; - final BigDecimal temp; - final BigDecimal result; - - if(amount == null) - { - throw new IllegalArgumentException("amount cannot be null"); - } - - aInUSD = CurrencyValues.getValue(currencyA); - bInUSD = CurrencyValues.getValue(currencyB); - temp = amount.divide(aInUSD, MathContext.DECIMAL32); - result = temp.multiply(bInUSD); - - return (result.setScale(2, RoundingMode.HALF_DOWN)); - } + BigDecimal convert(Currency from, + Currency to, + BigDecimal amount) + throws InvalidConversionException; } diff -r 2864c6d744c0 -r 37c9921c653e task1/solution04/src/org/apidesign/apifest08/currency/ConvertorFactory.java --- a/task1/solution04/src/org/apidesign/apifest08/currency/ConvertorFactory.java Tue Sep 30 11:47:02 2008 +0200 +++ b/task1/solution04/src/org/apidesign/apifest08/currency/ConvertorFactory.java Tue Sep 30 11:50:09 2008 +0200 @@ -1,6 +1,7 @@ package org.apidesign.apifest08.currency; import java.lang.ref.WeakReference; +import java.math.BigDecimal; import java.util.Currency; import java.util.Map; import java.util.WeakHashMap; @@ -36,11 +37,16 @@ * must be acceptable to java.util.Currency.getInstance(String) * * @param a the currency to convert from. + * @param aRate the exchange rate for a to b. * @param b the currency to convert to. + * @param bRate the echante rate for b to a. * @return the convertor for the specified currencies. + * @throws IllegalArgumentException if any of the arguments are null. */ - public static Convertor getConvertor(final String a, - final String b) + public static Convertor getConvertor(final String a, + final BigDecimal aRate, + final String b, + final BigDecimal bRate) { final Currency currencyA; final Currency currencyB; @@ -48,7 +54,7 @@ currencyA = Currency.getInstance(a); currencyB = Currency.getInstance(b); - convertor = getConvertor(currencyA, currencyB); + convertor = getConvertor(currencyA, aRate, currencyB, bRate); return (convertor); } @@ -57,11 +63,16 @@ * Get the convertor for the specified currencies. * * @param a the currency to convert from. + * @param aRate the exchange rate for a to b. * @param b the currency to convert to. + * @param bRate the echante rate for b to a. * @return the convertor for the specified currencies. + * @throws IllegalArgumentException if either any of the arguments are null or if either rate <= 0. */ - public static Convertor getConvertor(final Currency a, - final Currency b) + public static Convertor getConvertor(final Currency a, + final BigDecimal aRate, + final Currency b, + final BigDecimal bRate) { final String key; Convertor convertor; @@ -75,15 +86,25 @@ { throw new IllegalArgumentException("b cannot be null"); } + + if(aRate == null) + { + throw new IllegalArgumentException("aRate cannot be null"); + } + + if(bRate == null) + { + throw new IllegalArgumentException("bRate cannot be null"); + } - key = a.getCurrencyCode() + b.getCurrencyCode(); + key = a.getCurrencyCode() + aRate + b.getCurrencyCode() + bRate; // make sure that we don't try to overwrite one synchronized(convertors) { if(!(convertors.containsKey(key))) { - convertor = new Convertor(a, b); + convertor = new ConvertorImpl(a, aRate, b, bRate); convertors.put(key, new WeakReference(convertor)); } } diff -r 2864c6d744c0 -r 37c9921c653e task1/solution04/src/org/apidesign/apifest08/currency/InvalidConversionException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/task1/solution04/src/org/apidesign/apifest08/currency/InvalidConversionException.java Tue Sep 30 11:50:09 2008 +0200 @@ -0,0 +1,82 @@ +package org.apidesign.apifest08.currency; + + +import java.util.Currency; + + +/** + * Thrown when a currency is invalid for a given Convertor. + * + * @author D'Arcy Smith + * @version 1.0 + */ +public class InvalidConversionException + extends Exception +{ + /** + * The currency that was tried. + */ + private final Currency badCurrency; + + /** + * A currency that is valid for the Convertor. + */ + private final Currency currencyA; + + /** + * A currency that is valid for the Convertor. + */ + private final Currency currencyB; + + /** + * Construct a new InvalidConversionException wit the specified message. + * + * @param msg the message for getMessage. + * @param bad the currency that is not valid. + * @param a a valid currency. + * @param b a valid currency. + */ + public InvalidConversionException(final String msg, + final Currency bad, + final Currency a, + final Currency b) + { + super(msg); + + badCurrency = bad; + currencyA = a; + currencyB = b; + } + + /** + * Get the currency that is not valid. + * + * @return the badCurrency + */ + public Currency getBadCurrency() + { + return (badCurrency); + } + + /** + * Get a currency that is valid. + * + * @return the currencyA passed to the constructor. + */ + public Currency getCurrencyA() + { + return (currencyA); + } + + /** + * Get a currency that is valid. + * + * @return the currencyB passed to the constructor. + */ + public Currency getCurrencyB() + { + return (currencyB); + } + + +} \ No newline at end of file diff -r 2864c6d744c0 -r 37c9921c653e task1/solution04/test/org/apidesign/apifest08/test/Task1Test.java --- a/task1/solution04/test/org/apidesign/apifest08/test/Task1Test.java Tue Sep 30 11:47:02 2008 +0200 +++ b/task1/solution04/test/org/apidesign/apifest08/test/Task1Test.java Tue Sep 30 11:50:09 2008 +0200 @@ -1,10 +1,13 @@ package org.apidesign.apifest08.test; + import java.math.BigDecimal; import java.util.Currency; import junit.framework.TestCase; import org.apidesign.apifest08.currency.Convertor; import org.apidesign.apifest08.currency.ConvertorFactory; +import org.apidesign.apifest08.currency.InvalidConversionException; + /** 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 @@ -13,6 +16,18 @@ * shall run without any runtime permissions. */ public class Task1Test extends TestCase { + + private final static Currency CZK; + private final static Currency SKK; + private final static Currency USD; + + static + { + CZK = Currency.getInstance("CZK"); + SKK = Currency.getInstance("SKK"); + USD = Currency.getInstance("USD"); + } + public Task1Test(String testName) { super(testName); } @@ -35,7 +50,7 @@ */ public static Convertor createCZKtoUSD() { - return (ConvertorFactory.getConvertor("CZK", "USD")); + return (ConvertorFactory.getConvertor("CZK", BigDecimal.valueOf(17.0), "USD", BigDecimal.valueOf(1))); } /** Create convertor that understands two currencies, CZK and @@ -48,12 +63,7 @@ */ public static Convertor createSKKtoCZK() { - return (ConvertorFactory.getConvertor(Currency.getInstance("SKK"), Currency.getInstance("CZK"))); - } - - public static Convertor createUSDtoUSD() - { - return (ConvertorFactory.getConvertor(Currency.getInstance("USD"), Currency.getInstance("USD"))); + return (ConvertorFactory.getConvertor(Currency.getInstance("SKK"), BigDecimal.valueOf(100), Currency.getInstance("CZK"), BigDecimal.valueOf(80))); } /** Use the convertor from createCZKtoUSD method and do few conversions @@ -65,17 +75,17 @@ // convert $5 to CZK using c: // assertEquals("Result is 85 CZK"); - result = c.convertFrom(BigDecimal.valueOf(5)); + result = c.convert(USD, CZK, BigDecimal.valueOf(5)); assertEquals(new BigDecimal("85.00"), result); // convert $8 to CZK // assertEquals("Result is 136 CZK"); - result = c.convertFrom(BigDecimal.valueOf(8)); + result = c.convert(USD, CZK, BigDecimal.valueOf(8)); assertEquals(new BigDecimal("136.00"), result); // convert 1003CZK to USD // assertEquals("Result is 59 USD"); - result = c.convertTo(BigDecimal.valueOf(1003)); + result = c.convert(CZK, USD, BigDecimal.valueOf(1003)); assertEquals(new BigDecimal("59.00"), result); } @@ -88,31 +98,87 @@ // convert 16CZK using c: // assertEquals("Result is 20 SKK"); - result = c.convertFrom(BigDecimal.valueOf(16)); + result = c.convert(CZK, SKK, BigDecimal.valueOf(16)); assertEquals(new BigDecimal("20.00"), result); // convert 500SKK to CZK // assertEquals("Result is 400 CZK"); - result = c.convertTo(BigDecimal.valueOf(500)); + result = c.convert(SKK, CZK, BigDecimal.valueOf(500)); assertEquals(new BigDecimal("400.00"), result); } - /** Use the convertor from createSKKtoCZK method and do few conversions - * with it. + /** + * Verify that the CZK to USD convertor knows nothing about SKK. */ - public void testCurrencyUSDUSD() throws Exception { - Convertor c = createUSDtoUSD(); - BigDecimal result; + public void testCannotConvertToSKKwithCZKUSDConvertor() + throws Exception + { + Convertor c = createCZKtoUSD(); - // convert 1USD using c: - // assertEquals("Result is 1 USD"); - result = c.convertFrom(BigDecimal.valueOf(1)); - assertEquals(new BigDecimal("1.00"), result); - - // convert 500USD to USD - // assertEquals("Result is 500 USD"); - result = c.convertTo(BigDecimal.valueOf(500)); - assertEquals(new BigDecimal("500.00"), result); - } + try + { + // convert $5 to SKK, the API shall say this is not possible + c.convert(USD, SKK, BigDecimal.valueOf(5)); + fail("cannot use the CZKtoUSD converter to convert to SKK"); + } + catch(InvalidConversionException ex) + { + assertEquals("cannot convert to: SKK", ex.getMessage()); + assertEquals(SKK, ex.getBadCurrency()); + assertEquals(CZK, ex.getCurrencyA()); + assertEquals(USD, ex.getCurrencyB()); + } + + try + { + // convert 500 SKK to CZK, the API shall say this is not possible + c.convert(SKK, CZK, BigDecimal.valueOf(5)); + fail("cannot use the CZKtoUSD converter to convert from SKK"); + } + catch(InvalidConversionException ex) + { + assertEquals("cannot convert from: SKK", ex.getMessage()); + assertEquals(SKK, ex.getBadCurrency()); + assertEquals(CZK, ex.getCurrencyA()); + assertEquals(USD, ex.getCurrencyB()); + } + } + + /** + * Verify that the CZK to SKK convertor knows nothing about USD. + */ + public void testCannotConvertToUSDwithSKKCZKConvertor() + throws Exception + { + Convertor c = createSKKtoCZK(); + + try + { + // convert $5 to SKK, the API shall say this is not possible + c.convert(USD, SKK, BigDecimal.valueOf(5)); + fail("cannot use the CZKtoUSD converter to convert to SKK"); + } + catch(InvalidConversionException ex) + { + assertEquals("cannot convert from: USD", ex.getMessage()); + assertEquals(USD, ex.getBadCurrency()); + assertEquals(SKK, ex.getCurrencyA()); + assertEquals(CZK, ex.getCurrencyB()); + } + + try + { + // convert 500 CZK to USD, the API shall say this is not possible + c.convert(CZK, USD, BigDecimal.valueOf(500)); + fail("cannot use the CZKtoUSD converter to convert from SKK"); + } + catch(InvalidConversionException ex) + { + assertEquals("cannot convert to: USD", ex.getMessage()); + assertEquals(USD, ex.getBadCurrency()); + assertEquals(SKK, ex.getCurrencyA()); + assertEquals(CZK, ex.getCurrencyB()); + } + } }