1.1 --- a/task2/solution13/src/org/apidesign/apifest08/currency/Convertor.java Wed Oct 01 10:43:05 2008 +0200
1.2 +++ b/task2/solution13/src/org/apidesign/apifest08/currency/Convertor.java Tue Oct 07 01:18:23 2008 +0200
1.3 @@ -5,23 +5,54 @@
1.4 import java.math.RoundingMode;
1.5
1.6 /** Convertor able to convert amount from one currency to other currency.
1.7 + * <p>
1.8 + * Conversion method are:
1.9 + * <ul>
1.10 + * <li>{@link #convert(ConvertorCurrency, ConvertorCurrency, BigDecimal)} - convert using exchange rate specified in exchange rate provide. <em>Do not try use reverted excahnage rate</em>.
1.11 + * <li>{@link #convertWithReversibleRates(ConvertorCurrency, ConvertorCurrency, BigDecimal)} - convert using exchange rate specified in exchange rate provide. <em>Try use reverted excahnage rate</em>.
1.12 + * </ul>
1.13 *
1.14 * Exchange rate is provided by {@link ExchangeRateProvider}.
1.15 */
1.16 public class Convertor {
1.17 - boolean remainderAllowed = false; //if false, remained is not allowed (should be true ideally, but can't handle it now)
1.18 + private Convertor[] convertors;
1.19 +
1.20 + /** Create new <code>Convertor</code> as merge of provided convertors. Merged convertor will use
1.21 + * provided convertors to convert between currencies.
1.22 + * <p>
1.23 + * Only one should be able to provide conversion between currencies. If more than one convertos
1.24 + * are able to convert currency, one of conversions will be used (it is not defined which).
1.25 + *
1.26 + * @since version 2
1.27 + * @param convertors Convertor used to create merge-convertor.
1.28 + * @return Returns new convertor instance.
1.29 + */
1.30 + public static Convertor createConvertorAsMerge(Convertor[] convertors) {
1.31 + return new Convertor(convertors);
1.32 + }
1.33 +
1.34 + boolean remainderAllowed = true; //if false, remained is not allowed (should be true ideally, but can't handle it now)
1.35 ExchangeRateProvider exchangeRateProvider;
1.36
1.37 + /** Create simle convertor.
1.38 + */
1.39 private Convertor() {
1.40 -
1.41 + this.convertors=new Convertor[0];
1.42 + }
1.43 +
1.44 + /** Create merge convertor.
1.45 + */
1.46 + private Convertor(Convertor[] convertors) {
1.47 + this.convertors = convertors;
1.48 }
1.49
1.50 /**
1.51 - * Static method used to create convertor.
1.52 + * Create new <code>Convertor</code> using <code>ExchangeRateProvider</code>.
1.53 *
1.54 * @param exchangeRateProvider {@link ExchangeRateProvider} used to get exchange rate.
1.55 *
1.56 * @return Returns <code>Convertor</code> which can be used to convert money.
1.57 + * @since version1
1.58 */
1.59 public static Convertor createConvertor(ExchangeRateProvider exchangeRateProvider) {
1.60 Convertor c = new Convertor();
1.61 @@ -36,9 +67,11 @@
1.62 *
1.63 * @param amount Amount which should be converted. Can't be negative value (can be zero or positive).
1.64 * @return Return <code>ConversionResult</code> which holds conversion result.
1.65 + * @since version1
1.66 + * @deprecated since version2. Use {@link #convert(ConvertorCurrency, ConvertorCurrency, BigDecimal) } - explicitly specify conversion currencies.
1.67 */
1.68 public ConversionResult convert(BigDecimal amount) {
1.69 - return convertValue(amount, false);
1.70 + return convertValue(exchangeRateProvider.getFromCurrency(), exchangeRateProvider.getToCurrency(),amount, false,false);
1.71 }
1.72
1.73 /**
1.74 @@ -47,32 +80,44 @@
1.75 *
1.76 * @param amount Amount which should be converted. Can't be negative value (can be zero or positive).
1.77 * @return Return <code>ConversionResult</code> which holds conversion result.
1.78 + * @since version1
1.79 + * @deprecated since version2. Use {@link #convert(ConvertorCurrency, ConvertorCurrency, BigDecimal) } - explicitly specify conversion currencies.
1.80 */
1.81 public ConversionResult convertBack(BigDecimal amount) {
1.82 - return convertValue(amount, true);
1.83 + return convertValue(exchangeRateProvider.getFromCurrency(), exchangeRateProvider.getToCurrency(),amount, true,false);
1.84 }
1.85
1.86 - private ConversionResult convertValue(BigDecimal amount, boolean convertBack) throws RuntimeException {
1.87 + private ConversionResult convertUsingSimpleConvertor(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency, boolean reversibleExRate, BigDecimal amount, boolean convertBack) throws ConversionNotSupportedException, RuntimeException {
1.88 ConversionResult result = new ConversionResult();
1.89 -
1.90 - ExchangeRate rate = exchangeRateProvider.getExchangeRate();
1.91 - int fromFranctionDigits = exchangeRateProvider.getFromCurrency().getDefaultFractionDigits();
1.92 - int toFractionDigits = exchangeRateProvider.getToCurrency().getDefaultFractionDigits();
1.93 -
1.94 - if (toFractionDigits!=2) {
1.95 - throw new RuntimeException("Can't process currency with defaultFractionDigits!=2, "+exchangeRateProvider.getToCurrency()+" has "+toFractionDigits+" defaultFractionDigits");
1.96 +
1.97 + //ExchangeRate rate = exchangeRateProvider.getExchangeRate();
1.98 + ExchangeRate rate;
1.99 + if (reversibleExRate) {
1.100 + rate = exchangeRateProvider.getReversibleExchangeRate(fromCurrency, toCurrency);
1.101 + } else {
1.102 + rate = exchangeRateProvider.getExchangeRate(fromCurrency, toCurrency);
1.103 }
1.104 - if (fromFranctionDigits!=2) {
1.105 - throw new RuntimeException("Can't process currency with defaultFractionDigits!=2, "+exchangeRateProvider.getFromCurrency()+" has "+fromFranctionDigits+" defaultFractionDigits");
1.106 + if (rate == null) {
1.107 + return null;
1.108 }
1.109
1.110 - if (amount.signum()==-1) {
1.111 - throw new RuntimeException("Can convert only non-negative value, current value is "+amount);
1.112 + int fromFranctionDigits = fromCurrency.getDefaultFractionDigits();
1.113 + int toFractionDigits = toCurrency.getDefaultFractionDigits();
1.114 +
1.115 + if (toFractionDigits != 2) {
1.116 + throw new ConvertorException("Can't process currency with defaultFractionDigits!=2, " + exchangeRateProvider.getToCurrency() + " has " + toFractionDigits + " defaultFractionDigits");
1.117 }
1.118 -
1.119 -
1.120 + if (fromFranctionDigits != 2) {
1.121 + throw new ConvertorException("Can't process currency with defaultFractionDigits!=2, " + exchangeRateProvider.getFromCurrency() + " has " + fromFranctionDigits + " defaultFractionDigits");
1.122 + }
1.123 +
1.124 + if (amount.signum() == -1) {
1.125 + throw new RuntimeException("Can convert only non-negative value, current value is " + amount);
1.126 + }
1.127 +
1.128 +
1.129 MathContext context = new MathContext(0, RoundingMode.DOWN);
1.130 -
1.131 +
1.132 BigDecimal from;
1.133 BigDecimal to;
1.134 if (convertBack) {
1.135 @@ -80,26 +125,89 @@
1.136 to = rate.getFromValue();
1.137 from = rate.getToValue();
1.138 } else {
1.139 - //converting in mornak way
1.140 + //converting in normal way
1.141 from = rate.getFromValue();
1.142 to = rate.getToValue();
1.143 }
1.144
1.145 BigDecimal amountCent = amount.movePointRight(2);
1.146 -
1.147 - final BigDecimal multiplied = amountCent.multiply(to,context);
1.148 - BigDecimal[] division = multiplied.divideAndRemainder(from,context);
1.149 +
1.150 + final BigDecimal multiplied = amountCent.multiply(to, context);
1.151 + BigDecimal[] division = multiplied.divideAndRemainder(from, context);
1.152
1.153 if (!remainderAllowed && !(BigDecimal.ZERO.equals(division[1]))) {
1.154 - throw new RuntimeException("Remained is not allowed - remaining amount is " + division[1]+ " cents");
1.155 + throw new RuntimeException("Remained is not allowed - remaining amount is " + division[1] + " cents");
1.156 } else {
1.157 result.setRemainder(BigDecimal.ZERO);
1.158 }
1.159 -
1.160 - final BigDecimal converted = division[0].movePointLeft(2);
1.161 +
1.162 + final BigDecimal converted = division[0].movePointLeft(2);
1.163 result.setConverted(converted);
1.164 //result.setRemainder(...);
1.165 -
1.166 return result;
1.167 }
1.168 +
1.169 +
1.170 + private ConversionResult convertValue(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency,BigDecimal amount, boolean convertBack,boolean reversibleExRate) throws RuntimeException {
1.171 + //result.setRemainder(...);
1.172 + if (convertors.length==0) {
1.173 + return convertUsingSimpleConvertor(fromCurrency, toCurrency, reversibleExRate, amount, convertBack);
1.174 + } else {
1.175 + ConversionResult result = null;
1.176 + for (int i = 0;i<convertors.length;i++) {
1.177 + Convertor subConvertor = convertors[i];
1.178 + result = subConvertor.convertValue(fromCurrency, toCurrency, amount, convertBack, reversibleExRate);
1.179 + if (result!=null) {
1.180 + break;
1.181 + }
1.182 + }
1.183 + return result;
1.184 + }
1.185 + }
1.186 +
1.187 + /**
1.188 + * Convert <code>value</code> from <code>fromCurrency</code> to <code>toCurrency</code>.
1.189 + * <p>
1.190 + * Exchange rate is provided by exchange rate provider which was specified when Convertor was created.
1.191 + * This method is using only exchange rate from->to and not trying to use reverted excange rate to->from.
1.192 + *
1.193 + * @param fromCurrency Source currency to convert from.
1.194 + * @param toCurrency Target currency to convert to.
1.195 + * @param value Value in source currency which should be converted.
1.196 + * @return Return conversion result.
1.197 + * @since version2
1.198 + * @throws ConversionNotSupportedException If conversion from <code>fromCurrency</code> to <code>toCurrency</code> is not supported.
1.199 + */
1.200 + public ConversionResult convert(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency, BigDecimal value) {
1.201 + ConversionResult result = convertValue(fromCurrency, toCurrency, value, false,false);
1.202 + if (result==null) {
1.203 + //throw new ConversionNotSupportedException("Conversion from " + fromCurrency + " to " + toCurrency + " is not supported");
1.204 + throw new ConversionNotSupportedException(fromCurrency.getCurrencyCode(),toCurrency.getCurrencyCode(),false);
1.205 + }
1.206 + return result;
1.207 + }
1.208 +
1.209 + /**
1.210 + * Convert <code>value</code> from <code>fromCurrency</code> to <code>toCurrency</code>.
1.211 + * Exchange rate is provided by exchange rate provider which was specified when Convertor was created.
1.212 + * <p>
1.213 + * This method is using only exchange rate from->to and if not found, it is trying to use reverted excange rate to->from.
1.214 + *
1.215 + * @param fromCurrency Source currency to convert from.
1.216 + * @param toCurrency Target currency to convert to.
1.217 + * @param value Value in source currency which should be converted.
1.218 + * @return Return conversion result.
1.219 + * @since version2
1.220 + * @throws ConversionNotSupportedException If conversion from <code>fromCurrency</code> to <code>toCurrency</code>
1.221 + * is not supported and neither conversion from <code>toCurrency</code> to <code>fromCurrency</code> is not supported.
1.222 + */
1.223 + public ConversionResult convertWithReversibleRates(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency, BigDecimal value) {
1.224 + ConversionResult result = convertValue(fromCurrency, toCurrency, value, false,true);
1.225 + if (result==null) {
1.226 + //throw new ConversionNotSupportedException("Neither onversion nor reverted conversion from " + fromCurrency + " to " + toCurrency + " is not supported,");
1.227 + throw new ConversionNotSupportedException(fromCurrency.getCurrencyCode(),toCurrency.getCurrencyCode(),true);
1.228 + }
1.229 + return result;
1.230 + }
1.231 +
1.232 }