solution 11, task4
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Fri, 17 Oct 2008 17:34:40 +0200
changeset 66aa3f99f845ef
parent 65 8482e36a7ad2
child 67 bf7622ec1713
solution 11, task4
task4/solution11/src/org/apidesign/apifest08/currency/Convertor.java
task4/solution11/src/org/apidesign/apifest08/currency/DateUtil.java
task4/solution11/src/org/apidesign/apifest08/currency/ExchangeRateDataSource.java
task4/solution11/src/org/apidesign/apifest08/currency/ExchangeRateProvider.java
task4/solution11/src/org/apidesign/apifest08/currency/StaticExchangeRateProvider.java
task4/solution11/test/org/apidesign/apifest08/test/Task4Test.java
     1.1 --- a/task4/solution11/src/org/apidesign/apifest08/currency/Convertor.java	Fri Oct 17 17:33:32 2008 +0200
     1.2 +++ b/task4/solution11/src/org/apidesign/apifest08/currency/Convertor.java	Fri Oct 17 17:34:40 2008 +0200
     1.3 @@ -2,6 +2,7 @@
     1.4  
     1.5  import java.util.ArrayList;
     1.6  import java.util.Collection;
     1.7 +import java.util.Date;
     1.8  import java.util.HashSet;
     1.9  import java.util.List;
    1.10  import java.util.Set;
    1.11 @@ -25,71 +26,99 @@
    1.12   * as well as static exchange rates.
    1.13   * No time for javadoc, again.
    1.14   * 
    1.15 + * In Task4's version takes into account validity range of data sources,
    1.16 + * can convert using an exchange rate value according to the specified instant
    1.17 + * of the time and provides a method for creating a new convertor with the same
    1.18 + * data sources as the old one, but with their validity ranges limited
    1.19 + * to the specified range.
    1.20 + * As usual, no time for javadoc.
    1.21 + * 
    1.22   * @author ked
    1.23   */
    1.24  public final class Convertor<AmountType, IdentifierType> {
    1.25  
    1.26      Computer<AmountType> computer;
    1.27 -    // each static exchange rate could be a special case of an exchange rate data source
    1.28 -    List<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates = new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
    1.29 -    List<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources = new ArrayList<ExchangeRateDataSource<AmountType, IdentifierType>>();
    1.30 +    // each static exchange rate is a special case of an exchange rate data source
    1.31 +    // historically separated
    1.32 +    List<ExchangeRateDataSource<AmountType, IdentifierType>> staticExchangeRateDataSources =
    1.33 +            new ArrayList<ExchangeRateDataSource<AmountType, IdentifierType>>();
    1.34 +    List<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources =
    1.35 +            new ArrayList<ExchangeRateDataSource<AmountType, IdentifierType>>();
    1.36  
    1.37 +    // ---
    1.38 +    // BASICS
    1.39 +    // ---
    1.40      Convertor(Computer<AmountType> computer) {
    1.41          this.computer = computer;
    1.42      }
    1.43 -    
    1.44 -    void addExchangeRates(Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
    1.45 -        for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
    1.46 -            if (isExchangeRate(
    1.47 -                    exchangeRate.getCurrencyA().getIdentifier(),
    1.48 -                    exchangeRate.getCurrencyB().getIdentifier())) {
    1.49 +
    1.50 +    void addExchangeRateDataSources(
    1.51 +            List<ExchangeRateDataSource<AmountType, IdentifierType>> target,
    1.52 +            Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources) {
    1.53 +        for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : exchangeRateDataSources) {
    1.54 +            if (isOverlappingExchangeRate(
    1.55 +                    exchangeRateDataSource.getCurrencyAIdentifier(),
    1.56 +                    exchangeRateDataSource.getCurrencyBIdentifier(),
    1.57 +                    exchangeRateDataSource.getValidFrom(),
    1.58 +                    exchangeRateDataSource.getValidTill())) {
    1.59                  throw new IllegalArgumentException("Duplicate exchange rate!");
    1.60              }
    1.61 -            this.exchangeRates.add(exchangeRate);
    1.62 +            target.add(exchangeRateDataSource);
    1.63          }
    1.64      }
    1.65 -    
    1.66 -    void addExchangeRateDataSources(Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources) {
    1.67 -        for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : exchangeRateDataSources) {
    1.68 -            if (isExchangeRate(
    1.69 -                    exchangeRateDataSource.getCurrencyAIdentifier(),
    1.70 -                    exchangeRateDataSource.getCurrencyBIdentifier())) {
    1.71 -                throw new IllegalArgumentException("Duplicate exchange rate!");
    1.72 -            }
    1.73 -            this.exchangeRateDataSources.add(exchangeRateDataSource);
    1.74 -        }
    1.75 -    }
    1.76 -    
    1.77 +
    1.78      ExchangeRateValue<AmountType, IdentifierType> findExchangeRate(
    1.79              IdentifierType currencyA,
    1.80 -            IdentifierType currencyB) {
    1.81 -        for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
    1.82 -            if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) ||
    1.83 -                    (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) {
    1.84 -                return exchangeRate;
    1.85 -            }
    1.86 +            IdentifierType currencyB,
    1.87 +            Date instant) {
    1.88 +        ExchangeRateValue<AmountType, IdentifierType> result = null;
    1.89 +        result = findExchangeRateInternal(staticExchangeRateDataSources, currencyA, currencyB, instant);
    1.90 +        if (result != null) {
    1.91 +            return result;
    1.92          }
    1.93 -        for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : exchangeRateDataSources) {
    1.94 -            if ((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) ||
    1.95 -                    (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) {
    1.96 +        result = findExchangeRateInternal(exchangeRateDataSources, currencyA, currencyB, instant);
    1.97 +        return result;
    1.98 +    }
    1.99 +
   1.100 +    ExchangeRateValue<AmountType, IdentifierType> findExchangeRateInternal(
   1.101 +            List<ExchangeRateDataSource<AmountType, IdentifierType>> where,
   1.102 +            IdentifierType currencyA,
   1.103 +            IdentifierType currencyB,
   1.104 +            Date instant) {
   1.105 +        for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : where) {
   1.106 +            if (((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) ||
   1.107 +                    (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) &&
   1.108 +                    DateUtil.isInRange(instant, exchangeRateDataSource.getValidFrom(), exchangeRateDataSource.getValidTill())) {
   1.109                  return exchangeRateDataSource.getExchangeRate();
   1.110              }
   1.111          }
   1.112          return null;
   1.113      }
   1.114 -    
   1.115 -    boolean isExchangeRate(
   1.116 +
   1.117 +    boolean isOverlappingExchangeRate(
   1.118              IdentifierType currencyA,
   1.119 -            IdentifierType currencyB) {
   1.120 -        for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
   1.121 -            if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) ||
   1.122 -                    (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) {
   1.123 -                return true;
   1.124 -            }
   1.125 +            IdentifierType currencyB,
   1.126 +            Date from,
   1.127 +            Date to) {
   1.128 +        boolean result = false;
   1.129 +        result = isOverlappingExchangeRateInternal(staticExchangeRateDataSources, currencyA, currencyB, from, to);
   1.130 +        if (result == true) {
   1.131 +            return result;
   1.132          }
   1.133 -        for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : exchangeRateDataSources) {
   1.134 -            if ((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) ||
   1.135 -                    (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) {
   1.136 +        result = isOverlappingExchangeRateInternal(exchangeRateDataSources, currencyA, currencyB, from, to);
   1.137 +        return result;
   1.138 +    }
   1.139 +
   1.140 +    boolean isOverlappingExchangeRateInternal(
   1.141 +            List<ExchangeRateDataSource<AmountType, IdentifierType>> where,
   1.142 +            IdentifierType currencyA,
   1.143 +            IdentifierType currencyB,
   1.144 +            Date from,
   1.145 +            Date to) {
   1.146 +        for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : where) {
   1.147 +            if (((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) ||
   1.148 +                    (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) &&
   1.149 +                    DateUtil.isRangesOverlapping(from, to, exchangeRateDataSource.getValidFrom(), exchangeRateDataSource.getValidTill())) {
   1.150                  return true;
   1.151              }
   1.152          }
   1.153 @@ -107,8 +136,15 @@
   1.154      public CurrencyValue<AmountType, IdentifierType> convert(
   1.155              IdentifierType targetCurrency,
   1.156              CurrencyValue<AmountType, IdentifierType> currencyValue) {
   1.157 +        return convert(targetCurrency, currencyValue, new Date()); // System.currentTimeMillis()
   1.158 +    }
   1.159 +
   1.160 +    public CurrencyValue<AmountType, IdentifierType> convert(
   1.161 +            IdentifierType targetCurrency,
   1.162 +            CurrencyValue<AmountType, IdentifierType> currencyValue,
   1.163 +            Date instant) {
   1.164          ExchangeRateValue<AmountType, IdentifierType> exchangeRate =
   1.165 -                findExchangeRate(currencyValue.getIdentifier(), targetCurrency);
   1.166 +                findExchangeRate(currencyValue.getIdentifier(), targetCurrency, instant);
   1.167          if (exchangeRate == null) {
   1.168              throw new IllegalArgumentException("Inappropriate currencies to convert!");
   1.169          }
   1.170 @@ -136,23 +172,57 @@
   1.171      }
   1.172  
   1.173      // ---
   1.174 +    // LIMITING
   1.175 +    // ---
   1.176 +    Collection<ExchangeRateDataSource<AmountType, IdentifierType>> limitDataSources(
   1.177 +            Collection<ExchangeRateDataSource<AmountType, IdentifierType>> source,
   1.178 +            Date from, Date till) {
   1.179 +        Collection<ExchangeRateDataSource<AmountType, IdentifierType>> result =
   1.180 +                new ArrayList<ExchangeRateDataSource<AmountType, IdentifierType>>();
   1.181 +
   1.182 +        for (ExchangeRateDataSource<AmountType, IdentifierType> dataSource : source) {
   1.183 +            result.add(ExchangeRateDataSource.getExchangeRateDataSource(
   1.184 +                    dataSource.getCurrencyAIdentifier(), dataSource.getCurrencyBIdentifier(),
   1.185 +                    dataSource.getExchangeRateProvider(),
   1.186 +                    DateUtil.getRangesIntersectionBottom(dataSource.getValidFrom(), from),
   1.187 +                    DateUtil.getRangesIntersectionTop(dataSource.getValidTill(), till)));
   1.188 +        }
   1.189 +
   1.190 +        return result;
   1.191 +    }
   1.192 +
   1.193 +    public Convertor<AmountType, IdentifierType> limitConvertor(Date from, Date till) {
   1.194 +        Collection<ExchangeRateDataSource<AmountType, IdentifierType>> limitedStatic =
   1.195 +                limitDataSources(staticExchangeRateDataSources, from, till);
   1.196 +        Collection<ExchangeRateDataSource<AmountType, IdentifierType>> limited =
   1.197 +                limitDataSources(exchangeRateDataSources, from, till);
   1.198 +
   1.199 +        Convertor<AmountType, IdentifierType> c = new Convertor<AmountType, IdentifierType>(computer);
   1.200 +        c.addExchangeRateDataSources(c.staticExchangeRateDataSources, limitedStatic);
   1.201 +        c.addExchangeRateDataSources(c.exchangeRateDataSources, limited);
   1.202 +        return c;
   1.203 +    }
   1.204 +
   1.205 +    // ---
   1.206      // MERGING
   1.207      // ---
   1.208      static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
   1.209              Computer<AmountType> computer,
   1.210              Collection<Convertor<AmountType, IdentifierType>> convertors) {
   1.211 -        Set<ExchangeRateValue<AmountType, IdentifierType>> exchangeRatesSet = new HashSet<ExchangeRateValue<AmountType, IdentifierType>>();
   1.212 -        Set<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSourcesSet = new HashSet<ExchangeRateDataSource<AmountType, IdentifierType>>();
   1.213 +        Set<ExchangeRateDataSource<AmountType, IdentifierType>> mergedStatic =
   1.214 +                new HashSet<ExchangeRateDataSource<AmountType, IdentifierType>>();
   1.215 +        Set<ExchangeRateDataSource<AmountType, IdentifierType>> merged =
   1.216 +                new HashSet<ExchangeRateDataSource<AmountType, IdentifierType>>();
   1.217          for (Convertor<AmountType, IdentifierType> convertor : convertors) {
   1.218 -            exchangeRatesSet.addAll(convertor.exchangeRates);
   1.219 +            mergedStatic.addAll(convertor.staticExchangeRateDataSources);
   1.220          }
   1.221          for (Convertor<AmountType, IdentifierType> convertor : convertors) {
   1.222 -            exchangeRateDataSourcesSet.addAll(convertor.exchangeRateDataSources);
   1.223 +            merged.addAll(convertor.exchangeRateDataSources);
   1.224          }
   1.225 -        
   1.226 +
   1.227          Convertor<AmountType, IdentifierType> c = new Convertor<AmountType, IdentifierType>(computer);
   1.228 -        c.addExchangeRates(exchangeRatesSet);
   1.229 -        c.addExchangeRateDataSources(exchangeRateDataSourcesSet);
   1.230 +        c.addExchangeRateDataSources(c.staticExchangeRateDataSources, mergedStatic);
   1.231 +        c.addExchangeRateDataSources(c.exchangeRateDataSources, merged);
   1.232          return c;
   1.233      }
   1.234  
   1.235 @@ -195,17 +265,25 @@
   1.236      static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
   1.237              Computer<AmountType> computer, Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
   1.238          Convertor<AmountType, IdentifierType> c = new Convertor<AmountType, IdentifierType>(computer);
   1.239 -        c.addExchangeRates(exchangeRates);
   1.240 +        Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources =
   1.241 +                new ArrayList<ExchangeRateDataSource<AmountType, IdentifierType>>();
   1.242 +        for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
   1.243 +            exchangeRateDataSources.add(
   1.244 +                    ExchangeRateDataSource.getExchangeRateDataSource(
   1.245 +                    exchangeRate.getCurrencyA().getIdentifier(), exchangeRate.getCurrencyB().getIdentifier(),
   1.246 +                    StaticExchangeRateProvider.getStaticExchangeRateProvider(exchangeRate)));
   1.247 +        }
   1.248 +        c.addExchangeRateDataSources(c.staticExchangeRateDataSources, exchangeRateDataSources);
   1.249          return c;
   1.250      }
   1.251  
   1.252      static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertorDataSource(
   1.253              Computer<AmountType> computer, Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources) {
   1.254          Convertor<AmountType, IdentifierType> c = new Convertor<AmountType, IdentifierType>(computer);
   1.255 -        c.addExchangeRateDataSources(exchangeRateDataSources);
   1.256 +        c.addExchangeRateDataSources(c.exchangeRateDataSources, exchangeRateDataSources);
   1.257          return c;
   1.258      }
   1.259 -    
   1.260 +
   1.261      static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
   1.262              Computer<AmountType> computer, ExchangeRateValue<AmountType, IdentifierType> exchangeRate) {
   1.263          Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates =
   1.264 @@ -213,7 +291,7 @@
   1.265          exchangeRates.add(exchangeRate);
   1.266          return getConvertor(computer, exchangeRates);
   1.267      }
   1.268 -    
   1.269 +
   1.270      static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertorDataSource(
   1.271              Computer<AmountType> computer, ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource) {
   1.272          Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources =
   1.273 @@ -221,7 +299,7 @@
   1.274          exchangeRateDataSources.add(exchangeRateDataSource);
   1.275          return getConvertorDataSource(computer, exchangeRateDataSources);
   1.276      }
   1.277 -    
   1.278 +
   1.279      public static Convertor<Double, String> getConvertorDoubleString(
   1.280              Collection<ExchangeRateValue<Double, String>> exchangeRates) {
   1.281          return getConvertor(DoubleComputer, exchangeRates);
   1.282 @@ -231,7 +309,7 @@
   1.283              ExchangeRateValue<Double, String> exchangeRate) {
   1.284          return getConvertor(DoubleComputer, exchangeRate);
   1.285      }
   1.286 -    
   1.287 +
   1.288      public static Convertor<Double, String> getConvertorDataSourceDoubleString(
   1.289              Collection<ExchangeRateDataSource<Double, String>> exchangeRateDataSources) {
   1.290          return getConvertorDataSource(DoubleComputer, exchangeRateDataSources);
   1.291 @@ -241,7 +319,7 @@
   1.292              ExchangeRateDataSource<Double, String> exchangeRateDataSource) {
   1.293          return getConvertorDataSource(DoubleComputer, exchangeRateDataSource);
   1.294      }
   1.295 -    
   1.296 +
   1.297      public static Convertor<Integer, String> getConvertorIntegerString(
   1.298              Collection<ExchangeRateValue<Integer, String>> exchangeRates) {
   1.299          return getConvertor(IntegerComputer, exchangeRates);
   1.300 @@ -251,7 +329,7 @@
   1.301              ExchangeRateValue<Integer, String> exchangeRate) {
   1.302          return getConvertor(IntegerComputer, exchangeRate);
   1.303      }
   1.304 -    
   1.305 +
   1.306      public static Convertor<Integer, String> getConvertorDataSourceIntegerString(
   1.307              Collection<ExchangeRateDataSource<Integer, String>> exchangeRateDataSources) {
   1.308          return getConvertorDataSource(IntegerComputer, exchangeRateDataSources);
   1.309 @@ -292,7 +370,7 @@
   1.310              CurrencyValue<Integer, String> secondCurrencyExchangeRate) {
   1.311          return getConvertorIntegerString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
   1.312      }
   1.313 -    
   1.314 +
   1.315      // ---
   1.316      // COMPUTERS
   1.317      // ---
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/task4/solution11/src/org/apidesign/apifest08/currency/DateUtil.java	Fri Oct 17 17:34:40 2008 +0200
     2.3 @@ -0,0 +1,68 @@
     2.4 +package org.apidesign.apifest08.currency;
     2.5 +
     2.6 +import java.util.Date;
     2.7 +
     2.8 +/**
     2.9 + * Date util helper class.
    2.10 + * @author ked
    2.11 + */
    2.12 +final class DateUtil {
    2.13 +
    2.14 +    private DateUtil() {};
    2.15 +
    2.16 +    static boolean isInRange(Date instant, Date from, Date till) {
    2.17 +        if ((from == null || instant.equals(from) || instant.after(from)) &&
    2.18 +                (till == null || instant.before(till))) {
    2.19 +            return true;
    2.20 +        } else {
    2.21 +            return false;
    2.22 +        }
    2.23 +    }
    2.24 +
    2.25 +    static boolean isRangesOverlapping(Date fromA, Date tillA, Date fromB, Date tillB) {
    2.26 +        if ((fromA == null && tillA == null) || (fromB == null && tillB == null)) {
    2.27 +            return true;
    2.28 +        }
    2.29 +        if (fromA != null && isInRange(fromA, fromB, tillB)) {
    2.30 +            return true;
    2.31 +        }
    2.32 +        if (tillA != null && !tillA.equals(fromB) && isInRange(tillA, fromB, tillB)) {
    2.33 +            return true;
    2.34 +        }
    2.35 +        if (fromB != null && isInRange(fromB, fromA, tillA)) {
    2.36 +            return true;
    2.37 +        }
    2.38 +        if (tillB != null && !tillB.equals(fromA) && isInRange(tillB, fromA, tillA)) {
    2.39 +            return true;
    2.40 +        }
    2.41 +        return false;
    2.42 +    }
    2.43 +
    2.44 +    static Date getRangesIntersectionBottom(Date fromA, Date fromB) {
    2.45 +        if (fromA == null) {
    2.46 +            return fromB;
    2.47 +        }
    2.48 +        if (fromB == null) {
    2.49 +            return fromA;
    2.50 +        }
    2.51 +        if (fromA.after(fromB)) {
    2.52 +            return fromA;
    2.53 +        } else {
    2.54 +            return fromB;
    2.55 +        }
    2.56 +    }
    2.57 +
    2.58 +    static Date getRangesIntersectionTop(Date tillA, Date tillB) {
    2.59 +        if (tillA == null) {
    2.60 +            return tillB;
    2.61 +        }
    2.62 +        if (tillB == null) {
    2.63 +            return tillA;
    2.64 +        }
    2.65 +        if (tillA.before(tillB)) {
    2.66 +            return tillA;
    2.67 +        } else {
    2.68 +            return tillB;
    2.69 +        }
    2.70 +    }
    2.71 +}
     3.1 --- a/task4/solution11/src/org/apidesign/apifest08/currency/ExchangeRateDataSource.java	Fri Oct 17 17:33:32 2008 +0200
     3.2 +++ b/task4/solution11/src/org/apidesign/apifest08/currency/ExchangeRateDataSource.java	Fri Oct 17 17:34:40 2008 +0200
     3.3 @@ -1,5 +1,6 @@
     3.4  package org.apidesign.apifest08.currency;
     3.5  
     3.6 +import java.util.Date;
     3.7  import org.apidesign.apifest08.currency.ExchangeRateProvider.ExchangeRateRequest;
     3.8  import org.apidesign.apifest08.currency.ExchangeRateProvider.ExchangeRateResponse;
     3.9  
    3.10 @@ -10,94 +11,144 @@
    3.11   */
    3.12  public final class ExchangeRateDataSource<AmountType, IdentifierType> {
    3.13  
    3.14 -  private final IdentifierType currencyAIdentifier;
    3.15 +    private final IdentifierType currencyAIdentifier;
    3.16 +    private final IdentifierType currencyBIdentifier;
    3.17 +    private final ExchangeRateProvider<AmountType, IdentifierType> exchangeRateProvider;
    3.18 +    private final Date validFrom;
    3.19 +    private final Date validTill;
    3.20  
    3.21 -  private final IdentifierType currencyBIdentifier;
    3.22 +    private ExchangeRateDataSource(
    3.23 +            IdentifierType currencyAIdentifier,
    3.24 +            IdentifierType currencyBIdentifier,
    3.25 +            ExchangeRateProvider<AmountType, IdentifierType> exchangeRateProvider,
    3.26 +            Date validFrom,
    3.27 +            Date validTill) {
    3.28 +        if (currencyAIdentifier == null ||
    3.29 +                currencyBIdentifier == null ||
    3.30 +                currencyAIdentifier.equals(currencyBIdentifier)) {
    3.31 +            throw new IllegalArgumentException("Inappropriate exchange rates' identifiers!");
    3.32 +        }
    3.33 +        if (validFrom != null &&
    3.34 +                validTill != null &&
    3.35 +                !validTill.after(validFrom)) {
    3.36 +            throw new IllegalArgumentException("Inappropriate exchange rate validity!");
    3.37 +        }
    3.38  
    3.39 -  private final ExchangeRateProvider<AmountType, IdentifierType> exchangeRateProvider;
    3.40 +        this.currencyAIdentifier = currencyAIdentifier;
    3.41 +        this.currencyBIdentifier = currencyBIdentifier;
    3.42 +        this.exchangeRateProvider = exchangeRateProvider;
    3.43 +        this.validFrom = validFrom;
    3.44 +        this.validTill = validTill;
    3.45 +    }
    3.46  
    3.47 -  private ExchangeRateDataSource(
    3.48 -      IdentifierType currencyAIdentifier,
    3.49 -      IdentifierType currencyBIdentifier,
    3.50 -      ExchangeRateProvider<AmountType, IdentifierType> exchangeRateProvider) {
    3.51 -        if (currencyAIdentifier == null ||
    3.52 -            currencyBIdentifier == null ||
    3.53 -            currencyAIdentifier.equals(currencyBIdentifier)) {
    3.54 -                throw new IllegalArgumentException("Inappropriate exchange rates' identifiers!");
    3.55 +    public IdentifierType getCurrencyAIdentifier() {
    3.56 +        return currencyAIdentifier;
    3.57 +    }
    3.58 +
    3.59 +    public IdentifierType getCurrencyBIdentifier() {
    3.60 +        return currencyBIdentifier;
    3.61 +    }
    3.62 +
    3.63 +    ExchangeRateProvider<AmountType, IdentifierType> getExchangeRateProvider() {
    3.64 +        return exchangeRateProvider;
    3.65 +    }
    3.66 +
    3.67 +    public Date getValidFrom() {
    3.68 +        return validFrom != null ? (Date) validFrom.clone() : null;
    3.69 +    }
    3.70 +
    3.71 +    public Date getValidTill() {
    3.72 +        return validTill != null ? (Date) validTill.clone() : null;
    3.73 +    }
    3.74 +
    3.75 +    public ExchangeRateValue<AmountType, IdentifierType> getExchangeRate() {
    3.76 +        return getExchangeRate(new Date()); // System.currentTimeMillis()
    3.77 +    }
    3.78 +
    3.79 +    public ExchangeRateValue<AmountType, IdentifierType> getExchangeRate(Date instant) {
    3.80 +        ExchangeRateRequest<AmountType, IdentifierType> request =
    3.81 +                new ExchangeRateRequest<AmountType, IdentifierType>();
    3.82 +        ExchangeRateResponse<AmountType, IdentifierType> response =
    3.83 +                new ExchangeRateResponse<AmountType, IdentifierType>();
    3.84 +
    3.85 +        request.setCurrencyAIdentifier(currencyAIdentifier);
    3.86 +        request.setCurrencyBIdentifier(currencyBIdentifier);
    3.87 +        request.setInstant(instant);
    3.88 +
    3.89 +        exchangeRateProvider.getExchangeRate(request, response);
    3.90 +
    3.91 +        ExchangeRateValue<AmountType, IdentifierType> result = response.getExchangeRate();
    3.92 +        if (result.getCurrencyA().getIdentifier().equals(currencyAIdentifier) &&
    3.93 +                result.getCurrencyB().getIdentifier().equals(currencyBIdentifier)) {
    3.94 +            return result;
    3.95 +        } else {
    3.96 +            throw new IllegalStateException("Data source's provider returned inappropriate exchange rate!");
    3.97          }
    3.98 -  this.currencyAIdentifier = currencyAIdentifier;
    3.99 -    this.currencyBIdentifier = currencyBIdentifier;
   3.100 -    this.exchangeRateProvider = exchangeRateProvider;
   3.101 -  }
   3.102 +    }
   3.103  
   3.104 -  public IdentifierType getCurrencyAIdentifier() {
   3.105 -    return currencyAIdentifier;
   3.106 -  }
   3.107 +    public static <AmountType, IdentifierType> ExchangeRateDataSource<AmountType, IdentifierType> getExchangeRateDataSource(
   3.108 +            IdentifierType currencyAIdentifier,
   3.109 +            IdentifierType currencyBIdentifier,
   3.110 +            ExchangeRateProvider<AmountType, IdentifierType> exchangeRateProvider) {
   3.111 +        return getExchangeRateDataSource(
   3.112 +                currencyAIdentifier,
   3.113 +                currencyBIdentifier,
   3.114 +                exchangeRateProvider,
   3.115 +                null,
   3.116 +                null);
   3.117 +    }
   3.118  
   3.119 -  public IdentifierType getCurrencyBIdentifier() {
   3.120 -    return currencyBIdentifier;
   3.121 -  }
   3.122 +    public static <AmountType, IdentifierType> ExchangeRateDataSource<AmountType, IdentifierType> getExchangeRateDataSource(
   3.123 +            IdentifierType currencyAIdentifier,
   3.124 +            IdentifierType currencyBIdentifier,
   3.125 +            ExchangeRateProvider<AmountType, IdentifierType> exchangeRateProvider,
   3.126 +            Date validFrom,
   3.127 +            Date validTill) {
   3.128 +        return new ExchangeRateDataSource<AmountType, IdentifierType>(
   3.129 +                currencyAIdentifier,
   3.130 +                currencyBIdentifier,
   3.131 +                exchangeRateProvider,
   3.132 +                validFrom,
   3.133 +                validTill);
   3.134 +    }
   3.135  
   3.136 -  public ExchangeRateValue<AmountType, IdentifierType> getExchangeRate() {
   3.137 -    ExchangeRateRequest<AmountType, IdentifierType> request =
   3.138 -        new ExchangeRateRequest<AmountType, IdentifierType>();
   3.139 -    ExchangeRateResponse<AmountType, IdentifierType> response =
   3.140 -        new ExchangeRateResponse<AmountType, IdentifierType>();
   3.141 +    @Override
   3.142 +    public boolean equals(Object obj) {
   3.143 +        if (obj == null) {
   3.144 +            return false;
   3.145 +        }
   3.146 +        if (getClass() != obj.getClass()) {
   3.147 +            return false;
   3.148 +        }
   3.149 +        final ExchangeRateDataSource other =
   3.150 +                (ExchangeRateDataSource) obj;
   3.151 +        if (this.currencyAIdentifier != other.currencyAIdentifier &&
   3.152 +                (this.currencyAIdentifier == null || !this.currencyAIdentifier.equals(other.currencyAIdentifier))) {
   3.153 +            return false;
   3.154 +        }
   3.155 +        if (this.currencyBIdentifier != other.currencyBIdentifier &&
   3.156 +                (this.currencyBIdentifier == null || !this.currencyBIdentifier.equals(other.currencyBIdentifier))) {
   3.157 +            return false;
   3.158 +        }
   3.159 +        if (this.exchangeRateProvider != other.exchangeRateProvider &&
   3.160 +                (this.exchangeRateProvider == null || !this.exchangeRateProvider.equals(other.exchangeRateProvider))) {
   3.161 +            return false;
   3.162 +        }
   3.163 +        if (this.validFrom != other.validFrom && (this.validFrom == null || !this.validFrom.equals(other.validFrom))) {
   3.164 +            return false;
   3.165 +        }
   3.166 +        if (this.validTill != other.validTill && (this.validTill == null || !this.validTill.equals(other.validTill))) {
   3.167 +            return false;
   3.168 +        }
   3.169 +        return true;
   3.170 +    }
   3.171  
   3.172 -    request.setCurrencyAIdentifier(currencyAIdentifier);
   3.173 -    request.setCurrencyBIdentifier(currencyBIdentifier);
   3.174 -
   3.175 -    exchangeRateProvider.getExchangeRate(request, response);
   3.176 -
   3.177 -    if (response.getExchangeRate().getCurrencyA().getIdentifier().equals(currencyAIdentifier) &&
   3.178 -        response.getExchangeRate().getCurrencyB().getIdentifier().equals(currencyBIdentifier)) {
   3.179 -      return response.getExchangeRate();
   3.180 -    } else {
   3.181 -      throw new IllegalStateException("Data source's provider returned inappropriate exchange rate!");
   3.182 +    @Override
   3.183 +    public int hashCode() {
   3.184 +        int hash = 7;
   3.185 +        hash = 83 * hash + (this.currencyAIdentifier != null ? this.currencyAIdentifier.hashCode() : 0);
   3.186 +        hash = 83 * hash + (this.currencyBIdentifier != null ? this.currencyBIdentifier.hashCode() : 0);
   3.187 +        hash = 83 * hash + (this.exchangeRateProvider != null ? this.exchangeRateProvider.hashCode() : 0);
   3.188 +        return hash;
   3.189      }
   3.190 -  }
   3.191 -
   3.192 -  public static <AmountType, IdentifierType> ExchangeRateDataSource<AmountType, IdentifierType> getExchangeRateDataSource(
   3.193 -      IdentifierType currencyAIdentifier,
   3.194 -      IdentifierType currencyBIdentifier,
   3.195 -      ExchangeRateProvider<AmountType, IdentifierType> exchangeRateProvider) {
   3.196 -    return new ExchangeRateDataSource<AmountType, IdentifierType>(
   3.197 -        currencyAIdentifier,
   3.198 -        currencyBIdentifier,
   3.199 -        exchangeRateProvider);
   3.200 -  }
   3.201 -
   3.202 -  @Override
   3.203 -  public boolean equals(Object obj) {
   3.204 -    if (obj == null) {
   3.205 -      return false;
   3.206 -    }
   3.207 -    if (getClass() != obj.getClass()) {
   3.208 -      return false;
   3.209 -    }
   3.210 -    final ExchangeRateDataSource other =
   3.211 -        (ExchangeRateDataSource) obj;
   3.212 -    if (this.currencyAIdentifier != other.currencyAIdentifier &&
   3.213 -        (this.currencyAIdentifier == null || !this.currencyAIdentifier.equals(other.currencyAIdentifier))) {
   3.214 -      return false;
   3.215 -    }
   3.216 -    if (this.currencyBIdentifier != other.currencyBIdentifier &&
   3.217 -        (this.currencyBIdentifier == null || !this.currencyBIdentifier.equals(other.currencyBIdentifier))) {
   3.218 -      return false;
   3.219 -    }
   3.220 -    if (this.exchangeRateProvider != other.exchangeRateProvider &&
   3.221 -        (this.exchangeRateProvider == null || !this.exchangeRateProvider.equals(other.exchangeRateProvider))) {
   3.222 -      return false;
   3.223 -    }
   3.224 -    return true;
   3.225 -  }
   3.226 -
   3.227 -  @Override
   3.228 -  public int hashCode() {
   3.229 -    int hash = 7;
   3.230 -    hash = 83 * hash + (this.currencyAIdentifier != null ? this.currencyAIdentifier.hashCode() : 0);
   3.231 -    hash = 83 * hash + (this.currencyBIdentifier != null ? this.currencyBIdentifier.hashCode() : 0);
   3.232 -    hash = 83 * hash + (this.exchangeRateProvider != null ? this.exchangeRateProvider.hashCode() : 0);
   3.233 -    return hash;
   3.234 -  }
   3.235  }
     4.1 --- a/task4/solution11/src/org/apidesign/apifest08/currency/ExchangeRateProvider.java	Fri Oct 17 17:33:32 2008 +0200
     4.2 +++ b/task4/solution11/src/org/apidesign/apifest08/currency/ExchangeRateProvider.java	Fri Oct 17 17:34:40 2008 +0200
     4.3 @@ -1,5 +1,7 @@
     4.4  package org.apidesign.apifest08.currency;
     4.5  
     4.6 +import java.util.Date;
     4.7 +
     4.8  /**
     4.9   * Exchange rate provider.
    4.10   * 
    4.11 @@ -16,6 +18,7 @@
    4.12  
    4.13          private IdentifierType currencyAIdentifier;
    4.14          private IdentifierType currencyBIdentifier;
    4.15 +        private Date instant;
    4.16  
    4.17          ExchangeRateRequest() {
    4.18          }
    4.19 @@ -35,6 +38,14 @@
    4.20          void setCurrencyBIdentifier(IdentifierType currencyBIdentifier) {
    4.21              this.currencyBIdentifier = currencyBIdentifier;
    4.22          }
    4.23 +
    4.24 +        public Date getInstant() {
    4.25 +            return instant;
    4.26 +        }
    4.27 +
    4.28 +        void setInstant(Date instant) {
    4.29 +            this.instant = instant;
    4.30 +        }
    4.31      }
    4.32  
    4.33      public final class ExchangeRateResponse<AmountType, IdentifierType> {
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/task4/solution11/src/org/apidesign/apifest08/currency/StaticExchangeRateProvider.java	Fri Oct 17 17:34:40 2008 +0200
     5.3 @@ -0,0 +1,48 @@
     5.4 +package org.apidesign.apifest08.currency;
     5.5 +
     5.6 +/**
     5.7 + * Static exchange rate provider.
     5.8 + * 
     5.9 + * @author ked
    5.10 + */
    5.11 +final class StaticExchangeRateProvider<AmountType, IdentifierType> implements ExchangeRateProvider<AmountType, IdentifierType> {
    5.12 +
    5.13 +    final ExchangeRateValue<AmountType, IdentifierType> exchangeRate;
    5.14 +
    5.15 +    private StaticExchangeRateProvider(ExchangeRateValue<AmountType, IdentifierType> exchangeRate) {
    5.16 +        this.exchangeRate = exchangeRate;
    5.17 +    }
    5.18 +
    5.19 +    public void getExchangeRate(ExchangeRateRequest<AmountType, IdentifierType> request, ExchangeRateResponse<AmountType, IdentifierType> response) {
    5.20 +        response.setExchangeRate(exchangeRate);
    5.21 +    }
    5.22 +
    5.23 +    static <AmountType, IdentifierType> StaticExchangeRateProvider<AmountType, IdentifierType> getStaticExchangeRateProvider(ExchangeRateValue<AmountType, IdentifierType> exchangeRate) {
    5.24 +        return new StaticExchangeRateProvider<AmountType, IdentifierType>(exchangeRate);
    5.25 +    }
    5.26 +
    5.27 +    @Override
    5.28 +    public boolean equals(Object obj) {
    5.29 +        if (obj == null) {
    5.30 +            return false;
    5.31 +        }
    5.32 +
    5.33 +        if (getClass() != obj.getClass()) {
    5.34 +            return false;
    5.35 +        }
    5.36 +
    5.37 +        final StaticExchangeRateProvider other = (StaticExchangeRateProvider) obj;
    5.38 +        if (this.exchangeRate != other.exchangeRate && (this.exchangeRate == null || !this.exchangeRate.equals(other.exchangeRate))) {
    5.39 +            return false;
    5.40 +        }
    5.41 +
    5.42 +        return true;
    5.43 +    }
    5.44 +
    5.45 +    @Override
    5.46 +    public int hashCode() {
    5.47 +        int hash = 7;
    5.48 +        hash = 67 * hash + (this.exchangeRate != null ? this.exchangeRate.hashCode() : 0);
    5.49 +        return hash;
    5.50 +    }
    5.51 +}
     6.1 --- a/task4/solution11/test/org/apidesign/apifest08/test/Task4Test.java	Fri Oct 17 17:33:32 2008 +0200
     6.2 +++ b/task4/solution11/test/org/apidesign/apifest08/test/Task4Test.java	Fri Oct 17 17:34:40 2008 +0200
     6.3 @@ -1,8 +1,13 @@
     6.4  package org.apidesign.apifest08.test;
     6.5  
     6.6 +import java.util.Calendar;
     6.7  import java.util.Date;
     6.8 +import java.util.GregorianCalendar;
     6.9 +import java.util.TimeZone;
    6.10  import junit.framework.TestCase;
    6.11  import org.apidesign.apifest08.currency.Convertor;
    6.12 +import org.apidesign.apifest08.currency.CurrencyValue;
    6.13 +import org.apidesign.apifest08.currency.ExchangeRateValue;
    6.14  
    6.15  /** The exchange rates are not always the same. They are changing. However
    6.16   * as in order to predict the future, one needs to understand own past. That is
    6.17 @@ -44,58 +49,105 @@
    6.18       * @param till final date (exclusive)
    6.19       * @return new convertor
    6.20       */
    6.21 -    public static Convertor limitTo(Convertor old, Date from, Date till) {
    6.22 -        return null;
    6.23 +    public static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> limitTo(Convertor<AmountType, IdentifierType> old, Date from, Date till) {
    6.24 +        return old.limitConvertor(from, till);
    6.25      }
    6.26  
    6.27  
    6.28      public void testCompositionOfLimitedConvertors() throws Exception {
    6.29 -        if (Boolean.getBoolean("ignore.failing")) {
    6.30 -            // implement me! then delete this if statement
    6.31 -            return;
    6.32 -        }
    6.33 -
    6.34 -        Date d1 = null; // 2008-10-01 0:00 GMT
    6.35 -        Date d2 = null; // 2008-10-02 0:00 GMT
    6.36 -        Date d3 = null; // 2008-10-03 0:00 GMT
    6.37 +        Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
    6.38 +        cal.clear();
    6.39 +        cal.set(2008, 9, 1, 0, 0);
    6.40 +        Date d1 = cal.getTime(); // 2008-10-01 0:00 GMT
    6.41 +        cal.set(2008, 9, 2, 0, 0);
    6.42 +        Date d2 = cal.getTime(); // 2008-10-02 0:00 GMT
    6.43 +        cal.set(2008, 9, 3, 0, 0);
    6.44 +        Date d3 = cal.getTime(); // 2008-10-03 0:00 GMT
    6.45          
    6.46 -        Convertor c = Task2Test.merge(
    6.47 +        Convertor<Double, String> c = Task2Test.merge(
    6.48              limitTo(Task1Test.createCZKtoUSD(), d1, d2),
    6.49              limitTo(Task1Test.createSKKtoCZK(), d2, d3)
    6.50          );
    6.51  
    6.52 +        CurrencyValue<Double, String> result;
    6.53          // convert $5 to CZK using c:
    6.54          // cannot convert as no rate is applicable to current date
    6.55 -
    6.56 +        try {
    6.57 +            c.convert("CZK", CurrencyValue.getCurrencyValue(5d, "USD"));
    6.58 +            fail("Should not convert");
    6.59 +        } catch (Exception e) {
    6.60 +        }
    6.61 +        
    6.62          // convert $8 to CZK using c:
    6.63          // cannot convert as no rate is applicable to current date
    6.64 +        try {
    6.65 +            c.convert("CZK", CurrencyValue.getCurrencyValue(8d, "USD"));
    6.66 +            fail("Should not convert");
    6.67 +        } catch (Exception e) {
    6.68 +        }
    6.69  
    6.70          // convert 1003CZK to USD using c:
    6.71          // cannot convert as no rate is applicable to current date
    6.72 +        try {
    6.73 +            c.convert("USD", CurrencyValue.getCurrencyValue(1003d, "CZK"));
    6.74 +            fail("Should not convert");
    6.75 +        } catch (Exception e) {
    6.76 +        }
    6.77  
    6.78          // convert 16CZK using c:
    6.79          // cannot convert as no rate is applicable to current date
    6.80 +        try {
    6.81 +            c.convert("SKK", CurrencyValue.getCurrencyValue(16d, "CZK"));
    6.82 +            fail("Should not convert");
    6.83 +        } catch (Exception e) {
    6.84 +        }
    6.85  
    6.86          // convert 500SKK to CZK using c:
    6.87          // cannot convert as no rate is applicable to current date
    6.88 +        try {
    6.89 +            c.convert("CZK", CurrencyValue.getCurrencyValue(500d, "SKK"));
    6.90 +            fail("Should not convert");
    6.91 +        } catch (Exception e) {
    6.92 +        }
    6.93  
    6.94          // convert $5 to CZK using c at 2008-10-01 6:00 GMT:
    6.95          // assertEquals("Result is 85 CZK");
    6.96 +        cal.set(2008, 9, 1, 6, 0);
    6.97 +        result = c.convert("CZK", CurrencyValue.getCurrencyValue(5d, "USD"), cal.getTime());
    6.98 +        assertEquals(CurrencyValue.getCurrencyValue(85d, "CZK"), result);
    6.99  
   6.100          // convert $8 to CZK using c at 2008-10-01 6:00 GMT:
   6.101          // assertEquals("Result is 136 CZK");
   6.102 +        cal.set(2008, 9, 1, 6, 0);
   6.103 +        result = c.convert("CZK", CurrencyValue.getCurrencyValue(8d, "USD"), cal.getTime());
   6.104 +        assertEquals(CurrencyValue.getCurrencyValue(136d, "CZK"), result);
   6.105  
   6.106          // convert 1003CZK to USD using c at 2008-10-01 6:00 GMT:
   6.107          // assertEquals("Result is 59 USD");
   6.108 +        cal.set(2008, 9, 1, 6, 0);
   6.109 +        result = c.convert("USD", CurrencyValue.getCurrencyValue(1003d, "CZK"), cal.getTime());
   6.110 +        assertEquals(CurrencyValue.getCurrencyValue(59d, "USD"), result);
   6.111  
   6.112          // convert 16CZK using c at 2008-10-02 9:00 GMT:
   6.113          // assertEquals("Result is 20 SKK");
   6.114 +        cal.set(2008, 9, 2, 9, 0);
   6.115 +        result = c.convert("SKK", CurrencyValue.getCurrencyValue(16d, "CZK"), cal.getTime());
   6.116 +        assertEquals(CurrencyValue.getCurrencyValue(20d, "SKK"), result);
   6.117  
   6.118          // convert 500SKK to CZK using c at 2008-10-02 9:00 GMT:
   6.119          // assertEquals("Result is 400 CZK");
   6.120 +        cal.set(2008, 9, 2, 9, 0);
   6.121 +        result = c.convert("CZK", CurrencyValue.getCurrencyValue(500d, "SKK"), cal.getTime());
   6.122 +        assertEquals(CurrencyValue.getCurrencyValue(400d, "CZK"), result);
   6.123  
   6.124          // convert 500SKK to CZK using c at 2008-10-01 6:00 GMT:
   6.125          // cannot convert as no rate is applicable to current date
   6.126 +        cal.set(2008, 9, 1, 6, 0);
   6.127 +        try {
   6.128 +            result = c.convert("CZK", CurrencyValue.getCurrencyValue(500d, "SKK"), cal.getTime());
   6.129 +            fail("Should not convert");
   6.130 +        } catch (Exception e) {
   6.131 +        }
   6.132      }
   6.133  
   6.134      /** Create convertor that understands two currencies, CZK and
   6.135 @@ -103,30 +155,40 @@
   6.136       *
   6.137       * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
   6.138       */
   6.139 -    public static Convertor createSKKtoCZK2() {
   6.140 -        return null;
   6.141 +    public static Convertor<Double, String> createSKKtoCZK2() {
   6.142 +        return Convertor.getConvertorDoubleString(
   6.143 +                ExchangeRateValue.getExchangeRate(
   6.144 +                    CurrencyValue.getCurrencyValue(100d, "SKK"),
   6.145 +                    CurrencyValue.getCurrencyValue(90d, "CZK")));
   6.146      }
   6.147  
   6.148      public void testDateConvetorWithTwoDifferentRates() throws Exception {
   6.149 -        if (Boolean.getBoolean("ignore.failing")) {
   6.150 -            // implement me! then delete this if statement
   6.151 -            return;
   6.152 -        }
   6.153 +        Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
   6.154 +        cal.clear();
   6.155 +        cal.set(2008, 9, 1, 0, 0);
   6.156 +        Date d1 = cal.getTime(); // 2008-10-01 0:00 GMT
   6.157 +        cal.set(2008, 9, 2, 0, 0);
   6.158 +        Date d2 = cal.getTime(); // 2008-10-02 0:00 GMT
   6.159 +        cal.set(2008, 9, 3, 0, 0);
   6.160 +        Date d3 = cal.getTime(); // 2008-10-03 0:00 GMT
   6.161  
   6.162 -        Date d1 = null; // 2008-10-01 0:00 GMT
   6.163 -        Date d2 = null; // 2008-10-02 0:00 GMT
   6.164 -        Date d3 = null; // 2008-10-03 0:00 GMT
   6.165 -
   6.166 -        Convertor c = Task2Test.merge(
   6.167 +        Convertor<Double, String> c = Task2Test.merge(
   6.168              limitTo(createSKKtoCZK2(), d1, d2),
   6.169              limitTo(Task1Test.createSKKtoCZK(), d2, d3)
   6.170          );
   6.171  
   6.172 +        CurrencyValue<Double, String> result;
   6.173          // convert 500SKK to CZK using c at 2008-10-02 9:00 GMT:
   6.174          // assertEquals("Result is 400 CZK");
   6.175 +        cal.set(2008, 9, 2, 9, 0);
   6.176 +        result = c.convert("CZK", CurrencyValue.getCurrencyValue(500d, "SKK"), cal.getTime());
   6.177 +        assertEquals(CurrencyValue.getCurrencyValue(400d, "CZK"), result);
   6.178  
   6.179          // convert 500SKK to CZK using c at 2008-10-01 6:00 GMT:
   6.180          // assertEquals("Result is 450 CZK");
   6.181 +        cal.set(2008, 9, 1, 6, 0);
   6.182 +        result = c.convert("CZK", CurrencyValue.getCurrencyValue(500d, "SKK"), cal.getTime());
   6.183 +        assertEquals(CurrencyValue.getCurrencyValue(450d, "CZK"), result);
   6.184      }
   6.185  
   6.186  }