solution04 task3
authorjapod@localhost
Fri, 10 Oct 2008 22:05:15 +0200
changeset 5514e78f48ac2b
parent 54 1b300c79f4ce
child 56 a3144e7f9c90
solution04 task3
task3/solution04/src/org/apidesign/apifest08/currency/CompositeConvertorImpl.java
task3/solution04/src/org/apidesign/apifest08/currency/ConverterImpl.java
task3/solution04/src/org/apidesign/apifest08/currency/ConvertorFactory.java
task3/solution04/src/org/apidesign/apifest08/currency/ExchangeRate.java
task3/solution04/src/org/apidesign/apifest08/currency/ExchangeRateFinder.java
task3/solution04/src/org/apidesign/apifest08/currency/OnlineConvertor.java
task3/solution04/test/org/apidesign/apifest08/test/Task3Test.java
task3/solution04/test/org/apidesign/apifest08/test/TestExchangeRateFinder.java
     1.1 --- a/task3/solution04/src/org/apidesign/apifest08/currency/CompositeConvertorImpl.java	Fri Oct 10 22:02:31 2008 +0200
     1.2 +++ b/task3/solution04/src/org/apidesign/apifest08/currency/CompositeConvertorImpl.java	Fri Oct 10 22:05:15 2008 +0200
     1.3 @@ -16,7 +16,7 @@
     1.4   * A composite convertor will build all possible conversions that are allowed by the underlying set of convertors.
     1.5   *
     1.6   * @author D'Arcy Smith
     1.7 - * @verson 1.0
     1.8 + * @verson 1.1
     1.9   */
    1.10  final class CompositeConvertorImpl
    1.11      implements Convertor
    1.12 @@ -220,6 +220,38 @@
    1.13          return (convertor.getConversionRate(from, to));
    1.14      }
    1.15  
    1.16 +    private Convertor getConvertor(final Currency from, final Currency to)
    1.17 +        throws InvalidConversionException
    1.18 +    {
    1.19 +        final Map<Currency, Convertor> possible;
    1.20 +        Convertor                      convertor;
    1.21 +
    1.22 +        if(from == null)
    1.23 +        {
    1.24 +            throw new IllegalArgumentException("from cannot be null");
    1.25 +        }
    1.26 +        
    1.27 +        if(to == null)
    1.28 +        {
    1.29 +            throw new IllegalArgumentException("to cannot be null");
    1.30 +        }
    1.31 +        
    1.32 +        if(!(canConvert(from, to)))
    1.33 +        {
    1.34 +            throw new InvalidConversionException("cannot convert", to);
    1.35 +        }
    1.36 +
    1.37 +        possible  = possibleConversions.get(from);
    1.38 +        convertor = possible.get(to);
    1.39 +
    1.40 +        if(convertor == null)
    1.41 +        {
    1.42 +            throw new Error();
    1.43 +        }
    1.44 +
    1.45 +        return (convertor);
    1.46 +    }
    1.47 +
    1.48      /**
    1.49       * Convert an amount from one currency to another.
    1.50       * 
    1.51 @@ -236,6 +268,7 @@
    1.52          throws InvalidConversionException
    1.53      {
    1.54          final BigDecimal result;
    1.55 +        final Convertor  convertor;
    1.56          
    1.57          if(amount == null)
    1.58          {
    1.59 @@ -252,7 +285,11 @@
    1.60              throw new IllegalArgumentException("to cannot be null");
    1.61          }
    1.62  
    1.63 -        result = amount.multiply(getConversionRate(from, to));
    1.64 +        // fixed a bug from Task2 that showed up in Task3... before we did the conversion here,
    1.65 +        // but that meant that the underlying covnerter convert method never got called... which
    1.66 +        // meant that in Task3 the exchange rate never changed.
    1.67 +        convertor = getConvertor(from, to);
    1.68 +        result    = convertor.convert(from, to, amount);
    1.69  
    1.70          return (result.setScale(2, RoundingMode.HALF_DOWN));
    1.71      }
    1.72 @@ -300,8 +337,7 @@
    1.73              
    1.74              fromRate  = fromIntermediary.getConversionRate(from, intermediary);
    1.75              toRate    = toIntermediary.getConversionRate(intermediary, to);
    1.76 -            rate      = fromRate.multiply(toRate);
    1.77 -            
    1.78 +            rate      = fromRate.multiply(toRate);            
    1.79              convertor = ConvertorFactory.getConvertor(from, BigDecimal.ONE, to, rate);
    1.80              
    1.81              return (convertor);
     2.1 --- a/task3/solution04/src/org/apidesign/apifest08/currency/ConverterImpl.java	Fri Oct 10 22:02:31 2008 +0200
     2.2 +++ b/task3/solution04/src/org/apidesign/apifest08/currency/ConverterImpl.java	Fri Oct 10 22:05:15 2008 +0200
     2.3 @@ -20,12 +20,12 @@
     2.4      implements Convertor
     2.5  {
     2.6      /**
     2.7 -     * The currency to cvonvert from.
     2.8 +     * The currency to convert from.
     2.9       */
    2.10      private final Currency currencyA;
    2.11  
    2.12      /**
    2.13 -     * The currency to cvonvert from.
    2.14 +     * The currency to convert to.
    2.15       */
    2.16      private final Currency currencyB;
    2.17  
    2.18 @@ -142,9 +142,20 @@
    2.19       * @param from the currency to convert from.
    2.20       * @param to the currency to convert to.
    2.21       * @return true if the conversion is possible.
    2.22 +     * @throws IllegalArgumentException if either from or to are null.
    2.23       */
    2.24      public boolean canConvert(final Currency from, final Currency to)
    2.25      {
    2.26 +        if(from == null)
    2.27 +        {
    2.28 +            throw new IllegalArgumentException("from cannot be null");
    2.29 +        }
    2.30 +        
    2.31 +        if(to == null)
    2.32 +        {
    2.33 +            throw new IllegalArgumentException("to cannot be null");
    2.34 +        }
    2.35 +        
    2.36          return ((from.equals(currencyA) || from.equals(currencyB)) &&
    2.37                  (to.equals(currencyA)   || to.equals(currencyB)));
    2.38      }
    2.39 @@ -172,12 +183,23 @@
    2.40       * @param to the currency to convert to.
    2.41       * @return the conversion rate between the two currencies.
    2.42       * @throws InvalidConversionException if canConvert would return false.
    2.43 +     * @throws IllegalArgumentException if either from or to are null.
    2.44       */
    2.45      public BigDecimal getConversionRate(final Currency from, 
    2.46                                          final Currency to)
    2.47          throws InvalidConversionException
    2.48 -    {
    2.49 +    {                
    2.50          final BigDecimal rate;
    2.51 +        
    2.52 +        if(from == null)
    2.53 +        {
    2.54 +            throw new IllegalArgumentException("from cannot be null");
    2.55 +        }
    2.56 +        
    2.57 +        if(to == null)
    2.58 +        {
    2.59 +            throw new IllegalArgumentException("to cannot be null");
    2.60 +        }
    2.61  
    2.62          if(from.equals(to))
    2.63          {
     3.1 --- a/task3/solution04/src/org/apidesign/apifest08/currency/ConvertorFactory.java	Fri Oct 10 22:02:31 2008 +0200
     3.2 +++ b/task3/solution04/src/org/apidesign/apifest08/currency/ConvertorFactory.java	Fri Oct 10 22:05:15 2008 +0200
     3.3 @@ -115,6 +115,11 @@
     3.4          return (convertor);
     3.5      }
     3.6      
     3.7 +    /**
     3.8 +     * 
     3.9 +     * @param cs
    3.10 +     * @return
    3.11 +     */
    3.12      public static Convertor mergeConvertors(final Convertor ... cs)
    3.13      {
    3.14          Convertor convertor;
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/task3/solution04/src/org/apidesign/apifest08/currency/ExchangeRate.java	Fri Oct 10 22:05:15 2008 +0200
     4.3 @@ -0,0 +1,125 @@
     4.4 +package org.apidesign.apifest08.currency;
     4.5 +
     4.6 +
     4.7 +import java.math.BigDecimal;
     4.8 +import java.util.Currency;
     4.9 +
    4.10 +
    4.11 +/**
    4.12 + * The exchange rate between two currencies.
    4.13 + *
    4.14 + * @author D'Arcy Smith
    4.15 + * @version 1.0
    4.16 + */
    4.17 +public final class ExchangeRate
    4.18 +{
    4.19 +    /**
    4.20 +     * 
    4.21 +     */
    4.22 +    private final Currency currencyA;
    4.23 +
    4.24 +    /**
    4.25 +     * 
    4.26 +     */
    4.27 +    private final Currency currencyB;
    4.28 +
    4.29 +    /**
    4.30 +     * 
    4.31 +     */
    4.32 +    private final BigDecimal rateAtoB;
    4.33 +
    4.34 +    /**
    4.35 +     * 
    4.36 +     */
    4.37 +    private final BigDecimal rateBtoA;
    4.38 +
    4.39 +    /**
    4.40 +     * Construct an ExchangeRate with the specified values.
    4.41 +     * 
    4.42 +     * @param a the first currency
    4.43 +     * @param b the second currency
    4.44 +     * @param ra the rate to convert a to b
    4.45 +     * @param rb the rate to covertt b to a
    4.46 +     * @throws IllegalArgumentException if any parameter is null.
    4.47 +     */
    4.48 +    public ExchangeRate(final Currency   a,
    4.49 +                        final Currency   b,
    4.50 +                        final BigDecimal ra,
    4.51 +                        final BigDecimal rb)
    4.52 +    {
    4.53 +        if(a == null)
    4.54 +        {
    4.55 +            throw new IllegalArgumentException("a cannot be null");
    4.56 +        }
    4.57 +        
    4.58 +        if(b == null)
    4.59 +        {
    4.60 +            throw new IllegalArgumentException("b cannot be null");
    4.61 +        }
    4.62 +        
    4.63 +        if(ra == null)
    4.64 +        {
    4.65 +            throw new IllegalArgumentException("ra cannot be null");
    4.66 +        }
    4.67 +        
    4.68 +        if(rb == null)
    4.69 +        {
    4.70 +            throw new IllegalArgumentException("rb cannot be null");
    4.71 +        }
    4.72 +        
    4.73 +        if(ra.compareTo(BigDecimal.ZERO) <= 0)
    4.74 +        {
    4.75 +            throw new IllegalArgumentException("ra cannot be <= 0, was: " + ra);
    4.76 +        }
    4.77 +        
    4.78 +        if(rb.compareTo(BigDecimal.ZERO) <= 0)
    4.79 +        {
    4.80 +            throw new IllegalArgumentException("rb cannot be <= 0, was: " + ra);
    4.81 +        }
    4.82 +        
    4.83 +        currencyA = a;
    4.84 +        currencyB = b;
    4.85 +        rateAtoB  = ra;
    4.86 +        rateBtoA  = rb;
    4.87 +    }
    4.88 +
    4.89 +    /**
    4.90 +     * Get the first currency.
    4.91 +     * 
    4.92 +     * @return the first currency.
    4.93 +     */
    4.94 +    public Currency getCurrencyA()
    4.95 +    {
    4.96 +        return currencyA;
    4.97 +    }
    4.98 +
    4.99 +    /**
   4.100 +     * Get the second currency.
   4.101 +     * 
   4.102 +     * @return the second currency.
   4.103 +     */
   4.104 +    public Currency getCurrencyB()
   4.105 +    {
   4.106 +        return currencyB;
   4.107 +    }
   4.108 +
   4.109 +    /**
   4.110 +     * Get the conversion rate from currencyA to currencyB.
   4.111 +     * 
   4.112 +     * @return the conversion rate from currencyA to currencyB.
   4.113 +     */
   4.114 +    public BigDecimal getRateAtoB()
   4.115 +    {
   4.116 +        return rateAtoB;
   4.117 +    }
   4.118 +
   4.119 +    /**
   4.120 +     * Get the conversion rate from currencyB to currencyA.
   4.121 +     * 
   4.122 +     * @return the conversion rate from currencyB to currencyA.
   4.123 +     */
   4.124 +    public BigDecimal getRateBtoA()
   4.125 +    {
   4.126 +        return rateBtoA;
   4.127 +    }
   4.128 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/task3/solution04/src/org/apidesign/apifest08/currency/ExchangeRateFinder.java	Fri Oct 10 22:05:15 2008 +0200
     5.3 @@ -0,0 +1,22 @@
     5.4 +package org.apidesign.apifest08.currency;
     5.5 +
     5.6 +import java.util.Currency;
     5.7 +
     5.8 +
     5.9 +/**
    5.10 + * Used to look up the exchange rate between two currencies.
    5.11 + *
    5.12 + * @author D'Arcy Smith
    5.13 + * @version 1.0
    5.14 + */
    5.15 +public interface ExchangeRateFinder
    5.16 +{
    5.17 +    /**
    5.18 +     * Find the exchange rate between two currencies.
    5.19 +     *
    5.20 +     * @param a the currency to convert from.
    5.21 +     * @param b the currency to convert to.
    5.22 +     * @return the exchange rate for conversions between the two currencies.
    5.23 +     */
    5.24 +    ExchangeRate findRate(Currency a, Currency b);
    5.25 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/task3/solution04/src/org/apidesign/apifest08/currency/OnlineConvertor.java	Fri Oct 10 22:05:15 2008 +0200
     6.3 @@ -0,0 +1,175 @@
     6.4 +package org.apidesign.apifest08.currency;
     6.5 +
     6.6 +
     6.7 +import java.math.BigDecimal;
     6.8 +import java.util.Currency;
     6.9 +import java.util.Set;
    6.10 +
    6.11 +
    6.12 +/**
    6.13 + * A Convertor that looks up the exchange rate with each call to "convert".
    6.14 + *
    6.15 + * @author D'Arcy Smith
    6.16 + * @version 1.0
    6.17 + */
    6.18 +public class OnlineConvertor
    6.19 +    implements Convertor
    6.20 +{
    6.21 +    /**
    6.22 +     * The currency to convert from.
    6.23 +     */
    6.24 +    private final Currency currencyA;
    6.25 +
    6.26 +    /**
    6.27 +     * The currency to convert to.
    6.28 +     */
    6.29 +    private final Currency currencyB;
    6.30 +
    6.31 +    /**
    6.32 +     * Used to find the current exchange rate.
    6.33 +     */
    6.34 +    private final ExchangeRateFinder finder;
    6.35 +    
    6.36 +    /**
    6.37 +     * The convertor to perform the conversion.
    6.38 +     */
    6.39 +    private Convertor realConvertor;
    6.40 +
    6.41 +    /**
    6.42 +     * Constructs an OnlinConvertor with the specified currencies.
    6.43 +     * 
    6.44 +     * @param a the currency to convert from.
    6.45 +     * @param b the currency to convert to.
    6.46 +     * @param f the finder used to obtanin the current exchange rate.
    6.47 +     * @throws IllegalArgumentException if either a or b are null.
    6.48 +     */
    6.49 +    public OnlineConvertor(final Currency           a,
    6.50 +                           final Currency           b,
    6.51 +                           final ExchangeRateFinder f)
    6.52 +    {
    6.53 +        if(a == null)        
    6.54 +        {
    6.55 +            throw new IllegalArgumentException("a cannot be null");
    6.56 +        }
    6.57 +        
    6.58 +        if(b == null)
    6.59 +        {
    6.60 +            throw new IllegalArgumentException("b cannot be null");
    6.61 +        }
    6.62 +        
    6.63 +        if(f == null)
    6.64 +        {
    6.65 +            throw new IllegalArgumentException("f cannot be null");
    6.66 +        }
    6.67 +        
    6.68 +        currencyA     = a;
    6.69 +        currencyB     = b;
    6.70 +        finder        = f;
    6.71 +        realConvertor = lookupRate();
    6.72 +    }
    6.73 +
    6.74 +    /**
    6.75 +     * Convert an amount from one currency to another.  Before the conversion takes place 
    6.76 +     * the current exchange rate is looked up.
    6.77 +     *
    6.78 +     * @param from the currency to convert from.
    6.79 +     * @param to the currency to convert to.
    6.80 +     * @param amount the amount to convert.
    6.81 +     * @return the converted amount.
    6.82 +     * @throws IllegalArgumentException if any of the arguments are null.
    6.83 +     * @throws InvalidConversionException if either from or to are not equal to the currencies passed to the constructor.
    6.84 +     */
    6.85 +    public BigDecimal convert(final Currency   from, 
    6.86 +                              final Currency   to, 
    6.87 +                              final BigDecimal amount) 
    6.88 +        throws InvalidConversionException
    6.89 +    {
    6.90 +        final BigDecimal value;
    6.91 +        
    6.92 +        synchronized(this)
    6.93 +        {
    6.94 +            realConvertor = lookupRate();
    6.95 +            value         = realConvertor.convert(from, to, amount);
    6.96 +        }
    6.97 +        
    6.98 +        return (value);
    6.99 +    }
   6.100 +
   6.101 +    /**
   6.102 +     * Lookup the current exchange rate.
   6.103 +     * 
   6.104 +     * @return
   6.105 +     */
   6.106 +    private final Convertor lookupRate()
   6.107 +    {
   6.108 +        final Convertor convertor;
   6.109 +        final ExchangeRate rate;
   6.110 +
   6.111 +        rate      = finder.findRate(currencyA, currencyB);
   6.112 +        convertor = ConvertorFactory.getConvertor(rate.getCurrencyA(), rate.getRateAtoB(), rate.getCurrencyB(), rate.getRateBtoA());
   6.113 +
   6.114 +        return (convertor);
   6.115 +    }
   6.116 +
   6.117 +    /**
   6.118 +     * Check to see if converting between the two currencies is possible.
   6.119 +     * 
   6.120 +     * @param from the currency to convert from.
   6.121 +     * @param to the currency to convert to.
   6.122 +     * @return true if the conversion is possible.
   6.123 +     * @throws IllegalArgumentException if either from or to are null.
   6.124 +     */
   6.125 +    public boolean canConvert(final Currency from, 
   6.126 +                              final Currency to) 
   6.127 +    {
   6.128 +        if(from == null)
   6.129 +        {
   6.130 +            throw new IllegalArgumentException("from cannot be null");
   6.131 +        }
   6.132 +        
   6.133 +        if(to == null)
   6.134 +        {
   6.135 +            throw new IllegalArgumentException("to cannot be null");
   6.136 +        }
   6.137 +        
   6.138 +        return (realConvertor.canConvert(from, to));
   6.139 +    }
   6.140 +
   6.141 +    /**
   6.142 +     * Get the currencies that the convertor supports.
   6.143 +     * 
   6.144 +     * @return the supported currencies.
   6.145 +     */
   6.146 +    public Set<Currency> getCurrencies() 
   6.147 +    {
   6.148 +        return (realConvertor.getCurrencies());
   6.149 +    }
   6.150 +
   6.151 +    /**
   6.152 +     * Get the conversion rate between two currencies.  This does not lookup the current
   6.153 +     * conversion rate (it probably should, but given the way the contest works that might 
   6.154 +     * not be a good idea - if it were the real world way it might be a good idea).
   6.155 +     * 
   6.156 +     * @param from the currency to convert from.
   6.157 +     * @param to the currency to convert to.
   6.158 +     * @return the conversion rate between the two currencies.
   6.159 +     * @throws InvalidConversionException if canConvert would return false.
   6.160 +     * @throws IllegalArgumentException if either from or to are null.
   6.161 +     */
   6.162 +    public BigDecimal getConversionRate(final Currency from, 
   6.163 +                                        final Currency to) 
   6.164 +        throws InvalidConversionException 
   6.165 +    {        
   6.166 +        if(from == null)
   6.167 +        {
   6.168 +            throw new IllegalArgumentException("from cannot be null");
   6.169 +        }
   6.170 +        
   6.171 +        if(to == null)
   6.172 +        {
   6.173 +            throw new IllegalArgumentException("to cannot be null");
   6.174 +        }
   6.175 +        
   6.176 +        return (realConvertor.getConversionRate(from, to));
   6.177 +    }    
   6.178 +}
     7.1 --- a/task3/solution04/test/org/apidesign/apifest08/test/Task3Test.java	Fri Oct 10 22:02:31 2008 +0200
     7.2 +++ b/task3/solution04/test/org/apidesign/apifest08/test/Task3Test.java	Fri Oct 10 22:05:15 2008 +0200
     7.3 @@ -1,7 +1,11 @@
     7.4  package org.apidesign.apifest08.test;
     7.5  
     7.6 +import java.math.BigDecimal;
     7.7 +import java.util.Currency;
     7.8  import junit.framework.TestCase;
     7.9  import org.apidesign.apifest08.currency.Convertor;
    7.10 +import org.apidesign.apifest08.currency.InvalidConversionException;
    7.11 +import org.apidesign.apifest08.currency.OnlineConvertor;
    7.12  
    7.13  /** The exchange rates are not always the same. They are changing. Day by day,
    7.14   * hour by hour, minute by minute. For every bank it is important to always
    7.15 @@ -15,17 +19,33 @@
    7.16   * he does not know how the whole system looks and how the convertor is supposed
    7.17   * to be used.
    7.18   */
    7.19 -public class Task3Test extends TestCase {
    7.20 -    public Task3Test(String testName) {
    7.21 +public class Task3Test 
    7.22 +    extends TestCase
    7.23 +{
    7.24 +    private final static Currency CZK;
    7.25 +    private final static Currency SKK;
    7.26 +    private final static Currency USD;
    7.27 +
    7.28 +    static
    7.29 +    {
    7.30 +        CZK = Currency.getInstance("CZK");
    7.31 +        SKK = Currency.getInstance("SKK");
    7.32 +        USD = Currency.getInstance("USD");
    7.33 +    }
    7.34 +    
    7.35 +    public Task3Test(String testName)
    7.36 +    {
    7.37          super(testName);
    7.38      }
    7.39  
    7.40      @Override
    7.41 -    protected void setUp() throws Exception {
    7.42 +    protected void setUp() throws Exception
    7.43 +    {
    7.44      }
    7.45  
    7.46      @Override
    7.47 -    protected void tearDown() throws Exception {
    7.48 +    protected void tearDown() throws Exception
    7.49 +    {
    7.50      }
    7.51  
    7.52      // Backward compatibly enhance your existing API to support following
    7.53 @@ -41,8 +61,21 @@
    7.54       * until you reach 1USD = 16CZK
    7.55       *
    7.56       * @return new instance of "online" USD and CZK convertor starting with rate 1USD = 16CZK
    7.57 +     * @throws InvalidConversionException 
    7.58       */
    7.59 -    public static Convertor createOnlineCZKUSDConvertor() {
    7.60 +    public static Convertor createOnlineCZKUSDConvertor() 
    7.61 +        throws InvalidConversionException
    7.62 +    {
    7.63 +        final Convertor convertor;
    7.64 +        
    7.65 +        convertor = new OnlineConvertor(USD,
    7.66 +                                        CZK,
    7.67 +                                        new TestExchangeRateFinder(new BigDecimal("15.00"), 
    7.68 +                                                                   new BigDecimal("16.00"),
    7.69 +                                                                   new BigDecimal("16.00"),
    7.70 +                                                                   new BigDecimal("0.01"),
    7.71 +                                                                   new BigDecimal("-0.01")));
    7.72 +
    7.73          // initial rate: 1USD = 16CZK
    7.74          // 2nd query 1USD = 15.99CZK
    7.75          // 3rd query 1USD = 15.98CZK
    7.76 @@ -51,10 +84,12 @@
    7.77          // then 1USD = 15.02CZK
    7.78          // and so on and on up to 1USD = 16CZK
    7.79          // and then another round to 15, etc.
    7.80 -        return null;
    7.81 +        return convertor;
    7.82      }
    7.83  
    7.84 -    public void testFewQueriesForOnlineConvertor() {
    7.85 +    public void testFewQueriesForOnlineConvertor() 
    7.86 +        throws InvalidConversionException
    7.87 +    {
    7.88          if (Boolean.getBoolean("ignore.failing")) {
    7.89              // implement me!
    7.90              return;
    7.91 @@ -64,25 +99,37 @@
    7.92          doFewQueriesForOnlineConvertor(c);
    7.93      }
    7.94  
    7.95 -    static void doFewQueriesForOnlineConvertor(Convertor c) {
    7.96 +    static void doFewQueriesForOnlineConvertor(Convertor c) 
    7.97 +        throws InvalidConversionException            
    7.98 +    {
    7.99 +        BigDecimal amount;
   7.100 +
   7.101          // convert $5 to CZK using c:
   7.102          //assertEquals("Result is 80 CZK");
   7.103 +        amount = c.convert(USD, CZK, new BigDecimal("5.00"));
   7.104 +        assertEquals(new BigDecimal("80.00"), amount);
   7.105  
   7.106          // convert $8 to CZK using c:
   7.107          //assertEquals("Result is 127.92 CZK");
   7.108 +        amount = c.convert(USD, CZK, new BigDecimal("8.00"));
   7.109 +        assertEquals(new BigDecimal("127.92"), amount);
   7.110  
   7.111          // convert $1 to CZK using c:
   7.112          //assertEquals("Result is 15.98 CZK");
   7.113 +        amount = c.convert(USD, CZK, new BigDecimal("1.00"));
   7.114 +        assertEquals(new BigDecimal("15.98"), amount);
   7.115  
   7.116          // convert 15.97CZK to USD using c:
   7.117          //assertEquals("Result is 1$");
   7.118 -
   7.119 -        fail("Implement me!");
   7.120 +        amount = c.convert(CZK, USD, new BigDecimal("15.97"));
   7.121 +        assertEquals(new BigDecimal("1.00"), amount);
   7.122      }
   7.123  
   7.124      /** Join the convertors and show they behave sane.
   7.125       */
   7.126      public void testOnlineConvertorComposition() throws Exception {
   7.127 +        BigDecimal amount;
   7.128 +        
   7.129          if (Boolean.getBoolean("ignore.failing")) {
   7.130              // implement me!
   7.131              return;
   7.132 @@ -95,9 +142,13 @@
   7.133  
   7.134          // convert 16CZK to SKK using c:
   7.135          // assertEquals("Result is 20 SKK");
   7.136 -
   7.137 +        amount = c.convert(CZK, SKK, new BigDecimal("16.00"));
   7.138 +        assertEquals(new BigDecimal("20.00"), amount);
   7.139 +        
   7.140          // convert 500SKK to CZK using c:
   7.141          // assertEquals("Result is 400 CZK");
   7.142 +        amount = c.convert(SKK, CZK, new BigDecimal("500.00"));
   7.143 +        assertEquals(new BigDecimal("400.00"), amount);
   7.144  
   7.145          doFewQueriesForOnlineConvertor(c);
   7.146      }
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/task3/solution04/test/org/apidesign/apifest08/test/TestExchangeRateFinder.java	Fri Oct 10 22:05:15 2008 +0200
     8.3 @@ -0,0 +1,61 @@
     8.4 +package org.apidesign.apifest08.test;
     8.5 +
     8.6 +
     8.7 +import java.math.BigDecimal;
     8.8 +import java.util.Currency;
     8.9 +import org.apidesign.apifest08.currency.ExchangeRate;
    8.10 +import org.apidesign.apifest08.currency.ExchangeRateFinder;
    8.11 +
    8.12 +
    8.13 +class TestExchangeRateFinder
    8.14 +    implements ExchangeRateFinder
    8.15 +{
    8.16 +    private final BigDecimal min;
    8.17 +    private final BigDecimal max;
    8.18 +    private final BigDecimal stepUp;
    8.19 +    private final BigDecimal stepDown;
    8.20 +    private BigDecimal step;
    8.21 +    private BigDecimal rate;
    8.22 +    private boolean firstCall;
    8.23 +
    8.24 +    TestExchangeRateFinder(final BigDecimal mn,
    8.25 +                           final BigDecimal mx,
    8.26 +                           final BigDecimal start,
    8.27 +                           final BigDecimal up,
    8.28 +                           final BigDecimal down)
    8.29 +    {
    8.30 +        min       = mn;
    8.31 +        max       = mx;
    8.32 +        rate      = start;
    8.33 +        stepUp    = up;
    8.34 +        stepDown  = down;
    8.35 +        firstCall = true;
    8.36 +    }
    8.37 +    
    8.38 +    public ExchangeRate findRate(Currency a, Currency b) 
    8.39 +    {
    8.40 +        final ExchangeRate value;
    8.41 +
    8.42 +        if(rate.equals(max))
    8.43 +        {
    8.44 +            step = stepDown;
    8.45 +        }
    8.46 +        else if(rate.equals(min))
    8.47 +        {
    8.48 +            step = stepUp;
    8.49 +        }
    8.50 +
    8.51 +        value = new ExchangeRate(a, b, BigDecimal.ONE, rate);
    8.52 +
    8.53 +        if(firstCall)
    8.54 +        {
    8.55 +            firstCall = false;
    8.56 +        }
    8.57 +        else
    8.58 +        {
    8.59 +            rate = rate.add(step);
    8.60 +        }
    8.61 +
    8.62 +        return (value);
    8.63 +    }
    8.64 +}