# HG changeset patch # User Jaroslav Tulach # Date 1224257680 -7200 # Node ID aa3f99f845efe167820af6133ebb31822bf23fb1 # Parent 8482e36a7ad228c220af618ed0388b7efdd5b45d solution 11, task4 diff -r 8482e36a7ad2 -r aa3f99f845ef task4/solution11/src/org/apidesign/apifest08/currency/Convertor.java --- a/task4/solution11/src/org/apidesign/apifest08/currency/Convertor.java Fri Oct 17 17:33:32 2008 +0200 +++ b/task4/solution11/src/org/apidesign/apifest08/currency/Convertor.java Fri Oct 17 17:34:40 2008 +0200 @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -25,71 +26,99 @@ * as well as static exchange rates. * No time for javadoc, again. * + * In Task4's version takes into account validity range of data sources, + * can convert using an exchange rate value according to the specified instant + * of the time and provides a method for creating a new convertor with the same + * data sources as the old one, but with their validity ranges limited + * to the specified range. + * As usual, no time for javadoc. + * * @author ked */ public final class Convertor { Computer computer; - // each static exchange rate could be a special case of an exchange rate data source - List> exchangeRates = new ArrayList>(); - List> exchangeRateDataSources = new ArrayList>(); + // each static exchange rate is a special case of an exchange rate data source + // historically separated + List> staticExchangeRateDataSources = + new ArrayList>(); + List> exchangeRateDataSources = + new ArrayList>(); + // --- + // BASICS + // --- Convertor(Computer computer) { this.computer = computer; } - - void addExchangeRates(Collection> exchangeRates) { - for (ExchangeRateValue exchangeRate : exchangeRates) { - if (isExchangeRate( - exchangeRate.getCurrencyA().getIdentifier(), - exchangeRate.getCurrencyB().getIdentifier())) { + + void addExchangeRateDataSources( + List> target, + Collection> exchangeRateDataSources) { + for (ExchangeRateDataSource exchangeRateDataSource : exchangeRateDataSources) { + if (isOverlappingExchangeRate( + exchangeRateDataSource.getCurrencyAIdentifier(), + exchangeRateDataSource.getCurrencyBIdentifier(), + exchangeRateDataSource.getValidFrom(), + exchangeRateDataSource.getValidTill())) { throw new IllegalArgumentException("Duplicate exchange rate!"); } - this.exchangeRates.add(exchangeRate); + target.add(exchangeRateDataSource); } } - - void addExchangeRateDataSources(Collection> exchangeRateDataSources) { - for (ExchangeRateDataSource exchangeRateDataSource : exchangeRateDataSources) { - if (isExchangeRate( - exchangeRateDataSource.getCurrencyAIdentifier(), - exchangeRateDataSource.getCurrencyBIdentifier())) { - throw new IllegalArgumentException("Duplicate exchange rate!"); - } - this.exchangeRateDataSources.add(exchangeRateDataSource); - } - } - + ExchangeRateValue findExchangeRate( IdentifierType currencyA, - IdentifierType currencyB) { - for (ExchangeRateValue exchangeRate : exchangeRates) { - if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) || - (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) { - return exchangeRate; - } + IdentifierType currencyB, + Date instant) { + ExchangeRateValue result = null; + result = findExchangeRateInternal(staticExchangeRateDataSources, currencyA, currencyB, instant); + if (result != null) { + return result; } - for (ExchangeRateDataSource exchangeRateDataSource : exchangeRateDataSources) { - if ((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) || - (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) { + result = findExchangeRateInternal(exchangeRateDataSources, currencyA, currencyB, instant); + return result; + } + + ExchangeRateValue findExchangeRateInternal( + List> where, + IdentifierType currencyA, + IdentifierType currencyB, + Date instant) { + for (ExchangeRateDataSource exchangeRateDataSource : where) { + if (((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) || + (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) && + DateUtil.isInRange(instant, exchangeRateDataSource.getValidFrom(), exchangeRateDataSource.getValidTill())) { return exchangeRateDataSource.getExchangeRate(); } } return null; } - - boolean isExchangeRate( + + boolean isOverlappingExchangeRate( IdentifierType currencyA, - IdentifierType currencyB) { - for (ExchangeRateValue exchangeRate : exchangeRates) { - if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) || - (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) { - return true; - } + IdentifierType currencyB, + Date from, + Date to) { + boolean result = false; + result = isOverlappingExchangeRateInternal(staticExchangeRateDataSources, currencyA, currencyB, from, to); + if (result == true) { + return result; } - for (ExchangeRateDataSource exchangeRateDataSource : exchangeRateDataSources) { - if ((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) || - (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) { + result = isOverlappingExchangeRateInternal(exchangeRateDataSources, currencyA, currencyB, from, to); + return result; + } + + boolean isOverlappingExchangeRateInternal( + List> where, + IdentifierType currencyA, + IdentifierType currencyB, + Date from, + Date to) { + for (ExchangeRateDataSource exchangeRateDataSource : where) { + if (((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) || + (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) && + DateUtil.isRangesOverlapping(from, to, exchangeRateDataSource.getValidFrom(), exchangeRateDataSource.getValidTill())) { return true; } } @@ -107,8 +136,15 @@ public CurrencyValue convert( IdentifierType targetCurrency, CurrencyValue currencyValue) { + return convert(targetCurrency, currencyValue, new Date()); // System.currentTimeMillis() + } + + public CurrencyValue convert( + IdentifierType targetCurrency, + CurrencyValue currencyValue, + Date instant) { ExchangeRateValue exchangeRate = - findExchangeRate(currencyValue.getIdentifier(), targetCurrency); + findExchangeRate(currencyValue.getIdentifier(), targetCurrency, instant); if (exchangeRate == null) { throw new IllegalArgumentException("Inappropriate currencies to convert!"); } @@ -136,23 +172,57 @@ } // --- + // LIMITING + // --- + Collection> limitDataSources( + Collection> source, + Date from, Date till) { + Collection> result = + new ArrayList>(); + + for (ExchangeRateDataSource dataSource : source) { + result.add(ExchangeRateDataSource.getExchangeRateDataSource( + dataSource.getCurrencyAIdentifier(), dataSource.getCurrencyBIdentifier(), + dataSource.getExchangeRateProvider(), + DateUtil.getRangesIntersectionBottom(dataSource.getValidFrom(), from), + DateUtil.getRangesIntersectionTop(dataSource.getValidTill(), till))); + } + + return result; + } + + public Convertor limitConvertor(Date from, Date till) { + Collection> limitedStatic = + limitDataSources(staticExchangeRateDataSources, from, till); + Collection> limited = + limitDataSources(exchangeRateDataSources, from, till); + + Convertor c = new Convertor(computer); + c.addExchangeRateDataSources(c.staticExchangeRateDataSources, limitedStatic); + c.addExchangeRateDataSources(c.exchangeRateDataSources, limited); + return c; + } + + // --- // MERGING // --- static Convertor mergeConvertors( Computer computer, Collection> convertors) { - Set> exchangeRatesSet = new HashSet>(); - Set> exchangeRateDataSourcesSet = new HashSet>(); + Set> mergedStatic = + new HashSet>(); + Set> merged = + new HashSet>(); for (Convertor convertor : convertors) { - exchangeRatesSet.addAll(convertor.exchangeRates); + mergedStatic.addAll(convertor.staticExchangeRateDataSources); } for (Convertor convertor : convertors) { - exchangeRateDataSourcesSet.addAll(convertor.exchangeRateDataSources); + merged.addAll(convertor.exchangeRateDataSources); } - + Convertor c = new Convertor(computer); - c.addExchangeRates(exchangeRatesSet); - c.addExchangeRateDataSources(exchangeRateDataSourcesSet); + c.addExchangeRateDataSources(c.staticExchangeRateDataSources, mergedStatic); + c.addExchangeRateDataSources(c.exchangeRateDataSources, merged); return c; } @@ -195,17 +265,25 @@ static Convertor getConvertor( Computer computer, Collection> exchangeRates) { Convertor c = new Convertor(computer); - c.addExchangeRates(exchangeRates); + Collection> exchangeRateDataSources = + new ArrayList>(); + for (ExchangeRateValue exchangeRate : exchangeRates) { + exchangeRateDataSources.add( + ExchangeRateDataSource.getExchangeRateDataSource( + exchangeRate.getCurrencyA().getIdentifier(), exchangeRate.getCurrencyB().getIdentifier(), + StaticExchangeRateProvider.getStaticExchangeRateProvider(exchangeRate))); + } + c.addExchangeRateDataSources(c.staticExchangeRateDataSources, exchangeRateDataSources); return c; } static Convertor getConvertorDataSource( Computer computer, Collection> exchangeRateDataSources) { Convertor c = new Convertor(computer); - c.addExchangeRateDataSources(exchangeRateDataSources); + c.addExchangeRateDataSources(c.exchangeRateDataSources, exchangeRateDataSources); return c; } - + static Convertor getConvertor( Computer computer, ExchangeRateValue exchangeRate) { Collection> exchangeRates = @@ -213,7 +291,7 @@ exchangeRates.add(exchangeRate); return getConvertor(computer, exchangeRates); } - + static Convertor getConvertorDataSource( Computer computer, ExchangeRateDataSource exchangeRateDataSource) { Collection> exchangeRateDataSources = @@ -221,7 +299,7 @@ exchangeRateDataSources.add(exchangeRateDataSource); return getConvertorDataSource(computer, exchangeRateDataSources); } - + public static Convertor getConvertorDoubleString( Collection> exchangeRates) { return getConvertor(DoubleComputer, exchangeRates); @@ -231,7 +309,7 @@ ExchangeRateValue exchangeRate) { return getConvertor(DoubleComputer, exchangeRate); } - + public static Convertor getConvertorDataSourceDoubleString( Collection> exchangeRateDataSources) { return getConvertorDataSource(DoubleComputer, exchangeRateDataSources); @@ -241,7 +319,7 @@ ExchangeRateDataSource exchangeRateDataSource) { return getConvertorDataSource(DoubleComputer, exchangeRateDataSource); } - + public static Convertor getConvertorIntegerString( Collection> exchangeRates) { return getConvertor(IntegerComputer, exchangeRates); @@ -251,7 +329,7 @@ ExchangeRateValue exchangeRate) { return getConvertor(IntegerComputer, exchangeRate); } - + public static Convertor getConvertorDataSourceIntegerString( Collection> exchangeRateDataSources) { return getConvertorDataSource(IntegerComputer, exchangeRateDataSources); @@ -292,7 +370,7 @@ CurrencyValue secondCurrencyExchangeRate) { return getConvertorIntegerString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate)); } - + // --- // COMPUTERS // --- diff -r 8482e36a7ad2 -r aa3f99f845ef task4/solution11/src/org/apidesign/apifest08/currency/DateUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/task4/solution11/src/org/apidesign/apifest08/currency/DateUtil.java Fri Oct 17 17:34:40 2008 +0200 @@ -0,0 +1,68 @@ +package org.apidesign.apifest08.currency; + +import java.util.Date; + +/** + * Date util helper class. + * @author ked + */ +final class DateUtil { + + private DateUtil() {}; + + static boolean isInRange(Date instant, Date from, Date till) { + if ((from == null || instant.equals(from) || instant.after(from)) && + (till == null || instant.before(till))) { + return true; + } else { + return false; + } + } + + static boolean isRangesOverlapping(Date fromA, Date tillA, Date fromB, Date tillB) { + if ((fromA == null && tillA == null) || (fromB == null && tillB == null)) { + return true; + } + if (fromA != null && isInRange(fromA, fromB, tillB)) { + return true; + } + if (tillA != null && !tillA.equals(fromB) && isInRange(tillA, fromB, tillB)) { + return true; + } + if (fromB != null && isInRange(fromB, fromA, tillA)) { + return true; + } + if (tillB != null && !tillB.equals(fromA) && isInRange(tillB, fromA, tillA)) { + return true; + } + return false; + } + + static Date getRangesIntersectionBottom(Date fromA, Date fromB) { + if (fromA == null) { + return fromB; + } + if (fromB == null) { + return fromA; + } + if (fromA.after(fromB)) { + return fromA; + } else { + return fromB; + } + } + + static Date getRangesIntersectionTop(Date tillA, Date tillB) { + if (tillA == null) { + return tillB; + } + if (tillB == null) { + return tillA; + } + if (tillA.before(tillB)) { + return tillA; + } else { + return tillB; + } + } +} diff -r 8482e36a7ad2 -r aa3f99f845ef task4/solution11/src/org/apidesign/apifest08/currency/ExchangeRateDataSource.java --- a/task4/solution11/src/org/apidesign/apifest08/currency/ExchangeRateDataSource.java Fri Oct 17 17:33:32 2008 +0200 +++ b/task4/solution11/src/org/apidesign/apifest08/currency/ExchangeRateDataSource.java Fri Oct 17 17:34:40 2008 +0200 @@ -1,5 +1,6 @@ package org.apidesign.apifest08.currency; +import java.util.Date; import org.apidesign.apifest08.currency.ExchangeRateProvider.ExchangeRateRequest; import org.apidesign.apifest08.currency.ExchangeRateProvider.ExchangeRateResponse; @@ -10,94 +11,144 @@ */ public final class ExchangeRateDataSource { - private final IdentifierType currencyAIdentifier; + private final IdentifierType currencyAIdentifier; + private final IdentifierType currencyBIdentifier; + private final ExchangeRateProvider exchangeRateProvider; + private final Date validFrom; + private final Date validTill; - private final IdentifierType currencyBIdentifier; + private ExchangeRateDataSource( + IdentifierType currencyAIdentifier, + IdentifierType currencyBIdentifier, + ExchangeRateProvider exchangeRateProvider, + Date validFrom, + Date validTill) { + if (currencyAIdentifier == null || + currencyBIdentifier == null || + currencyAIdentifier.equals(currencyBIdentifier)) { + throw new IllegalArgumentException("Inappropriate exchange rates' identifiers!"); + } + if (validFrom != null && + validTill != null && + !validTill.after(validFrom)) { + throw new IllegalArgumentException("Inappropriate exchange rate validity!"); + } - private final ExchangeRateProvider exchangeRateProvider; + this.currencyAIdentifier = currencyAIdentifier; + this.currencyBIdentifier = currencyBIdentifier; + this.exchangeRateProvider = exchangeRateProvider; + this.validFrom = validFrom; + this.validTill = validTill; + } - private ExchangeRateDataSource( - IdentifierType currencyAIdentifier, - IdentifierType currencyBIdentifier, - ExchangeRateProvider exchangeRateProvider) { - if (currencyAIdentifier == null || - currencyBIdentifier == null || - currencyAIdentifier.equals(currencyBIdentifier)) { - throw new IllegalArgumentException("Inappropriate exchange rates' identifiers!"); + public IdentifierType getCurrencyAIdentifier() { + return currencyAIdentifier; + } + + public IdentifierType getCurrencyBIdentifier() { + return currencyBIdentifier; + } + + ExchangeRateProvider getExchangeRateProvider() { + return exchangeRateProvider; + } + + public Date getValidFrom() { + return validFrom != null ? (Date) validFrom.clone() : null; + } + + public Date getValidTill() { + return validTill != null ? (Date) validTill.clone() : null; + } + + public ExchangeRateValue getExchangeRate() { + return getExchangeRate(new Date()); // System.currentTimeMillis() + } + + public ExchangeRateValue getExchangeRate(Date instant) { + ExchangeRateRequest request = + new ExchangeRateRequest(); + ExchangeRateResponse response = + new ExchangeRateResponse(); + + request.setCurrencyAIdentifier(currencyAIdentifier); + request.setCurrencyBIdentifier(currencyBIdentifier); + request.setInstant(instant); + + exchangeRateProvider.getExchangeRate(request, response); + + ExchangeRateValue result = response.getExchangeRate(); + if (result.getCurrencyA().getIdentifier().equals(currencyAIdentifier) && + result.getCurrencyB().getIdentifier().equals(currencyBIdentifier)) { + return result; + } else { + throw new IllegalStateException("Data source's provider returned inappropriate exchange rate!"); } - this.currencyAIdentifier = currencyAIdentifier; - this.currencyBIdentifier = currencyBIdentifier; - this.exchangeRateProvider = exchangeRateProvider; - } + } - public IdentifierType getCurrencyAIdentifier() { - return currencyAIdentifier; - } + public static ExchangeRateDataSource getExchangeRateDataSource( + IdentifierType currencyAIdentifier, + IdentifierType currencyBIdentifier, + ExchangeRateProvider exchangeRateProvider) { + return getExchangeRateDataSource( + currencyAIdentifier, + currencyBIdentifier, + exchangeRateProvider, + null, + null); + } - public IdentifierType getCurrencyBIdentifier() { - return currencyBIdentifier; - } + public static ExchangeRateDataSource getExchangeRateDataSource( + IdentifierType currencyAIdentifier, + IdentifierType currencyBIdentifier, + ExchangeRateProvider exchangeRateProvider, + Date validFrom, + Date validTill) { + return new ExchangeRateDataSource( + currencyAIdentifier, + currencyBIdentifier, + exchangeRateProvider, + validFrom, + validTill); + } - public ExchangeRateValue getExchangeRate() { - ExchangeRateRequest request = - new ExchangeRateRequest(); - ExchangeRateResponse response = - new ExchangeRateResponse(); + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ExchangeRateDataSource other = + (ExchangeRateDataSource) obj; + if (this.currencyAIdentifier != other.currencyAIdentifier && + (this.currencyAIdentifier == null || !this.currencyAIdentifier.equals(other.currencyAIdentifier))) { + return false; + } + if (this.currencyBIdentifier != other.currencyBIdentifier && + (this.currencyBIdentifier == null || !this.currencyBIdentifier.equals(other.currencyBIdentifier))) { + return false; + } + if (this.exchangeRateProvider != other.exchangeRateProvider && + (this.exchangeRateProvider == null || !this.exchangeRateProvider.equals(other.exchangeRateProvider))) { + return false; + } + if (this.validFrom != other.validFrom && (this.validFrom == null || !this.validFrom.equals(other.validFrom))) { + return false; + } + if (this.validTill != other.validTill && (this.validTill == null || !this.validTill.equals(other.validTill))) { + return false; + } + return true; + } - request.setCurrencyAIdentifier(currencyAIdentifier); - request.setCurrencyBIdentifier(currencyBIdentifier); - - exchangeRateProvider.getExchangeRate(request, response); - - if (response.getExchangeRate().getCurrencyA().getIdentifier().equals(currencyAIdentifier) && - response.getExchangeRate().getCurrencyB().getIdentifier().equals(currencyBIdentifier)) { - return response.getExchangeRate(); - } else { - throw new IllegalStateException("Data source's provider returned inappropriate exchange rate!"); + @Override + public int hashCode() { + int hash = 7; + hash = 83 * hash + (this.currencyAIdentifier != null ? this.currencyAIdentifier.hashCode() : 0); + hash = 83 * hash + (this.currencyBIdentifier != null ? this.currencyBIdentifier.hashCode() : 0); + hash = 83 * hash + (this.exchangeRateProvider != null ? this.exchangeRateProvider.hashCode() : 0); + return hash; } - } - - public static ExchangeRateDataSource getExchangeRateDataSource( - IdentifierType currencyAIdentifier, - IdentifierType currencyBIdentifier, - ExchangeRateProvider exchangeRateProvider) { - return new ExchangeRateDataSource( - currencyAIdentifier, - currencyBIdentifier, - exchangeRateProvider); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final ExchangeRateDataSource other = - (ExchangeRateDataSource) obj; - if (this.currencyAIdentifier != other.currencyAIdentifier && - (this.currencyAIdentifier == null || !this.currencyAIdentifier.equals(other.currencyAIdentifier))) { - return false; - } - if (this.currencyBIdentifier != other.currencyBIdentifier && - (this.currencyBIdentifier == null || !this.currencyBIdentifier.equals(other.currencyBIdentifier))) { - return false; - } - if (this.exchangeRateProvider != other.exchangeRateProvider && - (this.exchangeRateProvider == null || !this.exchangeRateProvider.equals(other.exchangeRateProvider))) { - return false; - } - return true; - } - - @Override - public int hashCode() { - int hash = 7; - hash = 83 * hash + (this.currencyAIdentifier != null ? this.currencyAIdentifier.hashCode() : 0); - hash = 83 * hash + (this.currencyBIdentifier != null ? this.currencyBIdentifier.hashCode() : 0); - hash = 83 * hash + (this.exchangeRateProvider != null ? this.exchangeRateProvider.hashCode() : 0); - return hash; - } } diff -r 8482e36a7ad2 -r aa3f99f845ef task4/solution11/src/org/apidesign/apifest08/currency/ExchangeRateProvider.java --- a/task4/solution11/src/org/apidesign/apifest08/currency/ExchangeRateProvider.java Fri Oct 17 17:33:32 2008 +0200 +++ b/task4/solution11/src/org/apidesign/apifest08/currency/ExchangeRateProvider.java Fri Oct 17 17:34:40 2008 +0200 @@ -1,5 +1,7 @@ package org.apidesign.apifest08.currency; +import java.util.Date; + /** * Exchange rate provider. * @@ -16,6 +18,7 @@ private IdentifierType currencyAIdentifier; private IdentifierType currencyBIdentifier; + private Date instant; ExchangeRateRequest() { } @@ -35,6 +38,14 @@ void setCurrencyBIdentifier(IdentifierType currencyBIdentifier) { this.currencyBIdentifier = currencyBIdentifier; } + + public Date getInstant() { + return instant; + } + + void setInstant(Date instant) { + this.instant = instant; + } } public final class ExchangeRateResponse { diff -r 8482e36a7ad2 -r aa3f99f845ef task4/solution11/src/org/apidesign/apifest08/currency/StaticExchangeRateProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/task4/solution11/src/org/apidesign/apifest08/currency/StaticExchangeRateProvider.java Fri Oct 17 17:34:40 2008 +0200 @@ -0,0 +1,48 @@ +package org.apidesign.apifest08.currency; + +/** + * Static exchange rate provider. + * + * @author ked + */ +final class StaticExchangeRateProvider implements ExchangeRateProvider { + + final ExchangeRateValue exchangeRate; + + private StaticExchangeRateProvider(ExchangeRateValue exchangeRate) { + this.exchangeRate = exchangeRate; + } + + public void getExchangeRate(ExchangeRateRequest request, ExchangeRateResponse response) { + response.setExchangeRate(exchangeRate); + } + + static StaticExchangeRateProvider getStaticExchangeRateProvider(ExchangeRateValue exchangeRate) { + return new StaticExchangeRateProvider(exchangeRate); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + + final StaticExchangeRateProvider other = (StaticExchangeRateProvider) obj; + if (this.exchangeRate != other.exchangeRate && (this.exchangeRate == null || !this.exchangeRate.equals(other.exchangeRate))) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 67 * hash + (this.exchangeRate != null ? this.exchangeRate.hashCode() : 0); + return hash; + } +} diff -r 8482e36a7ad2 -r aa3f99f845ef task4/solution11/test/org/apidesign/apifest08/test/Task4Test.java --- a/task4/solution11/test/org/apidesign/apifest08/test/Task4Test.java Fri Oct 17 17:33:32 2008 +0200 +++ b/task4/solution11/test/org/apidesign/apifest08/test/Task4Test.java Fri Oct 17 17:34:40 2008 +0200 @@ -1,8 +1,13 @@ package org.apidesign.apifest08.test; +import java.util.Calendar; import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; import junit.framework.TestCase; import org.apidesign.apifest08.currency.Convertor; +import org.apidesign.apifest08.currency.CurrencyValue; +import org.apidesign.apifest08.currency.ExchangeRateValue; /** The exchange rates are not always the same. They are changing. However * as in order to predict the future, one needs to understand own past. That is @@ -44,58 +49,105 @@ * @param till final date (exclusive) * @return new convertor */ - public static Convertor limitTo(Convertor old, Date from, Date till) { - return null; + public static Convertor limitTo(Convertor old, Date from, Date till) { + return old.limitConvertor(from, till); } public void testCompositionOfLimitedConvertors() throws Exception { - if (Boolean.getBoolean("ignore.failing")) { - // implement me! then delete this if statement - return; - } - - Date d1 = null; // 2008-10-01 0:00 GMT - Date d2 = null; // 2008-10-02 0:00 GMT - Date d3 = null; // 2008-10-03 0:00 GMT + Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); + cal.clear(); + cal.set(2008, 9, 1, 0, 0); + Date d1 = cal.getTime(); // 2008-10-01 0:00 GMT + cal.set(2008, 9, 2, 0, 0); + Date d2 = cal.getTime(); // 2008-10-02 0:00 GMT + cal.set(2008, 9, 3, 0, 0); + Date d3 = cal.getTime(); // 2008-10-03 0:00 GMT - Convertor c = Task2Test.merge( + Convertor c = Task2Test.merge( limitTo(Task1Test.createCZKtoUSD(), d1, d2), limitTo(Task1Test.createSKKtoCZK(), d2, d3) ); + CurrencyValue result; // convert $5 to CZK using c: // cannot convert as no rate is applicable to current date - + try { + c.convert("CZK", CurrencyValue.getCurrencyValue(5d, "USD")); + fail("Should not convert"); + } catch (Exception e) { + } + // convert $8 to CZK using c: // cannot convert as no rate is applicable to current date + try { + c.convert("CZK", CurrencyValue.getCurrencyValue(8d, "USD")); + fail("Should not convert"); + } catch (Exception e) { + } // convert 1003CZK to USD using c: // cannot convert as no rate is applicable to current date + try { + c.convert("USD", CurrencyValue.getCurrencyValue(1003d, "CZK")); + fail("Should not convert"); + } catch (Exception e) { + } // convert 16CZK using c: // cannot convert as no rate is applicable to current date + try { + c.convert("SKK", CurrencyValue.getCurrencyValue(16d, "CZK")); + fail("Should not convert"); + } catch (Exception e) { + } // convert 500SKK to CZK using c: // cannot convert as no rate is applicable to current date + try { + c.convert("CZK", CurrencyValue.getCurrencyValue(500d, "SKK")); + fail("Should not convert"); + } catch (Exception e) { + } // convert $5 to CZK using c at 2008-10-01 6:00 GMT: // assertEquals("Result is 85 CZK"); + cal.set(2008, 9, 1, 6, 0); + result = c.convert("CZK", CurrencyValue.getCurrencyValue(5d, "USD"), cal.getTime()); + assertEquals(CurrencyValue.getCurrencyValue(85d, "CZK"), result); // convert $8 to CZK using c at 2008-10-01 6:00 GMT: // assertEquals("Result is 136 CZK"); + cal.set(2008, 9, 1, 6, 0); + result = c.convert("CZK", CurrencyValue.getCurrencyValue(8d, "USD"), cal.getTime()); + assertEquals(CurrencyValue.getCurrencyValue(136d, "CZK"), result); // convert 1003CZK to USD using c at 2008-10-01 6:00 GMT: // assertEquals("Result is 59 USD"); + cal.set(2008, 9, 1, 6, 0); + result = c.convert("USD", CurrencyValue.getCurrencyValue(1003d, "CZK"), cal.getTime()); + assertEquals(CurrencyValue.getCurrencyValue(59d, "USD"), result); // convert 16CZK using c at 2008-10-02 9:00 GMT: // assertEquals("Result is 20 SKK"); + cal.set(2008, 9, 2, 9, 0); + result = c.convert("SKK", CurrencyValue.getCurrencyValue(16d, "CZK"), cal.getTime()); + assertEquals(CurrencyValue.getCurrencyValue(20d, "SKK"), result); // convert 500SKK to CZK using c at 2008-10-02 9:00 GMT: // assertEquals("Result is 400 CZK"); + cal.set(2008, 9, 2, 9, 0); + result = c.convert("CZK", CurrencyValue.getCurrencyValue(500d, "SKK"), cal.getTime()); + assertEquals(CurrencyValue.getCurrencyValue(400d, "CZK"), result); // convert 500SKK to CZK using c at 2008-10-01 6:00 GMT: // cannot convert as no rate is applicable to current date + cal.set(2008, 9, 1, 6, 0); + try { + result = c.convert("CZK", CurrencyValue.getCurrencyValue(500d, "SKK"), cal.getTime()); + fail("Should not convert"); + } catch (Exception e) { + } } /** Create convertor that understands two currencies, CZK and @@ -103,30 +155,40 @@ * * @return prepared convertor ready for converting SKK to CZK and CZK to SKK */ - public static Convertor createSKKtoCZK2() { - return null; + public static Convertor createSKKtoCZK2() { + return Convertor.getConvertorDoubleString( + ExchangeRateValue.getExchangeRate( + CurrencyValue.getCurrencyValue(100d, "SKK"), + CurrencyValue.getCurrencyValue(90d, "CZK"))); } public void testDateConvetorWithTwoDifferentRates() throws Exception { - if (Boolean.getBoolean("ignore.failing")) { - // implement me! then delete this if statement - return; - } + Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); + cal.clear(); + cal.set(2008, 9, 1, 0, 0); + Date d1 = cal.getTime(); // 2008-10-01 0:00 GMT + cal.set(2008, 9, 2, 0, 0); + Date d2 = cal.getTime(); // 2008-10-02 0:00 GMT + cal.set(2008, 9, 3, 0, 0); + Date d3 = cal.getTime(); // 2008-10-03 0:00 GMT - Date d1 = null; // 2008-10-01 0:00 GMT - Date d2 = null; // 2008-10-02 0:00 GMT - Date d3 = null; // 2008-10-03 0:00 GMT - - Convertor c = Task2Test.merge( + Convertor c = Task2Test.merge( limitTo(createSKKtoCZK2(), d1, d2), limitTo(Task1Test.createSKKtoCZK(), d2, d3) ); + CurrencyValue result; // convert 500SKK to CZK using c at 2008-10-02 9:00 GMT: // assertEquals("Result is 400 CZK"); + cal.set(2008, 9, 2, 9, 0); + result = c.convert("CZK", CurrencyValue.getCurrencyValue(500d, "SKK"), cal.getTime()); + assertEquals(CurrencyValue.getCurrencyValue(400d, "CZK"), result); // convert 500SKK to CZK using c at 2008-10-01 6:00 GMT: // assertEquals("Result is 450 CZK"); + cal.set(2008, 9, 1, 6, 0); + result = c.convert("CZK", CurrencyValue.getCurrencyValue(500d, "SKK"), cal.getTime()); + assertEquals(CurrencyValue.getCurrencyValue(450d, "CZK"), result); } }