task4/solution11/src/org/apidesign/apifest08/currency/Convertor.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 11 Oct 2008 23:38:46 +0200
changeset 61 58ec6da75f6f
parent 53 task3/solution11/src/org/apidesign/apifest08/currency/Convertor.java@09d690bb97f6
child 66 aa3f99f845ef
permissions -rw-r--r--
Copying structure for task4
     1 package org.apidesign.apifest08.currency;
     2 
     3 import java.util.ArrayList;
     4 import java.util.Collection;
     5 import java.util.HashSet;
     6 import java.util.List;
     7 import java.util.Set;
     8 import org.apidesign.apifest08.currency.Computer.ComputerRequest;
     9 import org.apidesign.apifest08.currency.Computer.ComputerResponse;
    10 
    11 /**
    12  * Convertor.
    13  * 
    14  * In Task 1's version provides conversion between currency values
    15  * with amount stored in integer or double, that are identified
    16  * with string value. Exchange rates are immutable.
    17  * 
    18  * In Task2's version provides support for multiple exchange rates
    19  * between different currencies & merging exchange rates from
    20  * existing convertors into new convertor's instance.
    21  * No time for javadoc these features, sorry.
    22  * 
    23  * In Task3's version supports reading of current exchange rates
    24  * from data sources. Data sources are merged during convertors' merging
    25  * as well as static exchange rates.
    26  * No time for javadoc, again.
    27  * 
    28  * @author ked
    29  */
    30 public final class Convertor<AmountType, IdentifierType> {
    31 
    32     Computer<AmountType> computer;
    33     // each static exchange rate could be a special case of an exchange rate data source
    34     List<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates = new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
    35     List<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources = new ArrayList<ExchangeRateDataSource<AmountType, IdentifierType>>();
    36 
    37     Convertor(Computer<AmountType> computer) {
    38         this.computer = computer;
    39     }
    40     
    41     void addExchangeRates(Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
    42         for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
    43             if (isExchangeRate(
    44                     exchangeRate.getCurrencyA().getIdentifier(),
    45                     exchangeRate.getCurrencyB().getIdentifier())) {
    46                 throw new IllegalArgumentException("Duplicate exchange rate!");
    47             }
    48             this.exchangeRates.add(exchangeRate);
    49         }
    50     }
    51     
    52     void addExchangeRateDataSources(Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources) {
    53         for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : exchangeRateDataSources) {
    54             if (isExchangeRate(
    55                     exchangeRateDataSource.getCurrencyAIdentifier(),
    56                     exchangeRateDataSource.getCurrencyBIdentifier())) {
    57                 throw new IllegalArgumentException("Duplicate exchange rate!");
    58             }
    59             this.exchangeRateDataSources.add(exchangeRateDataSource);
    60         }
    61     }
    62     
    63     ExchangeRateValue<AmountType, IdentifierType> findExchangeRate(
    64             IdentifierType currencyA,
    65             IdentifierType currencyB) {
    66         for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
    67             if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) ||
    68                     (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) {
    69                 return exchangeRate;
    70             }
    71         }
    72         for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : exchangeRateDataSources) {
    73             if ((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) ||
    74                     (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) {
    75                 return exchangeRateDataSource.getExchangeRate();
    76             }
    77         }
    78         return null;
    79     }
    80     
    81     boolean isExchangeRate(
    82             IdentifierType currencyA,
    83             IdentifierType currencyB) {
    84         for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
    85             if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) ||
    86                     (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) {
    87                 return true;
    88             }
    89         }
    90         for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : exchangeRateDataSources) {
    91             if ((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) ||
    92                     (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) {
    93                 return true;
    94             }
    95         }
    96         return false;
    97     }
    98 
    99     /**
   100      * Convert an amount of the one currency to an amount of the another one currency
   101      * with respect to previously specified exchange rates.
   102      * 
   103      * @param targetCurrency an identifier of the requested currency
   104      * @param currencyValue an amount of the another one currency
   105      * @return an amount of the requested currency
   106      */
   107     public CurrencyValue<AmountType, IdentifierType> convert(
   108             IdentifierType targetCurrency,
   109             CurrencyValue<AmountType, IdentifierType> currencyValue) {
   110         ExchangeRateValue<AmountType, IdentifierType> exchangeRate =
   111                 findExchangeRate(currencyValue.getIdentifier(), targetCurrency);
   112         if (exchangeRate == null) {
   113             throw new IllegalArgumentException("Inappropriate currencies to convert!");
   114         }
   115 
   116         ComputerRequest<AmountType> computerRequest = new ComputerRequest<AmountType>();
   117         computerRequest.setInput(currencyValue.getAmount());
   118 
   119         IdentifierType targetCurrencyRef; // just for backward compatibility :-(
   120         if (exchangeRate.getCurrencyA().getIdentifier().equals(targetCurrency)) {
   121             computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
   122             computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
   123             targetCurrencyRef = exchangeRate.getCurrencyA().getIdentifier();
   124         } else {
   125             computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
   126             computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
   127             targetCurrencyRef = exchangeRate.getCurrencyB().getIdentifier();
   128         }
   129 
   130         ComputerResponse<AmountType> computerResponse = new ComputerResponse<AmountType>();
   131         computer.compute(computerRequest, computerResponse);
   132 
   133         return CurrencyValue.getCurrencyValue(
   134                 computerResponse.getResult(),
   135                 targetCurrencyRef);
   136     }
   137 
   138     // ---
   139     // MERGING
   140     // ---
   141     static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
   142             Computer<AmountType> computer,
   143             Collection<Convertor<AmountType, IdentifierType>> convertors) {
   144         Set<ExchangeRateValue<AmountType, IdentifierType>> exchangeRatesSet = new HashSet<ExchangeRateValue<AmountType, IdentifierType>>();
   145         Set<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSourcesSet = new HashSet<ExchangeRateDataSource<AmountType, IdentifierType>>();
   146         for (Convertor<AmountType, IdentifierType> convertor : convertors) {
   147             exchangeRatesSet.addAll(convertor.exchangeRates);
   148         }
   149         for (Convertor<AmountType, IdentifierType> convertor : convertors) {
   150             exchangeRateDataSourcesSet.addAll(convertor.exchangeRateDataSources);
   151         }
   152         
   153         Convertor<AmountType, IdentifierType> c = new Convertor<AmountType, IdentifierType>(computer);
   154         c.addExchangeRates(exchangeRatesSet);
   155         c.addExchangeRateDataSources(exchangeRateDataSourcesSet);
   156         return c;
   157     }
   158 
   159     static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
   160             Computer<AmountType> computer,
   161             Convertor<AmountType, IdentifierType> convertorA,
   162             Convertor<AmountType, IdentifierType> convertorB) {
   163         Collection<Convertor<AmountType, IdentifierType>> convertors =
   164                 new ArrayList<Convertor<AmountType, IdentifierType>>();
   165         convertors.add(convertorA);
   166         convertors.add(convertorB);
   167         return mergeConvertors(computer, convertors);
   168     }
   169 
   170     public static Convertor<Double, String> mergeConvertorsDoubleString(
   171             Collection<Convertor<Double, String>> convertors) {
   172         return mergeConvertors(DoubleComputer, convertors);
   173     }
   174 
   175     public static Convertor<Double, String> mergeConvertorsDoubleString(
   176             Convertor<Double, String> convertorA,
   177             Convertor<Double, String> convertorB) {
   178         return mergeConvertors(DoubleComputer, convertorA, convertorB);
   179     }
   180 
   181     public static Convertor<Integer, String> mergeConvertorsIntegerString(
   182             Collection<Convertor<Integer, String>> convertors) {
   183         return mergeConvertors(IntegerComputer, convertors);
   184     }
   185 
   186     public static Convertor<Integer, String> mergeConvertorsIntegerString(
   187             Convertor<Integer, String> convertorA,
   188             Convertor<Integer, String> convertorB) {
   189         return mergeConvertors(IntegerComputer, convertorA, convertorB);
   190     }
   191 
   192     // ---
   193     // CREATION
   194     // ---
   195     static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
   196             Computer<AmountType> computer, Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
   197         Convertor<AmountType, IdentifierType> c = new Convertor<AmountType, IdentifierType>(computer);
   198         c.addExchangeRates(exchangeRates);
   199         return c;
   200     }
   201 
   202     static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertorDataSource(
   203             Computer<AmountType> computer, Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources) {
   204         Convertor<AmountType, IdentifierType> c = new Convertor<AmountType, IdentifierType>(computer);
   205         c.addExchangeRateDataSources(exchangeRateDataSources);
   206         return c;
   207     }
   208     
   209     static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
   210             Computer<AmountType> computer, ExchangeRateValue<AmountType, IdentifierType> exchangeRate) {
   211         Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates =
   212                 new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
   213         exchangeRates.add(exchangeRate);
   214         return getConvertor(computer, exchangeRates);
   215     }
   216     
   217     static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertorDataSource(
   218             Computer<AmountType> computer, ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource) {
   219         Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources =
   220                 new ArrayList<ExchangeRateDataSource<AmountType, IdentifierType>>();
   221         exchangeRateDataSources.add(exchangeRateDataSource);
   222         return getConvertorDataSource(computer, exchangeRateDataSources);
   223     }
   224     
   225     public static Convertor<Double, String> getConvertorDoubleString(
   226             Collection<ExchangeRateValue<Double, String>> exchangeRates) {
   227         return getConvertor(DoubleComputer, exchangeRates);
   228     }
   229 
   230     public static Convertor<Double, String> getConvertorDoubleString(
   231             ExchangeRateValue<Double, String> exchangeRate) {
   232         return getConvertor(DoubleComputer, exchangeRate);
   233     }
   234     
   235     public static Convertor<Double, String> getConvertorDataSourceDoubleString(
   236             Collection<ExchangeRateDataSource<Double, String>> exchangeRateDataSources) {
   237         return getConvertorDataSource(DoubleComputer, exchangeRateDataSources);
   238     }
   239 
   240     public static Convertor<Double, String> getConvertorDataSourceDoubleString(
   241             ExchangeRateDataSource<Double, String> exchangeRateDataSource) {
   242         return getConvertorDataSource(DoubleComputer, exchangeRateDataSource);
   243     }
   244     
   245     public static Convertor<Integer, String> getConvertorIntegerString(
   246             Collection<ExchangeRateValue<Integer, String>> exchangeRates) {
   247         return getConvertor(IntegerComputer, exchangeRates);
   248     }
   249 
   250     public static Convertor<Integer, String> getConvertorIntegerString(
   251             ExchangeRateValue<Integer, String> exchangeRate) {
   252         return getConvertor(IntegerComputer, exchangeRate);
   253     }
   254     
   255     public static Convertor<Integer, String> getConvertorDataSourceIntegerString(
   256             Collection<ExchangeRateDataSource<Integer, String>> exchangeRateDataSources) {
   257         return getConvertorDataSource(IntegerComputer, exchangeRateDataSources);
   258     }
   259 
   260     public static Convertor<Integer, String> getConvertorDataSourceIntegerString(
   261             ExchangeRateDataSource<Integer, String> exchangeRateDataSource) {
   262         return getConvertorDataSource(IntegerComputer, exchangeRateDataSource);
   263     }
   264 
   265     // ---
   266     // BACKWARD COMPATIBILITY - CREATION
   267     // ---
   268     /**
   269      * Creates convertor for Double|String values with specified exchange rate
   270      * between two currencies.
   271      * 
   272      * @param firstCurrencyExchangeRate first currency
   273      * @param secondCurrencyExchangeRate second currency
   274      * @return convertor
   275      */
   276     public static Convertor<Double, String> getConvertorDoubleString(
   277             CurrencyValue<Double, String> firstCurrencyExchangeRate,
   278             CurrencyValue<Double, String> secondCurrencyExchangeRate) {
   279         return getConvertorDoubleString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
   280     }
   281 
   282     /**
   283      * Creates convertor for Integer|String values with specified exchange rate
   284      * between two currencies.
   285      * 
   286      * @param firstCurrencyExchangeRate first currency
   287      * @param secondCurrencyExchangeRate second currency
   288      * @return convertor
   289      */
   290     public static Convertor<Integer, String> getConvertorIntegerString(
   291             CurrencyValue<Integer, String> firstCurrencyExchangeRate,
   292             CurrencyValue<Integer, String> secondCurrencyExchangeRate) {
   293         return getConvertorIntegerString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
   294     }
   295     
   296     // ---
   297     // COMPUTERS
   298     // ---
   299     static final Computer<Double> DoubleComputer = new Computer<Double>() {
   300 
   301         public void compute(ComputerRequest<Double> request, ComputerResponse<Double> response) {
   302             response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());
   303         }
   304     };
   305     static final Computer<Integer> IntegerComputer = new Computer<Integer>() {
   306 
   307         public void compute(ComputerRequest<Integer> request, ComputerResponse<Integer> response) {
   308             response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());
   309         }
   310     };
   311 }