1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/task1/solution04/src/org/apidesign/apifest08/currency/ConverterImpl.java Tue Sep 30 11:50:09 2008 +0200
1.3 @@ -0,0 +1,159 @@
1.4 +package org.apidesign.apifest08.currency;
1.5 +
1.6 +
1.7 +import java.math.BigDecimal;
1.8 +import java.math.MathContext;
1.9 +import java.math.RoundingMode;
1.10 +import java.util.Currency;
1.11 +
1.12 +
1.13 +/**
1.14 + * Convert between two currencies.
1.15 + *
1.16 + * @author D'Arcy Smith
1.17 + * @version 1.0
1.18 + */
1.19 +final class ConvertorImpl
1.20 + implements Convertor
1.21 +{
1.22 + /**
1.23 + * The currency to cvonvert from.
1.24 + */
1.25 + private final Currency currencyA;
1.26 +
1.27 + /**
1.28 + * The currency to cvonvert from.
1.29 + */
1.30 + private final Currency currencyB;
1.31 +
1.32 + /**
1.33 + * The echange rate between a and b.
1.34 + */
1.35 + private final BigDecimal currencyARate;
1.36 +
1.37 + /**
1.38 + * The echange rate between b and a.
1.39 + */
1.40 + private final BigDecimal currencyBRate;
1.41 +
1.42 + /**
1.43 + * Constructs a convertor with the specified currencies.
1.44 + *
1.45 + * @param a the currency to convert from.
1.46 + * @param aRate the exchage rage between from and to.
1.47 + * @param b the currency to convert to.
1.48 + * @param bRate the exchage rage between to and from.
1.49 + * @throws IllegalArgumentException if either any of the arguments are null or if either rate <= 0.
1.50 + */
1.51 + public ConvertorImpl(final Currency a,
1.52 + final BigDecimal aRate,
1.53 + final Currency b,
1.54 + final BigDecimal bRate)
1.55 + {
1.56 + if(a == null)
1.57 + {
1.58 + throw new IllegalArgumentException("a cannot be null");
1.59 + }
1.60 +
1.61 + if(b == null)
1.62 + {
1.63 + throw new IllegalArgumentException("b cannot be null");
1.64 + }
1.65 +
1.66 + if(aRate == null)
1.67 + {
1.68 + throw new IllegalArgumentException("aRate cannot be null");
1.69 + }
1.70 +
1.71 + if(bRate == null)
1.72 + {
1.73 + throw new IllegalArgumentException("bRate cannot be null");
1.74 + }
1.75 +
1.76 + if(aRate.compareTo(BigDecimal.ZERO) <= 0)
1.77 + {
1.78 + throw new IllegalArgumentException("aRate must be > 0, was: " + aRate);
1.79 + }
1.80 +
1.81 + if(bRate.compareTo(BigDecimal.ZERO) <= 0)
1.82 + {
1.83 + throw new IllegalArgumentException("bRate must be > 0, was: " + bRate);
1.84 + }
1.85 +
1.86 + currencyA = a;
1.87 + currencyB = b;
1.88 + currencyARate = aRate;
1.89 + currencyBRate = bRate;
1.90 + }
1.91 +
1.92 + /**
1.93 + * Convert an amount from one currency to another.
1.94 + *
1.95 + * @param from the currency to convert from.
1.96 + * @param to the currency to convert to.
1.97 + * @param amount the amount to convert.
1.98 + * @return the converted amount.
1.99 + * @throws IllegalArgumentException if any of the arguments are null.
1.100 + * @throws InvalidConversionException if either from or to are not equal to the currencies passed to the constructor.
1.101 + */
1.102 + public BigDecimal convert(final Currency from,
1.103 + final Currency to,
1.104 + final BigDecimal amount)
1.105 + throws InvalidConversionException
1.106 + {
1.107 + final BigDecimal result;
1.108 +
1.109 + if(amount == null)
1.110 + {
1.111 + throw new IllegalArgumentException("amount cannot be null");
1.112 + }
1.113 +
1.114 + if(from == null)
1.115 + {
1.116 + throw new IllegalArgumentException("from cannot be null");
1.117 + }
1.118 +
1.119 + if(to == null)
1.120 + {
1.121 + throw new IllegalArgumentException("to cannot be null");
1.122 + }
1.123 +
1.124 + if(!(from.equals(currencyA)) && (!(from.equals(currencyB))))
1.125 + {
1.126 + throw new InvalidConversionException("cannot convert from: " + from.getCurrencyCode(), from, currencyA, currencyB);
1.127 + }
1.128 +
1.129 + if(!(to.equals(currencyA)) && (!(to.equals(currencyB))))
1.130 + {
1.131 + throw new InvalidConversionException("cannot convert to: " + to.getCurrencyCode(), to, currencyA, currencyB);
1.132 + }
1.133 +
1.134 + // converting between the same currency is no converstion at all.
1.135 + if(from.equals(to))
1.136 + {
1.137 + result = amount;
1.138 + }
1.139 + else
1.140 + {
1.141 + final BigDecimal rateX;
1.142 + final BigDecimal rateY;
1.143 + final BigDecimal temp;
1.144 +
1.145 + if(from.equals(currencyA))
1.146 + {
1.147 + rateX = currencyARate;
1.148 + rateY = currencyBRate;
1.149 + }
1.150 + else
1.151 + {
1.152 + rateX = currencyBRate;
1.153 + rateY = currencyARate;
1.154 + }
1.155 +
1.156 + temp = amount.divide(rateX, MathContext.DECIMAL32);
1.157 + result = temp.multiply(rateY);
1.158 + }
1.159 +
1.160 + return (result.setScale(2, RoundingMode.HALF_DOWN));
1.161 + }
1.162 +}
2.1 --- a/task1/solution04/src/org/apidesign/apifest08/currency/Convertor.java Tue Sep 30 11:47:02 2008 +0200
2.2 +++ b/task1/solution04/src/org/apidesign/apifest08/currency/Convertor.java Tue Sep 30 11:50:09 2008 +0200
2.3 @@ -2,8 +2,6 @@
2.4
2.5
2.6 import java.math.BigDecimal;
2.7 -import java.math.MathContext;
2.8 -import java.math.RoundingMode;
2.9 import java.util.Currency;
2.10
2.11
2.12 @@ -13,93 +11,20 @@
2.13 * @author D'Arcy Smith
2.14 * @version 1.0
2.15 */
2.16 -public final class Convertor
2.17 +public interface Convertor
2.18 {
2.19 /**
2.20 - * The currency to cvonvert from.
2.21 - */
2.22 - private final Currency currencyA;
2.23 -
2.24 - /**
2.25 - * The currency to cvonvert from.
2.26 - */
2.27 - private final Currency currencyB;
2.28 -
2.29 - /**
2.30 - * Constructs a convertor with the specified currencies.
2.31 + * Convert an amount from one currency to another.
2.32 *
2.33 - * @param a the currency to convert from.
2.34 - * @param b the currency to convert to.
2.35 - * @throws IllegalArgumentException if either a or b are null.
2.36 - */
2.37 - public Convertor(final Currency a,
2.38 - final Currency b)
2.39 - {
2.40 - if(a == null)
2.41 - {
2.42 - throw new IllegalArgumentException("a cannot be null");
2.43 - }
2.44 -
2.45 - if(b == null)
2.46 - {
2.47 - throw new IllegalArgumentException("a cannot be null");
2.48 - }
2.49 -
2.50 - currencyA = a;
2.51 - currencyB = b;
2.52 - }
2.53 -
2.54 - /**
2.55 - * Convert from currency "b" to currency "a".
2.56 - *
2.57 + * @param from the currency to convert from.
2.58 + * @param to the currency to convert to.
2.59 * @param amount the amount to convert.
2.60 * @return the converted amount.
2.61 - * @throws IllegalArgumentException if amount is null.
2.62 + * @throws IllegalArgumentException if any of the arguments are null.
2.63 + * @throws InvalidConversionException if either from or to are not valid for the convertor.
2.64 */
2.65 - public BigDecimal convertFrom(final BigDecimal amount)
2.66 - {
2.67 - final BigDecimal aInUSD;
2.68 - final BigDecimal bInUSD;
2.69 - final BigDecimal temp;
2.70 - final BigDecimal result;
2.71 -
2.72 - if(amount == null)
2.73 - {
2.74 - throw new IllegalArgumentException("amount cannot be null");
2.75 - }
2.76 -
2.77 - aInUSD = CurrencyValues.getValue(currencyA);
2.78 - bInUSD = CurrencyValues.getValue(currencyB);
2.79 - temp = amount.divide(bInUSD, MathContext.DECIMAL32);
2.80 - result = temp.multiply(aInUSD);
2.81 -
2.82 - return (result.setScale(2, RoundingMode.HALF_DOWN));
2.83 - }
2.84 -
2.85 - /**
2.86 - * Convert from currency "a" to currency "b".
2.87 - *
2.88 - * @param amount the amount to convert.
2.89 - * @return the converted amount.
2.90 - * @throws IllegalArgumentException if amount is null.
2.91 - */
2.92 - public BigDecimal convertTo(final BigDecimal amount)
2.93 - {
2.94 - final BigDecimal aInUSD;
2.95 - final BigDecimal bInUSD;
2.96 - final BigDecimal temp;
2.97 - final BigDecimal result;
2.98 -
2.99 - if(amount == null)
2.100 - {
2.101 - throw new IllegalArgumentException("amount cannot be null");
2.102 - }
2.103 -
2.104 - aInUSD = CurrencyValues.getValue(currencyA);
2.105 - bInUSD = CurrencyValues.getValue(currencyB);
2.106 - temp = amount.divide(aInUSD, MathContext.DECIMAL32);
2.107 - result = temp.multiply(bInUSD);
2.108 -
2.109 - return (result.setScale(2, RoundingMode.HALF_DOWN));
2.110 - }
2.111 + BigDecimal convert(Currency from,
2.112 + Currency to,
2.113 + BigDecimal amount)
2.114 + throws InvalidConversionException;
2.115 }
3.1 --- a/task1/solution04/src/org/apidesign/apifest08/currency/ConvertorFactory.java Tue Sep 30 11:47:02 2008 +0200
3.2 +++ b/task1/solution04/src/org/apidesign/apifest08/currency/ConvertorFactory.java Tue Sep 30 11:50:09 2008 +0200
3.3 @@ -1,6 +1,7 @@
3.4 package org.apidesign.apifest08.currency;
3.5
3.6 import java.lang.ref.WeakReference;
3.7 +import java.math.BigDecimal;
3.8 import java.util.Currency;
3.9 import java.util.Map;
3.10 import java.util.WeakHashMap;
3.11 @@ -36,11 +37,16 @@
3.12 * must be acceptable to java.util.Currency.getInstance(String)
3.13 *
3.14 * @param a the currency to convert from.
3.15 + * @param aRate the exchange rate for a to b.
3.16 * @param b the currency to convert to.
3.17 + * @param bRate the echante rate for b to a.
3.18 * @return the convertor for the specified currencies.
3.19 + * @throws IllegalArgumentException if any of the arguments are null.
3.20 */
3.21 - public static Convertor getConvertor(final String a,
3.22 - final String b)
3.23 + public static Convertor getConvertor(final String a,
3.24 + final BigDecimal aRate,
3.25 + final String b,
3.26 + final BigDecimal bRate)
3.27 {
3.28 final Currency currencyA;
3.29 final Currency currencyB;
3.30 @@ -48,7 +54,7 @@
3.31
3.32 currencyA = Currency.getInstance(a);
3.33 currencyB = Currency.getInstance(b);
3.34 - convertor = getConvertor(currencyA, currencyB);
3.35 + convertor = getConvertor(currencyA, aRate, currencyB, bRate);
3.36
3.37 return (convertor);
3.38 }
3.39 @@ -57,11 +63,16 @@
3.40 * Get the convertor for the specified currencies.
3.41 *
3.42 * @param a the currency to convert from.
3.43 + * @param aRate the exchange rate for a to b.
3.44 * @param b the currency to convert to.
3.45 + * @param bRate the echante rate for b to a.
3.46 * @return the convertor for the specified currencies.
3.47 + * @throws IllegalArgumentException if either any of the arguments are null or if either rate <= 0.
3.48 */
3.49 - public static Convertor getConvertor(final Currency a,
3.50 - final Currency b)
3.51 + public static Convertor getConvertor(final Currency a,
3.52 + final BigDecimal aRate,
3.53 + final Currency b,
3.54 + final BigDecimal bRate)
3.55 {
3.56 final String key;
3.57 Convertor convertor;
3.58 @@ -75,15 +86,25 @@
3.59 {
3.60 throw new IllegalArgumentException("b cannot be null");
3.61 }
3.62 +
3.63 + if(aRate == null)
3.64 + {
3.65 + throw new IllegalArgumentException("aRate cannot be null");
3.66 + }
3.67 +
3.68 + if(bRate == null)
3.69 + {
3.70 + throw new IllegalArgumentException("bRate cannot be null");
3.71 + }
3.72
3.73 - key = a.getCurrencyCode() + b.getCurrencyCode();
3.74 + key = a.getCurrencyCode() + aRate + b.getCurrencyCode() + bRate;
3.75
3.76 // make sure that we don't try to overwrite one
3.77 synchronized(convertors)
3.78 {
3.79 if(!(convertors.containsKey(key)))
3.80 {
3.81 - convertor = new Convertor(a, b);
3.82 + convertor = new ConvertorImpl(a, aRate, b, bRate);
3.83 convertors.put(key, new WeakReference(convertor));
3.84 }
3.85 }
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/task1/solution04/src/org/apidesign/apifest08/currency/InvalidConversionException.java Tue Sep 30 11:50:09 2008 +0200
4.3 @@ -0,0 +1,82 @@
4.4 +package org.apidesign.apifest08.currency;
4.5 +
4.6 +
4.7 +import java.util.Currency;
4.8 +
4.9 +
4.10 +/**
4.11 + * Thrown when a currency is invalid for a given Convertor.
4.12 + *
4.13 + * @author D'Arcy Smith
4.14 + * @version 1.0
4.15 + */
4.16 +public class InvalidConversionException
4.17 + extends Exception
4.18 +{
4.19 + /**
4.20 + * The currency that was tried.
4.21 + */
4.22 + private final Currency badCurrency;
4.23 +
4.24 + /**
4.25 + * A currency that is valid for the Convertor.
4.26 + */
4.27 + private final Currency currencyA;
4.28 +
4.29 + /**
4.30 + * A currency that is valid for the Convertor.
4.31 + */
4.32 + private final Currency currencyB;
4.33 +
4.34 + /**
4.35 + * Construct a new InvalidConversionException wit the specified message.
4.36 + *
4.37 + * @param msg the message for getMessage.
4.38 + * @param bad the currency that is not valid.
4.39 + * @param a a valid currency.
4.40 + * @param b a valid currency.
4.41 + */
4.42 + public InvalidConversionException(final String msg,
4.43 + final Currency bad,
4.44 + final Currency a,
4.45 + final Currency b)
4.46 + {
4.47 + super(msg);
4.48 +
4.49 + badCurrency = bad;
4.50 + currencyA = a;
4.51 + currencyB = b;
4.52 + }
4.53 +
4.54 + /**
4.55 + * Get the currency that is not valid.
4.56 + *
4.57 + * @return the badCurrency
4.58 + */
4.59 + public Currency getBadCurrency()
4.60 + {
4.61 + return (badCurrency);
4.62 + }
4.63 +
4.64 + /**
4.65 + * Get a currency that is valid.
4.66 + *
4.67 + * @return the currencyA passed to the constructor.
4.68 + */
4.69 + public Currency getCurrencyA()
4.70 + {
4.71 + return (currencyA);
4.72 + }
4.73 +
4.74 + /**
4.75 + * Get a currency that is valid.
4.76 + *
4.77 + * @return the currencyB passed to the constructor.
4.78 + */
4.79 + public Currency getCurrencyB()
4.80 + {
4.81 + return (currencyB);
4.82 + }
4.83 +
4.84 +
4.85 +}
4.86 \ No newline at end of file
5.1 --- a/task1/solution04/test/org/apidesign/apifest08/test/Task1Test.java Tue Sep 30 11:47:02 2008 +0200
5.2 +++ b/task1/solution04/test/org/apidesign/apifest08/test/Task1Test.java Tue Sep 30 11:50:09 2008 +0200
5.3 @@ -1,10 +1,13 @@
5.4 package org.apidesign.apifest08.test;
5.5
5.6 +
5.7 import java.math.BigDecimal;
5.8 import java.util.Currency;
5.9 import junit.framework.TestCase;
5.10 import org.apidesign.apifest08.currency.Convertor;
5.11 import org.apidesign.apifest08.currency.ConvertorFactory;
5.12 +import org.apidesign.apifest08.currency.InvalidConversionException;
5.13 +
5.14
5.15 /** Finish the Convertor API, and then write bodies of methods inside
5.16 * of this class to match the given tasks. To fullfil your task, use the
5.17 @@ -13,6 +16,18 @@
5.18 * shall run without any runtime permissions.
5.19 */
5.20 public class Task1Test extends TestCase {
5.21 +
5.22 + private final static Currency CZK;
5.23 + private final static Currency SKK;
5.24 + private final static Currency USD;
5.25 +
5.26 + static
5.27 + {
5.28 + CZK = Currency.getInstance("CZK");
5.29 + SKK = Currency.getInstance("SKK");
5.30 + USD = Currency.getInstance("USD");
5.31 + }
5.32 +
5.33 public Task1Test(String testName) {
5.34 super(testName);
5.35 }
5.36 @@ -35,7 +50,7 @@
5.37 */
5.38 public static Convertor createCZKtoUSD()
5.39 {
5.40 - return (ConvertorFactory.getConvertor("CZK", "USD"));
5.41 + return (ConvertorFactory.getConvertor("CZK", BigDecimal.valueOf(17.0), "USD", BigDecimal.valueOf(1)));
5.42 }
5.43
5.44 /** Create convertor that understands two currencies, CZK and
5.45 @@ -48,12 +63,7 @@
5.46 */
5.47 public static Convertor createSKKtoCZK()
5.48 {
5.49 - return (ConvertorFactory.getConvertor(Currency.getInstance("SKK"), Currency.getInstance("CZK")));
5.50 - }
5.51 -
5.52 - public static Convertor createUSDtoUSD()
5.53 - {
5.54 - return (ConvertorFactory.getConvertor(Currency.getInstance("USD"), Currency.getInstance("USD")));
5.55 + return (ConvertorFactory.getConvertor(Currency.getInstance("SKK"), BigDecimal.valueOf(100), Currency.getInstance("CZK"), BigDecimal.valueOf(80)));
5.56 }
5.57
5.58 /** Use the convertor from <code>createCZKtoUSD</code> method and do few conversions
5.59 @@ -65,17 +75,17 @@
5.60
5.61 // convert $5 to CZK using c:
5.62 // assertEquals("Result is 85 CZK");
5.63 - result = c.convertFrom(BigDecimal.valueOf(5));
5.64 + result = c.convert(USD, CZK, BigDecimal.valueOf(5));
5.65 assertEquals(new BigDecimal("85.00"), result);
5.66
5.67 // convert $8 to CZK
5.68 // assertEquals("Result is 136 CZK");
5.69 - result = c.convertFrom(BigDecimal.valueOf(8));
5.70 + result = c.convert(USD, CZK, BigDecimal.valueOf(8));
5.71 assertEquals(new BigDecimal("136.00"), result);
5.72
5.73 // convert 1003CZK to USD
5.74 // assertEquals("Result is 59 USD");
5.75 - result = c.convertTo(BigDecimal.valueOf(1003));
5.76 + result = c.convert(CZK, USD, BigDecimal.valueOf(1003));
5.77 assertEquals(new BigDecimal("59.00"), result);
5.78 }
5.79
5.80 @@ -88,31 +98,87 @@
5.81
5.82 // convert 16CZK using c:
5.83 // assertEquals("Result is 20 SKK");
5.84 - result = c.convertFrom(BigDecimal.valueOf(16));
5.85 + result = c.convert(CZK, SKK, BigDecimal.valueOf(16));
5.86 assertEquals(new BigDecimal("20.00"), result);
5.87
5.88 // convert 500SKK to CZK
5.89 // assertEquals("Result is 400 CZK");
5.90 - result = c.convertTo(BigDecimal.valueOf(500));
5.91 + result = c.convert(SKK, CZK, BigDecimal.valueOf(500));
5.92 assertEquals(new BigDecimal("400.00"), result);
5.93 }
5.94
5.95 - /** Use the convertor from <code>createSKKtoCZK</code> method and do few conversions
5.96 - * with it.
5.97 + /**
5.98 + * Verify that the CZK to USD convertor knows nothing about SKK.
5.99 */
5.100 - public void testCurrencyUSDUSD() throws Exception {
5.101 - Convertor c = createUSDtoUSD();
5.102 - BigDecimal result;
5.103 + public void testCannotConvertToSKKwithCZKUSDConvertor()
5.104 + throws Exception
5.105 + {
5.106 + Convertor c = createCZKtoUSD();
5.107
5.108 - // convert 1USD using c:
5.109 - // assertEquals("Result is 1 USD");
5.110 - result = c.convertFrom(BigDecimal.valueOf(1));
5.111 - assertEquals(new BigDecimal("1.00"), result);
5.112 -
5.113 - // convert 500USD to USD
5.114 - // assertEquals("Result is 500 USD");
5.115 - result = c.convertTo(BigDecimal.valueOf(500));
5.116 - assertEquals(new BigDecimal("500.00"), result);
5.117 - }
5.118 + try
5.119 + {
5.120 + // convert $5 to SKK, the API shall say this is not possible
5.121 + c.convert(USD, SKK, BigDecimal.valueOf(5));
5.122 + fail("cannot use the CZKtoUSD converter to convert to SKK");
5.123 + }
5.124 + catch(InvalidConversionException ex)
5.125 + {
5.126 + assertEquals("cannot convert to: SKK", ex.getMessage());
5.127 + assertEquals(SKK, ex.getBadCurrency());
5.128 + assertEquals(CZK, ex.getCurrencyA());
5.129 + assertEquals(USD, ex.getCurrencyB());
5.130 + }
5.131 +
5.132 + try
5.133 + {
5.134 + // convert 500 SKK to CZK, the API shall say this is not possible
5.135 + c.convert(SKK, CZK, BigDecimal.valueOf(5));
5.136 + fail("cannot use the CZKtoUSD converter to convert from SKK");
5.137 + }
5.138 + catch(InvalidConversionException ex)
5.139 + {
5.140 + assertEquals("cannot convert from: SKK", ex.getMessage());
5.141 + assertEquals(SKK, ex.getBadCurrency());
5.142 + assertEquals(CZK, ex.getCurrencyA());
5.143 + assertEquals(USD, ex.getCurrencyB());
5.144 + }
5.145 + }
5.146 +
5.147 + /**
5.148 + * Verify that the CZK to SKK convertor knows nothing about USD.
5.149 + */
5.150 + public void testCannotConvertToUSDwithSKKCZKConvertor()
5.151 + throws Exception
5.152 + {
5.153 + Convertor c = createSKKtoCZK();
5.154 +
5.155 + try
5.156 + {
5.157 + // convert $5 to SKK, the API shall say this is not possible
5.158 + c.convert(USD, SKK, BigDecimal.valueOf(5));
5.159 + fail("cannot use the CZKtoUSD converter to convert to SKK");
5.160 + }
5.161 + catch(InvalidConversionException ex)
5.162 + {
5.163 + assertEquals("cannot convert from: USD", ex.getMessage());
5.164 + assertEquals(USD, ex.getBadCurrency());
5.165 + assertEquals(SKK, ex.getCurrencyA());
5.166 + assertEquals(CZK, ex.getCurrencyB());
5.167 + }
5.168 +
5.169 + try
5.170 + {
5.171 + // convert 500 CZK to USD, the API shall say this is not possible
5.172 + c.convert(CZK, USD, BigDecimal.valueOf(500));
5.173 + fail("cannot use the CZKtoUSD converter to convert from SKK");
5.174 + }
5.175 + catch(InvalidConversionException ex)
5.176 + {
5.177 + assertEquals("cannot convert to: USD", ex.getMessage());
5.178 + assertEquals(USD, ex.getBadCurrency());
5.179 + assertEquals(SKK, ex.getCurrencyA());
5.180 + assertEquals(CZK, ex.getCurrencyB());
5.181 + }
5.182 + }
5.183 }
5.184