task4/solution14/src/org/apidesign/apifest08/currency/Convertor.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Fri, 17 Oct 2008 17:35:52 +0200
changeset 67 bf7622ec1713
parent 61 58ec6da75f6f
permissions -rw-r--r--
Solution 14, task4
     1 package org.apidesign.apifest08.currency;
     2 
     3 import java.util.ArrayList;
     4 import java.util.Collection;
     5 import java.util.Collections;
     6 import java.util.Date;
     7 import java.util.HashSet;
     8 import java.util.List;
     9 import java.util.Set;
    10 
    11 /** This is the skeleton class for your API. You need to make it public, so
    12  * it is accessible to your client code (currently in Task1Test.java) file.
    13  * <p>
    14  * Feel free to create additional classes or rename this one, just keep all
    15  * the API and its implementation in this package. Do not spread it outside
    16  * to other packages.
    17  */
    18 public final class Convertor {
    19     //version 1 fields
    20 
    21     private String currency1 = null;
    22     private String currency2 = null;
    23     private Rate rate = null;
    24 
    25     //version 2 field
    26     private List<TimeLimitedCurrencyRate> currencyRates = null;
    27 
    28     //version - for compatible mode
    29     private int instanceVersion = 0; //compatible mode because of problem with empty currency and CZE -> CZE (1:2) rate
    30 
    31     Convertor(String currency1, String currency2, Rate rate) {
    32         instanceVersion = 1;
    33         if ((currency1 == null) || (currency2 == null) || (rate == null)) {
    34             throw new IllegalArgumentException("All arguments have to be non-null.");
    35         }
    36         this.currency1 = currency1;
    37         this.currency2 = currency2;
    38         this.rate = rate;
    39     }
    40 
    41     Convertor(final CurrencyRate ... currencyRate) {
    42         instanceVersion = 2;
    43 
    44         if (currencyRate == null) {
    45             throw new IllegalArgumentException("Parameter cannot be null.");
    46         }
    47         if (currencyRate.length == 0) {
    48             throw new IllegalArgumentException("CurrencyRates cannot be empty.");
    49         }
    50         Set<Pair<String,String>> currencies = new HashSet<Pair<String,String>>();
    51         List<TimeLimitedCurrencyRate> curRates = new ArrayList<TimeLimitedCurrencyRate>();
    52         for (int i = 0; i < currencyRate.length; i++) {
    53             final CurrencyRate curRat = currencyRate[i];
    54             if (curRat == null) {
    55                 throw new IllegalArgumentException("Parameter cannot be null.");
    56             }
    57             //check that currencyRate is not defined twice
    58             Pair<String, String> curPair= new Pair<String, String>(curRat.getCurrency1(), curRat.getCurrency2());
    59             if (currencies.contains(curPair)) {
    60                 throw new IllegalArgumentException("Pair of currencies in a currency rate cannot be defined twice");
    61             }
    62             currencies.add(curPair);
    63 
    64             if (curRat instanceof TimeLimitedCurrencyRate) {
    65                 curRates.add((TimeLimitedCurrencyRate)curRat);
    66             } else {
    67                 curRates.add(new TimeLimitedCurrencyRate() { //create delegate which implements TimeLimitedCurrencyRate
    68                     public long getFromTime() {
    69                         return Long.MIN_VALUE;
    70                     }
    71 
    72                     public long getToTime() {
    73                         return Long.MAX_VALUE;
    74                     }
    75 
    76                     public String getCurrency1() {
    77                         return curRat.getCurrency1();
    78                     }
    79 
    80                     public String getCurrency2() {
    81                         return curRat.getCurrency2();
    82                     }
    83 
    84                     public Rate getRate() {
    85                         return curRat.getRate();
    86                     }
    87                 });
    88             }
    89         }
    90         this.currencyRates = Collections.unmodifiableList(curRates);
    91     }
    92 
    93     Convertor(final int fakeParameter, final TimeLimitedCurrencyRate ... currencyRate) { //use fake parameter just to specify which constructor should be invoked
    94         instanceVersion = 3;
    95 
    96         if (currencyRate == null) {
    97             throw new IllegalArgumentException("Parameter cannot be null.");
    98         }
    99         List<TimeLimitedCurrencyRate> curRates = new ArrayList<TimeLimitedCurrencyRate>();
   100         for (int i = 0; i < currencyRate.length; i++) {
   101             final TimeLimitedCurrencyRate curRat = currencyRate[i];
   102             if (curRat == null) {
   103                 throw new IllegalArgumentException("Parameter cannot be null.");
   104             }
   105 
   106             curRates.add(curRat);
   107         }
   108         this.currencyRates = Collections.unmodifiableList(curRates);
   109     }
   110 
   111     public double convert(String fromCurrency, String toCurrency, int amount) {
   112         return convert(fromCurrency, toCurrency, amount, System.currentTimeMillis());
   113     }
   114 
   115     public double convert(String fromCurrency, String toCurrency, int amount, Date date) {
   116         if (date == null) {
   117             throw new IllegalArgumentException("Date cannot be null");
   118         }
   119         return convert(fromCurrency, toCurrency, amount, date.getTime());
   120     }
   121 
   122     public double convert(String fromCurrency, String toCurrency, int amount, long time) {
   123         if (instanceVersion == 1) {
   124             if ((fromCurrency == null) || (toCurrency == null)) {
   125                 throw new IllegalArgumentException("All arguments have to be non-null.");
   126             }
   127 
   128             if (currency1.equals(fromCurrency) && currency2.equals(toCurrency)) {
   129                 return rate.convertAtoB(amount);
   130             } else if (currency2.equals(fromCurrency) && currency1.equals(toCurrency)) {
   131                 return rate.convertBtoA(amount);
   132             } else {
   133                 throw new IllegalArgumentException("Convertor " + this.toString() +
   134                         " cannot work with currencies " + fromCurrency + " and " + toCurrency + ".");
   135             }
   136         } else { //instanceVersion >= 2
   137             //find suitable convertor
   138            for (TimeLimitedCurrencyRate curRate : currencyRates) {
   139                 if ((curRate.getCurrency1().equals(fromCurrency))&&
   140                         (curRate.getCurrency2().equals(toCurrency))&&
   141                         (curRate.getFromTime() <= time) &&
   142                         (curRate.getToTime() >= time))
   143                 {
   144                     return curRate.getRate().convertAtoB(amount);
   145                 }
   146             }
   147             //suitable convertor not found, try to find inverse convertor
   148             for (TimeLimitedCurrencyRate curRate : currencyRates) {
   149                 if ((curRate.getCurrency2().equals(fromCurrency))&&
   150                         (curRate.getCurrency1().equals(toCurrency))&&
   151                         (curRate.getFromTime() <= time) &&
   152                         (curRate.getToTime() >= time))
   153                 {
   154                     return curRate.getRate().convertBtoA(amount);
   155                 }
   156             }
   157             //even inverse convertor not found
   158             throw new IllegalArgumentException("Cannot work with selected currencies.");
   159         }
   160     }
   161 
   162     public double convert(String fromCurrency, String toCurrency, double amount) {
   163         return convert(fromCurrency, toCurrency, amount, System.currentTimeMillis());
   164     }
   165 
   166     public double convert(String fromCurrency, String toCurrency, double amount, Date date) {
   167         if (date == null) {
   168             throw new IllegalArgumentException("Date cannot be null");
   169         }
   170         return convert(fromCurrency, toCurrency, amount, date.getTime());
   171     }
   172 
   173     public double convert(String fromCurrency, String toCurrency, double amount, long time) {
   174         if (instanceVersion == 1) {
   175             if ((fromCurrency == null) || (toCurrency == null)) {
   176                 throw new IllegalArgumentException("All arguments have to be non-null.");
   177             }
   178 
   179             if (currency1.equals(fromCurrency) && currency2.equals(toCurrency)) {
   180                 return rate.convertAtoB(amount);
   181             } else if (currency2.equals(fromCurrency) && currency1.equals(toCurrency)) {
   182                 return rate.convertBtoA(amount);
   183             } else {
   184                 throw new IllegalArgumentException("Convertor " + this.toString() +
   185                         " cannot work with currencies " + fromCurrency + " and " + toCurrency + ".");
   186             }
   187         } else { //instanceVersion >= 2
   188             //find suitable convertor
   189             for (TimeLimitedCurrencyRate curRate : currencyRates) {
   190                 if ((curRate.getCurrency1().equals(fromCurrency))&&
   191                         (curRate.getCurrency2().equals(toCurrency))&&
   192                         (curRate.getFromTime() <= time) &&
   193                         (curRate.getToTime() >= time))
   194                 {
   195                     return curRate.getRate().convertAtoB(amount);
   196                 }
   197             }
   198             //suitable convertor not found, try to find inverse convertor
   199             for (TimeLimitedCurrencyRate curRate : currencyRates) {
   200                 if ((curRate.getCurrency2().equals(fromCurrency))&&
   201                         (curRate.getCurrency1().equals(toCurrency))&&
   202                         (curRate.getFromTime() <= time) &&
   203                         (curRate.getToTime() >= time))
   204                 {
   205                     return curRate.getRate().convertBtoA(amount);
   206                 }
   207             }
   208             //even inverse convertor not found
   209             throw new IllegalArgumentException("Cannot work with selected currencies.");
   210         }
   211     }
   212 
   213     /**
   214      * Returns currency rates. If instantiated with constructor from vesion 1
   215      * it creates new collection with one CurrencyRate.
   216      * Note, it can cause exception because of empty currencies or same currencies.
   217      */
   218     public Collection<CurrencyRate> getCurrencyRates() {
   219         if (instanceVersion == 1) {
   220             List<CurrencyRate> ret = new ArrayList<CurrencyRate>();
   221             ret.add(new CurrencyRateImpl(currency1, currency2, rate)); //here it checks that currency rate is not nonsense
   222             return Collections.unmodifiableCollection(ret);
   223         } else { //instanceVersion >= 2
   224             List<CurrencyRate> ret = new ArrayList<CurrencyRate>(currencyRates);
   225             return Collections.unmodifiableCollection(ret);
   226         }
   227     }
   228 
   229     public Collection<TimeLimitedCurrencyRate> getTimeLimitedCurrencyRates() {
   230         if (instanceVersion == 1) {
   231             List<TimeLimitedCurrencyRate> ret = new ArrayList<TimeLimitedCurrencyRate>();
   232             ret.add(new CurrencyRateImpl(currency1, currency2, rate)); //here it checks that currency rate is not nonsense
   233             return Collections.unmodifiableCollection(ret);
   234         } else { //instanceVersion >= 2
   235             List<TimeLimitedCurrencyRate> ret = new ArrayList<TimeLimitedCurrencyRate>(currencyRates);
   236             return Collections.unmodifiableCollection(ret);
   237         }
   238     }
   239 
   240     @Override
   241     public String toString() {
   242         if (instanceVersion == 1) {
   243             return currency1 + currency2;
   244         } else { //instanceVersion == 2
   245             return super.toString(); //better be compatible in future :-)
   246         }
   247     }
   248 
   249     @Override
   250     public boolean equals(Object obj) {
   251         if (instanceVersion == 1) {
   252             if (obj == null) {
   253                 return false;
   254             }
   255             if (getClass() != obj.getClass()) {
   256                 return false;
   257             }
   258             final Convertor other = (Convertor) obj;
   259             if (this.currency1 != other.currency1 && (this.currency1 == null || !this.currency1.equals(other.currency1))) {
   260                 return false;
   261             }
   262             if (this.currency2 != other.currency2 && (this.currency2 == null || !this.currency2.equals(other.currency2))) {
   263                 return false;
   264             }
   265             if (this.rate != other.rate && (this.rate == null || !this.rate.equals(other.rate))) {
   266                 return false;
   267             }
   268             return true;
   269         } else { //instanceVersion == 2
   270             return super.equals(obj); //better be compatible in future :-)
   271         }
   272     }
   273 
   274     @Override
   275     public int hashCode() {
   276         if (instanceVersion == 1) {
   277             int hash = 5;
   278             hash = 67 * hash + (this.currency1 != null ? this.currency1.hashCode() : 0);
   279             hash = 67 * hash + (this.currency2 != null ? this.currency2.hashCode() : 0);
   280             hash = 67 * hash + (this.rate != null ? this.rate.hashCode() : 0);
   281         return hash;
   282         } else { //instanceVersion == 2
   283             return super.hashCode(); //better be compatible in future :-)
   284         }
   285     }
   286 }