task4/solution04/src/org/apidesign/apifest08/currency/ExchangeRate.java
author Jaroslav Tulach <jtulach@netbeans.org>
Sat, 25 Oct 2008 20:53:00 +0200
changeset 84 2ae6e4aa7aef
parent 61 58ec6da75f6f
permissions -rw-r--r--
Solutions by Petr Smid
japod@55
     1
package org.apidesign.apifest08.currency;
japod@55
     2
japod@55
     3
japod@55
     4
import java.math.BigDecimal;
jaroslav@69
     5
import java.math.RoundingMode;
jaroslav@69
     6
import java.util.Collections;
japod@55
     7
import java.util.Currency;
jaroslav@69
     8
import java.util.HashSet;
jaroslav@69
     9
import java.util.Set;
japod@55
    10
japod@55
    11
japod@55
    12
/**
japod@55
    13
 * The exchange rate between two currencies.
japod@55
    14
 *
japod@55
    15
 * @author D'Arcy Smith
jaroslav@69
    16
 * @version 1.1
japod@55
    17
 */
japod@55
    18
public final class ExchangeRate
japod@55
    19
{
japod@55
    20
    /**
japod@55
    21
     * 
japod@55
    22
     */
japod@55
    23
    private final Currency currencyA;
japod@55
    24
japod@55
    25
    /**
japod@55
    26
     * 
japod@55
    27
     */
japod@55
    28
    private final Currency currencyB;
japod@55
    29
japod@55
    30
    /**
japod@55
    31
     * 
japod@55
    32
     */
japod@55
    33
    private final BigDecimal rateAtoB;
japod@55
    34
japod@55
    35
    /**
japod@55
    36
     * 
japod@55
    37
     */
japod@55
    38
    private final BigDecimal rateBtoA;
japod@55
    39
japod@55
    40
    /**
japod@55
    41
     * Construct an ExchangeRate with the specified values.
japod@55
    42
     * 
japod@55
    43
     * @param a the first currency
japod@55
    44
     * @param b the second currency
japod@55
    45
     * @param ra the rate to convert a to b
japod@55
    46
     * @param rb the rate to covertt b to a
japod@55
    47
     * @throws IllegalArgumentException if any parameter is null.
japod@55
    48
     */
japod@55
    49
    public ExchangeRate(final Currency   a,
japod@55
    50
                        final Currency   b,
japod@55
    51
                        final BigDecimal ra,
japod@55
    52
                        final BigDecimal rb)
japod@55
    53
    {
japod@55
    54
        if(a == null)
japod@55
    55
        {
japod@55
    56
            throw new IllegalArgumentException("a cannot be null");
japod@55
    57
        }
japod@55
    58
        
japod@55
    59
        if(b == null)
japod@55
    60
        {
japod@55
    61
            throw new IllegalArgumentException("b cannot be null");
japod@55
    62
        }
japod@55
    63
        
japod@55
    64
        if(ra == null)
japod@55
    65
        {
japod@55
    66
            throw new IllegalArgumentException("ra cannot be null");
japod@55
    67
        }
japod@55
    68
        
japod@55
    69
        if(rb == null)
japod@55
    70
        {
japod@55
    71
            throw new IllegalArgumentException("rb cannot be null");
japod@55
    72
        }
japod@55
    73
        
japod@55
    74
        if(ra.compareTo(BigDecimal.ZERO) <= 0)
japod@55
    75
        {
japod@55
    76
            throw new IllegalArgumentException("ra cannot be <= 0, was: " + ra);
japod@55
    77
        }
japod@55
    78
        
japod@55
    79
        if(rb.compareTo(BigDecimal.ZERO) <= 0)
japod@55
    80
        {
japod@55
    81
            throw new IllegalArgumentException("rb cannot be <= 0, was: " + ra);
japod@55
    82
        }
japod@55
    83
        
japod@55
    84
        currencyA = a;
japod@55
    85
        currencyB = b;
japod@55
    86
        rateAtoB  = ra;
japod@55
    87
        rateBtoA  = rb;
japod@55
    88
    }
japod@55
    89
japod@55
    90
    /**
japod@55
    91
     * Get the first currency.
japod@55
    92
     * 
japod@55
    93
     * @return the first currency.
japod@55
    94
     */
japod@55
    95
    public Currency getCurrencyA()
japod@55
    96
    {
japod@55
    97
        return currencyA;
japod@55
    98
    }
japod@55
    99
japod@55
   100
    /**
japod@55
   101
     * Get the second currency.
japod@55
   102
     * 
japod@55
   103
     * @return the second currency.
japod@55
   104
     */
japod@55
   105
    public Currency getCurrencyB()
japod@55
   106
    {
japod@55
   107
        return currencyB;
japod@55
   108
    }
japod@55
   109
japod@55
   110
    /**
japod@55
   111
     * Get the conversion rate from currencyA to currencyB.
japod@55
   112
     * 
japod@55
   113
     * @return the conversion rate from currencyA to currencyB.
japod@55
   114
     */
japod@55
   115
    public BigDecimal getRateAtoB()
japod@55
   116
    {
japod@55
   117
        return rateAtoB;
japod@55
   118
    }
japod@55
   119
japod@55
   120
    /**
japod@55
   121
     * Get the conversion rate from currencyB to currencyA.
japod@55
   122
     * 
japod@55
   123
     * @return the conversion rate from currencyB to currencyA.
japod@55
   124
     */
japod@55
   125
    public BigDecimal getRateBtoA()
japod@55
   126
    {
japod@55
   127
        return rateBtoA;
japod@55
   128
    }
jaroslav@69
   129
    
jaroslav@69
   130
    public static ExchangeRate getExchangeRate(final Currency   a,
jaroslav@69
   131
                                               final Currency   b,
jaroslav@69
   132
                                               final BigDecimal va,
jaroslav@69
   133
                                               final BigDecimal vb)
jaroslav@69
   134
    {
jaroslav@69
   135
        final BigDecimal   rateAtoB;
jaroslav@69
   136
        final BigDecimal   rateBtoA;
jaroslav@69
   137
        final ExchangeRate rate;    
jaroslav@69
   138
        
jaroslav@69
   139
        if(a == null)
jaroslav@69
   140
        {
jaroslav@69
   141
            throw new IllegalArgumentException("a cannot be null");
jaroslav@69
   142
        }
jaroslav@69
   143
        
jaroslav@69
   144
        if(b == null)
jaroslav@69
   145
        {
jaroslav@69
   146
            throw new IllegalArgumentException("b cannot be null");
jaroslav@69
   147
        }
jaroslav@69
   148
jaroslav@69
   149
        if(a.equals(b))
jaroslav@69
   150
        {
jaroslav@69
   151
            rateAtoB = BigDecimal.ONE;
jaroslav@69
   152
            rateBtoA = BigDecimal.ONE;
jaroslav@69
   153
        }
jaroslav@69
   154
        else 
jaroslav@69
   155
        {
jaroslav@69
   156
            rateAtoB = vb.divide(va, 20, RoundingMode.HALF_DOWN);
jaroslav@69
   157
            rateBtoA = va.divide(vb, 20, RoundingMode.HALF_DOWN);
jaroslav@69
   158
        }
jaroslav@69
   159
        
jaroslav@69
   160
        rate = new ExchangeRate(a, 
jaroslav@69
   161
                                b,
jaroslav@69
   162
                                rateAtoB.setScale(20, RoundingMode.HALF_EVEN),
jaroslav@69
   163
                                rateBtoA.setScale(20, RoundingMode.HALF_EVEN));
jaroslav@69
   164
        
jaroslav@69
   165
        return (rate);
jaroslav@69
   166
    }
jaroslav@69
   167
jaroslav@69
   168
    public BigDecimal convert(final Currency   from,
jaroslav@69
   169
                              final Currency   to,
jaroslav@69
   170
                              final BigDecimal amount)
jaroslav@69
   171
        throws InvalidConversionException
jaroslav@69
   172
    {
jaroslav@69
   173
        final BigDecimal result;
jaroslav@69
   174
        
jaroslav@69
   175
        if(amount == null)
jaroslav@69
   176
        {
jaroslav@69
   177
            throw new IllegalArgumentException("amount cannot be null");
jaroslav@69
   178
        }
jaroslav@69
   179
        
jaroslav@69
   180
        if(from == null)
jaroslav@69
   181
        {
jaroslav@69
   182
            throw new IllegalArgumentException("from cannot be null");
jaroslav@69
   183
        }
jaroslav@69
   184
        
jaroslav@69
   185
        if(to == null)
jaroslav@69
   186
        {
jaroslav@69
   187
            throw new IllegalArgumentException("to cannot be null");
jaroslav@69
   188
        }
jaroslav@69
   189
        
jaroslav@69
   190
        if(!(from.equals(currencyA)) && (!(from.equals(currencyB))))
jaroslav@69
   191
        {
jaroslav@69
   192
            throw new InvalidConversionException("cannot convert from: " + from.getCurrencyCode(), from, currencyA, currencyB);
jaroslav@69
   193
        }
jaroslav@69
   194
        
jaroslav@69
   195
        if(!(to.equals(currencyA)) && (!(to.equals(currencyB))))
jaroslav@69
   196
        {
jaroslav@69
   197
            throw new InvalidConversionException("cannot convert to: " + to.getCurrencyCode(), to, currencyA, currencyB);
jaroslav@69
   198
        }
jaroslav@69
   199
jaroslav@69
   200
        result = amount.multiply(getConversionRate(from, to));
jaroslav@69
   201
jaroslav@69
   202
        return (result.setScale(2, RoundingMode.HALF_DOWN));
jaroslav@69
   203
    }
jaroslav@69
   204
    
jaroslav@69
   205
    /**
jaroslav@69
   206
     * Check to see if converting between the two currencies is possible.
jaroslav@69
   207
     * 
jaroslav@69
   208
     * @param from the currency to convert from.
jaroslav@69
   209
     * @param to the currency to convert to.
jaroslav@69
   210
     * @return true if the conversion is possible.
jaroslav@69
   211
     * @throws IllegalArgumentException if either from or to are null.
jaroslav@69
   212
     */
jaroslav@69
   213
    public boolean canConvert(final Currency from, final Currency to)
jaroslav@69
   214
    {
jaroslav@69
   215
        if(from == null)
jaroslav@69
   216
        {
jaroslav@69
   217
            throw new IllegalArgumentException("from cannot be null");
jaroslav@69
   218
        }
jaroslav@69
   219
        
jaroslav@69
   220
        if(to == null)
jaroslav@69
   221
        {
jaroslav@69
   222
            throw new IllegalArgumentException("to cannot be null");
jaroslav@69
   223
        }
jaroslav@69
   224
        
jaroslav@69
   225
        return ((from.equals(currencyA) || from.equals(currencyB)) &&
jaroslav@69
   226
                (to.equals(currencyA)   || to.equals(currencyB)));
jaroslav@69
   227
    }
jaroslav@69
   228
    /**
jaroslav@69
   229
     * Get the currencies that the convertor supports.
jaroslav@69
   230
     * 
jaroslav@69
   231
     * @return the supported currencies.
jaroslav@69
   232
     */
jaroslav@69
   233
    public Set<Currency> getCurrencies()
jaroslav@69
   234
    {
jaroslav@69
   235
        final Set<Currency> currencies;
jaroslav@69
   236
        
jaroslav@69
   237
        currencies = new HashSet<Currency>();
jaroslav@69
   238
        currencies.add(currencyA);
jaroslav@69
   239
        currencies.add(currencyB);
jaroslav@69
   240
jaroslav@69
   241
        return (Collections.unmodifiableSet(currencies));
jaroslav@69
   242
    }
jaroslav@69
   243
jaroslav@69
   244
    /**
jaroslav@69
   245
     * Get the conversion rate between two currencies.
jaroslav@69
   246
     * 
jaroslav@69
   247
     * @param from the currency to convert from.
jaroslav@69
   248
     * @param to the currency to convert to.
jaroslav@69
   249
     * @return the conversion rate between the two currencies.
jaroslav@69
   250
     * @throws InvalidConversionException if canConvert would return false.
jaroslav@69
   251
     * @throws IllegalArgumentException if either from or to are null.
jaroslav@69
   252
     */
jaroslav@69
   253
    public BigDecimal getConversionRate(final Currency from, 
jaroslav@69
   254
                                        final Currency to)
jaroslav@69
   255
        throws InvalidConversionException
jaroslav@69
   256
    {                
jaroslav@69
   257
        final BigDecimal rate;
jaroslav@69
   258
        
jaroslav@69
   259
        if(from == null)
jaroslav@69
   260
        {
jaroslav@69
   261
            throw new IllegalArgumentException("from cannot be null");
jaroslav@69
   262
        }
jaroslav@69
   263
        
jaroslav@69
   264
        if(to == null)
jaroslav@69
   265
        {
jaroslav@69
   266
            throw new IllegalArgumentException("to cannot be null");
jaroslav@69
   267
        }
jaroslav@69
   268
jaroslav@69
   269
        if(from.equals(to))
jaroslav@69
   270
        {
jaroslav@69
   271
            rate = BigDecimal.ONE;
jaroslav@69
   272
        }
jaroslav@69
   273
        else 
jaroslav@69
   274
        {
jaroslav@69
   275
            if(from.equals(currencyA))
jaroslav@69
   276
            {
jaroslav@69
   277
                rate = rateAtoB;
jaroslav@69
   278
            }
jaroslav@69
   279
            else
jaroslav@69
   280
            {
jaroslav@69
   281
                rate = rateBtoA;
jaroslav@69
   282
            }
jaroslav@69
   283
        }
jaroslav@69
   284
        
jaroslav@69
   285
        return (rate);
jaroslav@69
   286
    }
jaroslav@69
   287
jaroslav@69
   288
    public String toString()
jaroslav@69
   289
    {
jaroslav@69
   290
        return (rateAtoB + " : " + rateBtoA);
jaroslav@69
   291
    }
jaroslav@69
   292
jaroslav@69
   293
    @Override
jaroslav@69
   294
    public boolean equals(Object obj) {
jaroslav@69
   295
        if (obj == null) {
jaroslav@69
   296
            return false;
jaroslav@69
   297
        }
jaroslav@69
   298
        if (getClass() != obj.getClass()) {
jaroslav@69
   299
            return false;
jaroslav@69
   300
        }
jaroslav@69
   301
        final ExchangeRate other = (ExchangeRate) obj;
jaroslav@69
   302
        if (this.currencyA != other.currencyA && (this.currencyA == null || !this.currencyA.equals(other.currencyA))) {
jaroslav@69
   303
            return false;
jaroslav@69
   304
        }
jaroslav@69
   305
        if (this.currencyB != other.currencyB && (this.currencyB == null || !this.currencyB.equals(other.currencyB))) {
jaroslav@69
   306
            return false;
jaroslav@69
   307
        }
jaroslav@69
   308
        if (this.rateAtoB != other.rateAtoB && (this.rateAtoB == null || !this.rateAtoB.equals(other.rateAtoB))) {
jaroslav@69
   309
            return false;
jaroslav@69
   310
        }
jaroslav@69
   311
        if (this.rateBtoA != other.rateBtoA && (this.rateBtoA == null || !this.rateBtoA.equals(other.rateBtoA))) {
jaroslav@69
   312
            return false;
jaroslav@69
   313
        }
jaroslav@69
   314
        return true;
jaroslav@69
   315
    }
jaroslav@69
   316
jaroslav@69
   317
    @Override
jaroslav@69
   318
    public int hashCode() {
jaroslav@69
   319
        int hash = 7;
jaroslav@69
   320
        hash = 97 * hash + (this.currencyA != null ? this.currencyA.hashCode() : 0);
jaroslav@69
   321
        hash = 97 * hash + (this.currencyB != null ? this.currencyB.hashCode() : 0);
jaroslav@69
   322
        hash = 97 * hash + (this.rateAtoB != null ? this.rateAtoB.hashCode() : 0);
jaroslav@69
   323
        hash = 97 * hash + (this.rateBtoA != null ? this.rateBtoA.hashCode() : 0);
jaroslav@69
   324
        return hash;
jaroslav@69
   325
    }
japod@55
   326
}