1.1 --- a/task4/solution11/src/org/apidesign/apifest08/currency/Convertor.java Sat Oct 11 23:38:46 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 // ---