diff -r 14e78f48ac2b -r 58ec6da75f6f task4/solution04/src/org/apidesign/apifest08/currency/ConverterImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/task4/solution04/src/org/apidesign/apifest08/currency/ConverterImpl.java Sat Oct 11 23:38:46 2008 +0200 @@ -0,0 +1,304 @@ +package org.apidesign.apifest08.currency; + + +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; +import java.util.Collections; +import java.util.Currency; +import java.util.HashSet; +import java.util.Set; + + +/** + * Convert between two currencies. + * + * @author D'Arcy Smith + * @version 1.0 + */ +final class ConvertorImpl + implements Convertor +{ + /** + * The currency to convert from. + */ + private final Currency currencyA; + + /** + * The currency to convert to. + */ + private final Currency currencyB; + + /** + * The echange rate between a and b. + */ + private final BigDecimal currencyARate; + + /** + * The echange rate between b and a. + */ + private final BigDecimal currencyBRate; + + /** + * Constructs a convertor with the specified currencies. + * + * @param a the currency to convert from. + * @param aRate the exchage rage between from and to. + * @param b the currency to convert to. + * @param bRate the exchage rage between to and from. + * @throws IllegalArgumentException if either any of the arguments are null or if either rate <= 0. + */ + public ConvertorImpl(final Currency a, + final BigDecimal aRate, + final Currency b, + final BigDecimal bRate) + { + if(a == null) + { + throw new IllegalArgumentException("a cannot be null"); + } + + if(b == null) + { + throw new IllegalArgumentException("b cannot be null"); + } + + if(aRate == null) + { + throw new IllegalArgumentException("aRate cannot be null"); + } + + if(bRate == null) + { + throw new IllegalArgumentException("bRate cannot be null"); + } + + if(aRate.compareTo(BigDecimal.ZERO) <= 0) + { + throw new IllegalArgumentException("aRate must be > 0, was: " + aRate); + } + + if(bRate.compareTo(BigDecimal.ZERO) <= 0) + { + throw new IllegalArgumentException("bRate must be > 0, was: " + bRate); + } + + currencyA = a; + currencyB = b; + currencyARate = aRate; + currencyBRate = bRate; + } + + /** + * Convert an amount from one currency to another. + * + * @param from the currency to convert from. + * @param to the currency to convert to. + * @param amount the amount to convert. + * @return the converted amount. + * @throws IllegalArgumentException if any of the arguments are null. + * @throws InvalidConversionException if either from or to are not equal to the currencies passed to the constructor. + */ + public BigDecimal convert(final Currency from, + final Currency to, + final BigDecimal amount) + throws InvalidConversionException + { + final BigDecimal result; + + if(amount == null) + { + throw new IllegalArgumentException("amount cannot be null"); + } + + if(from == null) + { + throw new IllegalArgumentException("from cannot be null"); + } + + if(to == null) + { + throw new IllegalArgumentException("to cannot be null"); + } + + if(!(from.equals(currencyA)) && (!(from.equals(currencyB)))) + { + throw new InvalidConversionException("cannot convert from: " + from.getCurrencyCode(), from, currencyA, currencyB); + } + + if(!(to.equals(currencyA)) && (!(to.equals(currencyB)))) + { + throw new InvalidConversionException("cannot convert to: " + to.getCurrencyCode(), to, currencyA, currencyB); + } + + result = amount.multiply(getConversionRate(from, to)); + + return (result.setScale(2, RoundingMode.HALF_DOWN)); + } + + /** + * Check to see if converting between the two currencies is possible. + * + * @param from the currency to convert from. + * @param to the currency to convert to. + * @return true if the conversion is possible. + * @throws IllegalArgumentException if either from or to are null. + */ + public boolean canConvert(final Currency from, final Currency to) + { + if(from == null) + { + throw new IllegalArgumentException("from cannot be null"); + } + + if(to == null) + { + throw new IllegalArgumentException("to cannot be null"); + } + + return ((from.equals(currencyA) || from.equals(currencyB)) && + (to.equals(currencyA) || to.equals(currencyB))); + } + + /** + * Get the currencies that the convertor supports. + * + * @return the supported currencies. + */ + public Set getCurrencies() + { + final Set currencies; + + currencies = new HashSet(); + currencies.add(currencyA); + currencies.add(currencyB); + + return (Collections.unmodifiableSet(currencies)); + } + + /** + * Get the conversion rate between two currencies. + * + * @param from the currency to convert from. + * @param to the currency to convert to. + * @return the conversion rate between the two currencies. + * @throws InvalidConversionException if canConvert would return false. + * @throws IllegalArgumentException if either from or to are null. + */ + public BigDecimal getConversionRate(final Currency from, + final Currency to) + throws InvalidConversionException + { + final BigDecimal rate; + + if(from == null) + { + throw new IllegalArgumentException("from cannot be null"); + } + + if(to == null) + { + throw new IllegalArgumentException("to cannot be null"); + } + + if(from.equals(to)) + { + rate = BigDecimal.ONE; + } + else + { + final BigDecimal rateX; + final BigDecimal rateY; + final BigDecimal temp; + + if(from.equals(currencyA)) + { + rateX = currencyARate; + rateY = currencyBRate; + } + else + { + rateX = currencyBRate; + rateY = currencyARate; + } + + temp = BigDecimal.ONE.divide(rateX, MathContext.DECIMAL64); + rate = temp.multiply(rateY); + } + + return (rate.setScale(20, RoundingMode.HALF_EVEN)); + } + + /** + * Check to see if two ConvertorImpls are equal. + * + * @param obj the object to check + * @return if the ConvertorImpls are not the same (cuyrrencies and rates). + */ + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + + if (getClass() != obj.getClass()) + { + return false; + } + + final ConvertorImpl other = (ConvertorImpl) obj; + + // it would be nice if NetBeans could chck to see if the variable is final and guaranteed not to be null... but that + // would likely be tricky... but in a NetBeans engineer reads that see if you can do it :-) + if (this.currencyA != other.currencyA && (this.currencyA == null || !this.currencyA.equals(other.currencyA))) + { + return false; + } + + if (this.currencyB != other.currencyB && (this.currencyB == null || !this.currencyB.equals(other.currencyB))) + { + return false; + } + + if (this.currencyARate != other.currencyARate && (this.currencyARate == null || !this.currencyARate.equals(other.currencyARate))) + { + return false; + } + + if (this.currencyBRate != other.currencyBRate && (this.currencyBRate == null || !this.currencyBRate.equals(other.currencyBRate))) + { + return false; + } + + return true; + } + + /** + * Get the hashCode of the Convertor. + * + * @return the hashCode of the convertor. + */ + @Override + public int hashCode() + { + int hash = 7; + hash = 37 * hash + (this.currencyA != null ? this.currencyA.hashCode() : 0); + hash = 37 * hash + (this.currencyB != null ? this.currencyB.hashCode() : 0); + hash = 37 * hash + (this.currencyARate != null ? this.currencyARate.hashCode() : 0); + hash = 37 * hash + (this.currencyBRate != null ? this.currencyBRate.hashCode() : 0); + return hash; + } + + /** + * Get the currencyCode of both currencies. + * + * @return the currency codes of both currencies. + */ + @Override + public String toString() + { + return (currencyA.getCurrencyCode() + " to " + currencyB.getCurrencyCode()); + } +}