task4/solution04/src/org/apidesign/apifest08/currency/ConverterImpl.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 11 Oct 2008 23:38:46 +0200
changeset 61 58ec6da75f6f
parent 55 task3/solution04/src/org/apidesign/apifest08/currency/ConverterImpl.java@14e78f48ac2b
child 69 420baec87dc5
permissions -rw-r--r--
Copying structure for task4
japod@17
     1
package org.apidesign.apifest08.currency;
japod@17
     2
japod@17
     3
japod@17
     4
import java.math.BigDecimal;
japod@17
     5
import java.math.MathContext;
japod@17
     6
import java.math.RoundingMode;
japod@35
     7
import java.util.Collections;
japod@17
     8
import java.util.Currency;
japod@35
     9
import java.util.HashSet;
japod@35
    10
import java.util.Set;
japod@17
    11
japod@17
    12
japod@17
    13
/**
japod@17
    14
 * Convert between two currencies.
japod@17
    15
 *
japod@17
    16
 * @author D'Arcy Smith
japod@17
    17
 * @version 1.0
japod@17
    18
 */
japod@17
    19
final class ConvertorImpl
japod@17
    20
    implements Convertor
japod@17
    21
{
japod@17
    22
    /**
japod@55
    23
     * The currency to convert from.
japod@17
    24
     */
japod@17
    25
    private final Currency currencyA;
japod@17
    26
japod@17
    27
    /**
japod@55
    28
     * The currency to convert to.
japod@17
    29
     */
japod@17
    30
    private final Currency currencyB;
japod@17
    31
japod@17
    32
    /**
japod@17
    33
     * The echange rate between a and b.
japod@17
    34
     */
japod@17
    35
    private final BigDecimal currencyARate;
japod@17
    36
japod@17
    37
    /**
japod@17
    38
     * The echange rate between b and a.
japod@17
    39
     */
japod@17
    40
    private final BigDecimal currencyBRate;
japod@17
    41
    
japod@17
    42
    /**
japod@17
    43
     * Constructs a convertor with the specified currencies.
japod@17
    44
     * 
japod@17
    45
     * @param a the currency to convert from.
japod@17
    46
     * @param aRate the exchage rage between from and to.
japod@17
    47
     * @param b the currency to convert to.
japod@17
    48
     * @param bRate the exchage rage between to and from.
japod@17
    49
     * @throws IllegalArgumentException if either any of the arguments are null or if either rate <= 0.
japod@17
    50
     */
japod@17
    51
    public ConvertorImpl(final Currency   a,
japod@17
    52
                         final BigDecimal aRate,
japod@17
    53
                         final Currency   b,
japod@17
    54
                         final BigDecimal bRate)
japod@17
    55
    {
japod@17
    56
        if(a == null)
japod@17
    57
        {
japod@17
    58
            throw new IllegalArgumentException("a cannot be null");
japod@17
    59
        }
japod@17
    60
japod@17
    61
        if(b == null)
japod@17
    62
        {
japod@17
    63
            throw new IllegalArgumentException("b cannot be null");
japod@17
    64
        }
japod@17
    65
japod@17
    66
        if(aRate == null)
japod@17
    67
        {
japod@17
    68
            throw new IllegalArgumentException("aRate cannot be null");
japod@17
    69
        }
japod@17
    70
japod@17
    71
        if(bRate == null)
japod@17
    72
        {
japod@17
    73
            throw new IllegalArgumentException("bRate cannot be null");
japod@17
    74
        }
japod@17
    75
                
japod@17
    76
        if(aRate.compareTo(BigDecimal.ZERO) <= 0)
japod@17
    77
        {
japod@17
    78
            throw new IllegalArgumentException("aRate must be > 0, was: " + aRate);
japod@17
    79
        }
japod@17
    80
                
japod@17
    81
        if(bRate.compareTo(BigDecimal.ZERO) <= 0)
japod@17
    82
        {
japod@17
    83
            throw new IllegalArgumentException("bRate must be > 0, was: " + bRate);
japod@17
    84
        }
japod@17
    85
        
japod@17
    86
        currencyA     = a;
japod@17
    87
        currencyB     = b;
japod@17
    88
        currencyARate = aRate;
japod@17
    89
        currencyBRate = bRate;
japod@17
    90
    }
japod@17
    91
    
japod@17
    92
    /**
japod@17
    93
     * Convert an amount from one currency to another.
japod@17
    94
     * 
japod@17
    95
     * @param from the currency to convert from.
japod@17
    96
     * @param to the currency to convert to.
japod@17
    97
     * @param amount the amount to convert.
japod@17
    98
     * @return the converted amount.
japod@17
    99
     * @throws IllegalArgumentException if any of the arguments are null.
japod@17
   100
     * @throws InvalidConversionException if either from or to are not equal to the currencies passed to the constructor.
japod@17
   101
     */
japod@17
   102
    public BigDecimal convert(final Currency   from,
japod@17
   103
                              final Currency   to,
japod@17
   104
                              final BigDecimal amount)
japod@17
   105
        throws InvalidConversionException
japod@17
   106
    {
japod@17
   107
        final BigDecimal result;
japod@17
   108
        
japod@17
   109
        if(amount == null)
japod@17
   110
        {
japod@17
   111
            throw new IllegalArgumentException("amount cannot be null");
japod@17
   112
        }
japod@17
   113
        
japod@17
   114
        if(from == null)
japod@17
   115
        {
japod@17
   116
            throw new IllegalArgumentException("from cannot be null");
japod@17
   117
        }
japod@17
   118
        
japod@17
   119
        if(to == null)
japod@17
   120
        {
japod@17
   121
            throw new IllegalArgumentException("to cannot be null");
japod@17
   122
        }
japod@17
   123
        
japod@17
   124
        if(!(from.equals(currencyA)) && (!(from.equals(currencyB))))
japod@17
   125
        {
japod@17
   126
            throw new InvalidConversionException("cannot convert from: " + from.getCurrencyCode(), from, currencyA, currencyB);
japod@17
   127
        }
japod@17
   128
        
japod@17
   129
        if(!(to.equals(currencyA)) && (!(to.equals(currencyB))))
japod@17
   130
        {
japod@17
   131
            throw new InvalidConversionException("cannot convert to: " + to.getCurrencyCode(), to, currencyA, currencyB);
japod@17
   132
        }
japod@17
   133
japod@35
   134
        result = amount.multiply(getConversionRate(from, to));
japod@35
   135
japod@35
   136
        return (result.setScale(2, RoundingMode.HALF_DOWN));
japod@35
   137
    }
japod@35
   138
japod@35
   139
    /**
japod@35
   140
     * Check to see if converting between the two currencies is possible.
japod@35
   141
     * 
japod@35
   142
     * @param from the currency to convert from.
japod@35
   143
     * @param to the currency to convert to.
japod@35
   144
     * @return true if the conversion is possible.
japod@55
   145
     * @throws IllegalArgumentException if either from or to are null.
japod@35
   146
     */
japod@35
   147
    public boolean canConvert(final Currency from, final Currency to)
japod@35
   148
    {
japod@55
   149
        if(from == null)
japod@55
   150
        {
japod@55
   151
            throw new IllegalArgumentException("from cannot be null");
japod@55
   152
        }
japod@55
   153
        
japod@55
   154
        if(to == null)
japod@55
   155
        {
japod@55
   156
            throw new IllegalArgumentException("to cannot be null");
japod@55
   157
        }
japod@55
   158
        
japod@35
   159
        return ((from.equals(currencyA) || from.equals(currencyB)) &&
japod@35
   160
                (to.equals(currencyA)   || to.equals(currencyB)));
japod@35
   161
    }
japod@35
   162
japod@35
   163
    /**
japod@35
   164
     * Get the currencies that the convertor supports.
japod@35
   165
     * 
japod@35
   166
     * @return the supported currencies.
japod@35
   167
     */
japod@35
   168
    public Set<Currency> getCurrencies()
japod@35
   169
    {
japod@35
   170
        final Set<Currency> currencies;
japod@35
   171
        
japod@35
   172
        currencies = new HashSet<Currency>();
japod@35
   173
        currencies.add(currencyA);
japod@35
   174
        currencies.add(currencyB);
japod@35
   175
japod@35
   176
        return (Collections.unmodifiableSet(currencies));
japod@35
   177
    }
japod@35
   178
japod@35
   179
    /**
japod@35
   180
     * Get the conversion rate between two currencies.
japod@35
   181
     * 
japod@35
   182
     * @param from the currency to convert from.
japod@35
   183
     * @param to the currency to convert to.
japod@35
   184
     * @return the conversion rate between the two currencies.
japod@35
   185
     * @throws InvalidConversionException if canConvert would return false.
japod@55
   186
     * @throws IllegalArgumentException if either from or to are null.
japod@35
   187
     */
japod@35
   188
    public BigDecimal getConversionRate(final Currency from, 
japod@35
   189
                                        final Currency to)
japod@35
   190
        throws InvalidConversionException
japod@55
   191
    {                
japod@35
   192
        final BigDecimal rate;
japod@55
   193
        
japod@55
   194
        if(from == null)
japod@55
   195
        {
japod@55
   196
            throw new IllegalArgumentException("from cannot be null");
japod@55
   197
        }
japod@55
   198
        
japod@55
   199
        if(to == null)
japod@55
   200
        {
japod@55
   201
            throw new IllegalArgumentException("to cannot be null");
japod@55
   202
        }
japod@35
   203
japod@17
   204
        if(from.equals(to))
japod@17
   205
        {
japod@35
   206
            rate = BigDecimal.ONE;
japod@17
   207
        }
japod@35
   208
        else 
japod@17
   209
        {
japod@17
   210
            final BigDecimal rateX;
japod@17
   211
            final BigDecimal rateY;
japod@17
   212
            final BigDecimal temp;
japod@17
   213
            
japod@17
   214
            if(from.equals(currencyA))
japod@17
   215
            {
japod@17
   216
                rateX = currencyARate;
japod@17
   217
                rateY = currencyBRate;
japod@17
   218
            }
japod@17
   219
            else
japod@17
   220
            {
japod@17
   221
                rateX = currencyBRate;
japod@17
   222
                rateY = currencyARate;
japod@17
   223
            }
japod@17
   224
japod@35
   225
            temp = BigDecimal.ONE.divide(rateX, MathContext.DECIMAL64);
japod@35
   226
            rate = temp.multiply(rateY);
japod@35
   227
        }
japod@35
   228
        
japod@35
   229
        return (rate.setScale(20, RoundingMode.HALF_EVEN));
japod@35
   230
    }
japod@35
   231
japod@35
   232
    /**
japod@35
   233
     * Check to see if two ConvertorImpls are equal.
japod@35
   234
     *
japod@35
   235
     * @param obj the object to check
japod@35
   236
     * @return if the ConvertorImpls are not the same (cuyrrencies and rates).
japod@35
   237
     */
japod@35
   238
    @Override
japod@35
   239
    public boolean equals(Object obj)
japod@35
   240
    {
japod@35
   241
        if (obj == null)
japod@35
   242
        {
japod@35
   243
            return false;
japod@35
   244
        }
japod@35
   245
        
japod@35
   246
        if (getClass() != obj.getClass())
japod@35
   247
        {
japod@35
   248
            return false;
japod@17
   249
        }
japod@17
   250
japod@35
   251
        final ConvertorImpl other = (ConvertorImpl) obj;
japod@35
   252
japod@35
   253
        // it would be nice if NetBeans could chck to see if the variable is final and guaranteed not to be null... but that
japod@35
   254
        // would likely be tricky... but in a NetBeans engineer reads that see if you can do it :-)
japod@35
   255
        if (this.currencyA != other.currencyA && (this.currencyA == null || !this.currencyA.equals(other.currencyA)))
japod@35
   256
        {
japod@35
   257
            return false;
japod@35
   258
        }
japod@35
   259
        
japod@35
   260
        if (this.currencyB != other.currencyB && (this.currencyB == null || !this.currencyB.equals(other.currencyB)))
japod@35
   261
        {
japod@35
   262
            return false;
japod@35
   263
        }
japod@35
   264
        
japod@35
   265
        if (this.currencyARate != other.currencyARate && (this.currencyARate == null || !this.currencyARate.equals(other.currencyARate)))
japod@35
   266
        {
japod@35
   267
            return false;
japod@35
   268
        }
japod@35
   269
        
japod@35
   270
        if (this.currencyBRate != other.currencyBRate && (this.currencyBRate == null || !this.currencyBRate.equals(other.currencyBRate)))
japod@35
   271
        {
japod@35
   272
            return false;
japod@35
   273
        }
japod@35
   274
japod@35
   275
        return true;
japod@35
   276
    }
japod@35
   277
japod@35
   278
    /**
japod@35
   279
     * Get the hashCode of the Convertor.
japod@35
   280
     *
japod@35
   281
     * @return the hashCode of the convertor.
japod@35
   282
     */
japod@35
   283
    @Override
japod@35
   284
    public int hashCode()
japod@35
   285
    {
japod@35
   286
        int hash = 7;
japod@35
   287
        hash = 37 * hash + (this.currencyA != null ? this.currencyA.hashCode() : 0);
japod@35
   288
        hash = 37 * hash + (this.currencyB != null ? this.currencyB.hashCode() : 0);
japod@35
   289
        hash = 37 * hash + (this.currencyARate != null ? this.currencyARate.hashCode() : 0);
japod@35
   290
        hash = 37 * hash + (this.currencyBRate != null ? this.currencyBRate.hashCode() : 0);
japod@35
   291
        return hash;
japod@35
   292
    }
japod@35
   293
japod@35
   294
    /**
japod@35
   295
     * Get the currencyCode of both currencies.
japod@35
   296
     *
japod@35
   297
     * @return the currency codes of both currencies.
japod@35
   298
     */
japod@35
   299
    @Override
japod@35
   300
    public String toString()
japod@35
   301
    {
japod@35
   302
        return (currencyA.getCurrencyCode() + " to " + currencyB.getCurrencyCode());
japod@17
   303
    }
japod@17
   304
}