1 package org.apidesign.apifest08.currency;
4 import java.math.BigDecimal;
5 import java.math.RoundingMode;
6 import java.util.Collections;
7 import java.util.Currency;
8 import java.util.HashSet;
13 * The exchange rate between two currencies.
15 * @author D'Arcy Smith
18 public final class ExchangeRate
23 private final Currency currencyA;
28 private final Currency currencyB;
33 private final BigDecimal rateAtoB;
38 private final BigDecimal rateBtoA;
41 * Construct an ExchangeRate with the specified values.
43 * @param a the first currency
44 * @param b the second currency
45 * @param ra the rate to convert a to b
46 * @param rb the rate to covertt b to a
47 * @throws IllegalArgumentException if any parameter is null.
49 public ExchangeRate(final Currency a,
56 throw new IllegalArgumentException("a cannot be null");
61 throw new IllegalArgumentException("b cannot be null");
66 throw new IllegalArgumentException("ra cannot be null");
71 throw new IllegalArgumentException("rb cannot be null");
74 if(ra.compareTo(BigDecimal.ZERO) <= 0)
76 throw new IllegalArgumentException("ra cannot be <= 0, was: " + ra);
79 if(rb.compareTo(BigDecimal.ZERO) <= 0)
81 throw new IllegalArgumentException("rb cannot be <= 0, was: " + ra);
91 * Get the first currency.
93 * @return the first currency.
95 public Currency getCurrencyA()
101 * Get the second currency.
103 * @return the second currency.
105 public Currency getCurrencyB()
111 * Get the conversion rate from currencyA to currencyB.
113 * @return the conversion rate from currencyA to currencyB.
115 public BigDecimal getRateAtoB()
121 * Get the conversion rate from currencyB to currencyA.
123 * @return the conversion rate from currencyB to currencyA.
125 public BigDecimal getRateBtoA()
130 public static ExchangeRate getExchangeRate(final Currency a,
135 final BigDecimal rateAtoB;
136 final BigDecimal rateBtoA;
137 final ExchangeRate rate;
141 throw new IllegalArgumentException("a cannot be null");
146 throw new IllegalArgumentException("b cannot be null");
151 rateAtoB = BigDecimal.ONE;
152 rateBtoA = BigDecimal.ONE;
156 rateAtoB = vb.divide(va, 20, RoundingMode.HALF_DOWN);
157 rateBtoA = va.divide(vb, 20, RoundingMode.HALF_DOWN);
160 rate = new ExchangeRate(a,
162 rateAtoB.setScale(20, RoundingMode.HALF_EVEN),
163 rateBtoA.setScale(20, RoundingMode.HALF_EVEN));
168 public BigDecimal convert(final Currency from,
170 final BigDecimal amount)
171 throws InvalidConversionException
173 final BigDecimal result;
177 throw new IllegalArgumentException("amount cannot be null");
182 throw new IllegalArgumentException("from cannot be null");
187 throw new IllegalArgumentException("to cannot be null");
190 if(!(from.equals(currencyA)) && (!(from.equals(currencyB))))
192 throw new InvalidConversionException("cannot convert from: " + from.getCurrencyCode(), from, currencyA, currencyB);
195 if(!(to.equals(currencyA)) && (!(to.equals(currencyB))))
197 throw new InvalidConversionException("cannot convert to: " + to.getCurrencyCode(), to, currencyA, currencyB);
200 result = amount.multiply(getConversionRate(from, to));
202 return (result.setScale(2, RoundingMode.HALF_DOWN));
206 * Check to see if converting between the two currencies is possible.
208 * @param from the currency to convert from.
209 * @param to the currency to convert to.
210 * @return true if the conversion is possible.
211 * @throws IllegalArgumentException if either from or to are null.
213 public boolean canConvert(final Currency from, final Currency to)
217 throw new IllegalArgumentException("from cannot be null");
222 throw new IllegalArgumentException("to cannot be null");
225 return ((from.equals(currencyA) || from.equals(currencyB)) &&
226 (to.equals(currencyA) || to.equals(currencyB)));
229 * Get the currencies that the convertor supports.
231 * @return the supported currencies.
233 public Set<Currency> getCurrencies()
235 final Set<Currency> currencies;
237 currencies = new HashSet<Currency>();
238 currencies.add(currencyA);
239 currencies.add(currencyB);
241 return (Collections.unmodifiableSet(currencies));
245 * Get the conversion rate between two currencies.
247 * @param from the currency to convert from.
248 * @param to the currency to convert to.
249 * @return the conversion rate between the two currencies.
250 * @throws InvalidConversionException if canConvert would return false.
251 * @throws IllegalArgumentException if either from or to are null.
253 public BigDecimal getConversionRate(final Currency from,
255 throws InvalidConversionException
257 final BigDecimal rate;
261 throw new IllegalArgumentException("from cannot be null");
266 throw new IllegalArgumentException("to cannot be null");
271 rate = BigDecimal.ONE;
275 if(from.equals(currencyA))
288 public String toString()
290 return (rateAtoB + " : " + rateBtoA);
294 public boolean equals(Object obj) {
298 if (getClass() != obj.getClass()) {
301 final ExchangeRate other = (ExchangeRate) obj;
302 if (this.currencyA != other.currencyA && (this.currencyA == null || !this.currencyA.equals(other.currencyA))) {
305 if (this.currencyB != other.currencyB && (this.currencyB == null || !this.currencyB.equals(other.currencyB))) {
308 if (this.rateAtoB != other.rateAtoB && (this.rateAtoB == null || !this.rateAtoB.equals(other.rateAtoB))) {
311 if (this.rateBtoA != other.rateBtoA && (this.rateBtoA == null || !this.rateBtoA.equals(other.rateBtoA))) {
318 public int hashCode() {
320 hash = 97 * hash + (this.currencyA != null ? this.currencyA.hashCode() : 0);
321 hash = 97 * hash + (this.currencyB != null ? this.currencyB.hashCode() : 0);
322 hash = 97 * hash + (this.rateAtoB != null ? this.rateAtoB.hashCode() : 0);
323 hash = 97 * hash + (this.rateBtoA != null ? this.rateBtoA.hashCode() : 0);