1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/task3/solution04/src/org/apidesign/apifest08/currency/ConverterImpl.java Tue Oct 07 11:05:34 2008 +0200
1.3 @@ -0,0 +1,282 @@
1.4 +package org.apidesign.apifest08.currency;
1.5 +
1.6 +
1.7 +import java.math.BigDecimal;
1.8 +import java.math.MathContext;
1.9 +import java.math.RoundingMode;
1.10 +import java.util.Collections;
1.11 +import java.util.Currency;
1.12 +import java.util.HashSet;
1.13 +import java.util.Set;
1.14 +
1.15 +
1.16 +/**
1.17 + * Convert between two currencies.
1.18 + *
1.19 + * @author D'Arcy Smith
1.20 + * @version 1.0
1.21 + */
1.22 +final class ConvertorImpl
1.23 + implements Convertor
1.24 +{
1.25 + /**
1.26 + * The currency to cvonvert from.
1.27 + */
1.28 + private final Currency currencyA;
1.29 +
1.30 + /**
1.31 + * The currency to cvonvert from.
1.32 + */
1.33 + private final Currency currencyB;
1.34 +
1.35 + /**
1.36 + * The echange rate between a and b.
1.37 + */
1.38 + private final BigDecimal currencyARate;
1.39 +
1.40 + /**
1.41 + * The echange rate between b and a.
1.42 + */
1.43 + private final BigDecimal currencyBRate;
1.44 +
1.45 + /**
1.46 + * Constructs a convertor with the specified currencies.
1.47 + *
1.48 + * @param a the currency to convert from.
1.49 + * @param aRate the exchage rage between from and to.
1.50 + * @param b the currency to convert to.
1.51 + * @param bRate the exchage rage between to and from.
1.52 + * @throws IllegalArgumentException if either any of the arguments are null or if either rate <= 0.
1.53 + */
1.54 + public ConvertorImpl(final Currency a,
1.55 + final BigDecimal aRate,
1.56 + final Currency b,
1.57 + final BigDecimal bRate)
1.58 + {
1.59 + if(a == null)
1.60 + {
1.61 + throw new IllegalArgumentException("a cannot be null");
1.62 + }
1.63 +
1.64 + if(b == null)
1.65 + {
1.66 + throw new IllegalArgumentException("b cannot be null");
1.67 + }
1.68 +
1.69 + if(aRate == null)
1.70 + {
1.71 + throw new IllegalArgumentException("aRate cannot be null");
1.72 + }
1.73 +
1.74 + if(bRate == null)
1.75 + {
1.76 + throw new IllegalArgumentException("bRate cannot be null");
1.77 + }
1.78 +
1.79 + if(aRate.compareTo(BigDecimal.ZERO) <= 0)
1.80 + {
1.81 + throw new IllegalArgumentException("aRate must be > 0, was: " + aRate);
1.82 + }
1.83 +
1.84 + if(bRate.compareTo(BigDecimal.ZERO) <= 0)
1.85 + {
1.86 + throw new IllegalArgumentException("bRate must be > 0, was: " + bRate);
1.87 + }
1.88 +
1.89 + currencyA = a;
1.90 + currencyB = b;
1.91 + currencyARate = aRate;
1.92 + currencyBRate = bRate;
1.93 + }
1.94 +
1.95 + /**
1.96 + * Convert an amount from one currency to another.
1.97 + *
1.98 + * @param from the currency to convert from.
1.99 + * @param to the currency to convert to.
1.100 + * @param amount the amount to convert.
1.101 + * @return the converted amount.
1.102 + * @throws IllegalArgumentException if any of the arguments are null.
1.103 + * @throws InvalidConversionException if either from or to are not equal to the currencies passed to the constructor.
1.104 + */
1.105 + public BigDecimal convert(final Currency from,
1.106 + final Currency to,
1.107 + final BigDecimal amount)
1.108 + throws InvalidConversionException
1.109 + {
1.110 + final BigDecimal result;
1.111 +
1.112 + if(amount == null)
1.113 + {
1.114 + throw new IllegalArgumentException("amount cannot be null");
1.115 + }
1.116 +
1.117 + if(from == null)
1.118 + {
1.119 + throw new IllegalArgumentException("from cannot be null");
1.120 + }
1.121 +
1.122 + if(to == null)
1.123 + {
1.124 + throw new IllegalArgumentException("to cannot be null");
1.125 + }
1.126 +
1.127 + if(!(from.equals(currencyA)) && (!(from.equals(currencyB))))
1.128 + {
1.129 + throw new InvalidConversionException("cannot convert from: " + from.getCurrencyCode(), from, currencyA, currencyB);
1.130 + }
1.131 +
1.132 + if(!(to.equals(currencyA)) && (!(to.equals(currencyB))))
1.133 + {
1.134 + throw new InvalidConversionException("cannot convert to: " + to.getCurrencyCode(), to, currencyA, currencyB);
1.135 + }
1.136 +
1.137 + result = amount.multiply(getConversionRate(from, to));
1.138 +
1.139 + return (result.setScale(2, RoundingMode.HALF_DOWN));
1.140 + }
1.141 +
1.142 + /**
1.143 + * Check to see if converting between the two currencies is possible.
1.144 + *
1.145 + * @param from the currency to convert from.
1.146 + * @param to the currency to convert to.
1.147 + * @return true if the conversion is possible.
1.148 + */
1.149 + public boolean canConvert(final Currency from, final Currency to)
1.150 + {
1.151 + return ((from.equals(currencyA) || from.equals(currencyB)) &&
1.152 + (to.equals(currencyA) || to.equals(currencyB)));
1.153 + }
1.154 +
1.155 + /**
1.156 + * Get the currencies that the convertor supports.
1.157 + *
1.158 + * @return the supported currencies.
1.159 + */
1.160 + public Set<Currency> getCurrencies()
1.161 + {
1.162 + final Set<Currency> currencies;
1.163 +
1.164 + currencies = new HashSet<Currency>();
1.165 + currencies.add(currencyA);
1.166 + currencies.add(currencyB);
1.167 +
1.168 + return (Collections.unmodifiableSet(currencies));
1.169 + }
1.170 +
1.171 + /**
1.172 + * Get the conversion rate between two currencies.
1.173 + *
1.174 + * @param from the currency to convert from.
1.175 + * @param to the currency to convert to.
1.176 + * @return the conversion rate between the two currencies.
1.177 + * @throws InvalidConversionException if canConvert would return false.
1.178 + */
1.179 + public BigDecimal getConversionRate(final Currency from,
1.180 + final Currency to)
1.181 + throws InvalidConversionException
1.182 + {
1.183 + final BigDecimal rate;
1.184 +
1.185 + if(from.equals(to))
1.186 + {
1.187 + rate = BigDecimal.ONE;
1.188 + }
1.189 + else
1.190 + {
1.191 + final BigDecimal rateX;
1.192 + final BigDecimal rateY;
1.193 + final BigDecimal temp;
1.194 +
1.195 + if(from.equals(currencyA))
1.196 + {
1.197 + rateX = currencyARate;
1.198 + rateY = currencyBRate;
1.199 + }
1.200 + else
1.201 + {
1.202 + rateX = currencyBRate;
1.203 + rateY = currencyARate;
1.204 + }
1.205 +
1.206 + temp = BigDecimal.ONE.divide(rateX, MathContext.DECIMAL64);
1.207 + rate = temp.multiply(rateY);
1.208 + }
1.209 +
1.210 + return (rate.setScale(20, RoundingMode.HALF_EVEN));
1.211 + }
1.212 +
1.213 + /**
1.214 + * Check to see if two ConvertorImpls are equal.
1.215 + *
1.216 + * @param obj the object to check
1.217 + * @return if the ConvertorImpls are not the same (cuyrrencies and rates).
1.218 + */
1.219 + @Override
1.220 + public boolean equals(Object obj)
1.221 + {
1.222 + if (obj == null)
1.223 + {
1.224 + return false;
1.225 + }
1.226 +
1.227 + if (getClass() != obj.getClass())
1.228 + {
1.229 + return false;
1.230 + }
1.231 +
1.232 + final ConvertorImpl other = (ConvertorImpl) obj;
1.233 +
1.234 + // it would be nice if NetBeans could chck to see if the variable is final and guaranteed not to be null... but that
1.235 + // would likely be tricky... but in a NetBeans engineer reads that see if you can do it :-)
1.236 + if (this.currencyA != other.currencyA && (this.currencyA == null || !this.currencyA.equals(other.currencyA)))
1.237 + {
1.238 + return false;
1.239 + }
1.240 +
1.241 + if (this.currencyB != other.currencyB && (this.currencyB == null || !this.currencyB.equals(other.currencyB)))
1.242 + {
1.243 + return false;
1.244 + }
1.245 +
1.246 + if (this.currencyARate != other.currencyARate && (this.currencyARate == null || !this.currencyARate.equals(other.currencyARate)))
1.247 + {
1.248 + return false;
1.249 + }
1.250 +
1.251 + if (this.currencyBRate != other.currencyBRate && (this.currencyBRate == null || !this.currencyBRate.equals(other.currencyBRate)))
1.252 + {
1.253 + return false;
1.254 + }
1.255 +
1.256 + return true;
1.257 + }
1.258 +
1.259 + /**
1.260 + * Get the hashCode of the Convertor.
1.261 + *
1.262 + * @return the hashCode of the convertor.
1.263 + */
1.264 + @Override
1.265 + public int hashCode()
1.266 + {
1.267 + int hash = 7;
1.268 + hash = 37 * hash + (this.currencyA != null ? this.currencyA.hashCode() : 0);
1.269 + hash = 37 * hash + (this.currencyB != null ? this.currencyB.hashCode() : 0);
1.270 + hash = 37 * hash + (this.currencyARate != null ? this.currencyARate.hashCode() : 0);
1.271 + hash = 37 * hash + (this.currencyBRate != null ? this.currencyBRate.hashCode() : 0);
1.272 + return hash;
1.273 + }
1.274 +
1.275 + /**
1.276 + * Get the currencyCode of both currencies.
1.277 + *
1.278 + * @return the currency codes of both currencies.
1.279 + */
1.280 + @Override
1.281 + public String toString()
1.282 + {
1.283 + return (currencyA.getCurrencyCode() + " to " + currencyB.getCurrencyCode());
1.284 + }
1.285 +}