task2/solution11/src/org/apidesign/apifest08/currency/Convertor.java
author japod@localhost
Tue, 07 Oct 2008 00:25:53 +0200
changeset 37 d333e45f6df1
parent 29 f6073056b9fe
permissions -rw-r--r--
adding solution11 for task 2
     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  * @author ked
    24  */
    25 public final class Convertor<AmountType, IdentifierType> {
    26 
    27     Computer<AmountType> computer;
    28     List<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates = new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
    29 
    30     Convertor(
    31             Computer<AmountType> computer,
    32             Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
    33         this.computer = computer;
    34 
    35         for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
    36             if (findExchangeRate(
    37                     this.exchangeRates,
    38                     exchangeRate.getCurrencyA().getIdentifier(),
    39                     exchangeRate.getCurrencyB().getIdentifier()) != null) {
    40                 throw new IllegalArgumentException("Duplicate exchange rate!");
    41             }
    42             this.exchangeRates.add(exchangeRate);
    43         }
    44     }
    45 
    46     private ExchangeRateValue<AmountType, IdentifierType> findExchangeRate(
    47             Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates,
    48             IdentifierType currencyA,
    49             IdentifierType currencyB) {
    50         for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
    51             if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) ||
    52                     (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) {
    53                 return exchangeRate;
    54             }
    55         }
    56         return null;
    57     }
    58 
    59     /**
    60      * Convert an amount of the one currency to an amount of the another one currency
    61      * with respect to previously specified exchange rates.
    62      * 
    63      * @param targetCurrency an identifier of the requested currency
    64      * @param currencyValue an amount of the another one currency
    65      * @return an amount of the requested currency
    66      */
    67     public CurrencyValue<AmountType, IdentifierType> convert(
    68             IdentifierType targetCurrency,
    69             CurrencyValue<AmountType, IdentifierType> currencyValue) {
    70         ExchangeRateValue<AmountType, IdentifierType> exchangeRate =
    71                 findExchangeRate(exchangeRates, currencyValue.getIdentifier(), targetCurrency);
    72         if (exchangeRate == null) {
    73             throw new IllegalArgumentException("Inappropriate currencies to convert!");
    74         }
    75 
    76         ComputerRequest<AmountType> computerRequest = new ComputerRequest<AmountType>();
    77         computerRequest.setInput(currencyValue.getAmount());
    78 
    79         IdentifierType targetCurrencyRef; // just for backward compatibility :-(
    80         if (exchangeRate.getCurrencyA().getIdentifier().equals(targetCurrency)) {
    81             computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
    82             computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
    83             targetCurrencyRef = exchangeRate.getCurrencyA().getIdentifier();
    84         } else {
    85             computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
    86             computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
    87             targetCurrencyRef = exchangeRate.getCurrencyB().getIdentifier();
    88         }
    89 
    90         ComputerResponse<AmountType> computerResponse = computer.compute(computerRequest);
    91         return CurrencyValue.getCurrencyValue(
    92                 computerResponse.getResult(),
    93                 targetCurrencyRef);
    94     }
    95 
    96     // ---
    97     // MERGING
    98     // ---
    99     static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
   100             Computer<AmountType> computer,
   101             Collection<Convertor<AmountType, IdentifierType>> convertors) {
   102         Set<ExchangeRateValue<AmountType, IdentifierType>> exchangeRatesSet = new HashSet<ExchangeRateValue<AmountType, IdentifierType>>();
   103         for (Convertor<AmountType, IdentifierType> convertor : convertors) {
   104             exchangeRatesSet.addAll(convertor.exchangeRates);
   105         }
   106         return getConvertor(computer, exchangeRatesSet);
   107     }
   108 
   109     static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
   110             Computer<AmountType> computer,
   111             Convertor<AmountType, IdentifierType> convertorA,
   112             Convertor<AmountType, IdentifierType> convertorB) {
   113         Collection<Convertor<AmountType, IdentifierType>> convertors =
   114                 new ArrayList<Convertor<AmountType, IdentifierType>>();
   115         convertors.add(convertorA);
   116         convertors.add(convertorB);
   117         return mergeConvertors(computer, convertors);
   118     }
   119 
   120     public static Convertor<Double, String> mergeConvertorsDoubleString(
   121             Collection<Convertor<Double, String>> convertors) {
   122         return mergeConvertors(DoubleComputer, convertors);
   123     }
   124 
   125     public static Convertor<Double, String> mergeConvertorsDoubleString(
   126             Convertor<Double, String> convertorA,
   127             Convertor<Double, String> convertorB) {
   128         return mergeConvertors(DoubleComputer, convertorA, convertorB);
   129     }
   130 
   131     public static Convertor<Integer, String> mergeConvertorsIntegerString(
   132             Collection<Convertor<Integer, String>> convertors) {
   133         return mergeConvertors(IntegerComputer, convertors);
   134     }
   135 
   136     public static Convertor<Integer, String> mergeConvertorsIntegerString(
   137             Convertor<Integer, String> convertorA,
   138             Convertor<Integer, String> convertorB) {
   139         return mergeConvertors(IntegerComputer, convertorA, convertorB);
   140     }
   141 
   142     // ---
   143     // CREATION
   144     // ---
   145     static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
   146             Computer<AmountType> computer, Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
   147         return new Convertor<AmountType, IdentifierType>(computer, exchangeRates);
   148     }
   149 
   150     static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
   151             Computer<AmountType> computer, ExchangeRateValue<AmountType, IdentifierType> exchangeRate) {
   152         Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates =
   153                 new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
   154         exchangeRates.add(exchangeRate);
   155         return getConvertor(computer, exchangeRates);
   156     }
   157     
   158     public static Convertor<Double, String> getConvertorDoubleString(
   159             Collection<ExchangeRateValue<Double, String>> exchangeRates) {
   160         return getConvertor(DoubleComputer, exchangeRates);
   161     }
   162 
   163     public static Convertor<Double, String> getConvertorDoubleString(
   164             ExchangeRateValue<Double, String> exchangeRate) {
   165         return getConvertor(DoubleComputer, exchangeRate);
   166     }
   167 
   168     public static Convertor<Integer, String> getConvertorIntegerString(
   169             Collection<ExchangeRateValue<Integer, String>> exchangeRates) {
   170         return getConvertor(IntegerComputer, exchangeRates);
   171     }
   172 
   173     public static Convertor<Integer, String> getConvertorIntegerString(
   174             ExchangeRateValue<Integer, String> exchangeRate) {
   175         return getConvertor(IntegerComputer, exchangeRate);
   176     }
   177 
   178     // ---
   179     // BACKWARD COMPATIBILITY - CREATION
   180     // ---
   181     /**
   182      * Creates convertor for Double|String values with specified exchange rate
   183      * between two currencies.
   184      * 
   185      * @param firstCurrencyExchangeRate first currency
   186      * @param secondCurrencyExchangeRate second currency
   187      * @return convertor
   188      */
   189     public static Convertor<Double, String> getConvertorDoubleString(
   190             CurrencyValue<Double, String> firstCurrencyExchangeRate,
   191             CurrencyValue<Double, String> secondCurrencyExchangeRate) {
   192         return getConvertorDoubleString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
   193     }
   194 
   195     /**
   196      * Creates convertor for Integer|String values with specified exchange rate
   197      * between two currencies.
   198      * 
   199      * @param firstCurrencyExchangeRate first currency
   200      * @param secondCurrencyExchangeRate second currency
   201      * @return convertor
   202      */
   203     public static Convertor<Integer, String> getConvertorIntegerString(
   204             CurrencyValue<Integer, String> firstCurrencyExchangeRate,
   205             CurrencyValue<Integer, String> secondCurrencyExchangeRate) {
   206         return getConvertorIntegerString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
   207     }
   208     
   209     // ---
   210     // COMPUTERS
   211     // ---
   212     static final Computer<Double> DoubleComputer = new Computer<Double>() {
   213 
   214         public ComputerResponse<Double> compute(ComputerRequest<Double> request) {
   215             ComputerResponse<Double> response = new ComputerResponse<Double>();
   216             response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());
   217             return response;
   218         }
   219     };
   220     static final Computer<Integer> IntegerComputer = new Computer<Integer>() {
   221 
   222         public ComputerResponse<Integer> compute(ComputerRequest<Integer> request) {
   223             ComputerResponse<Integer> response = new ComputerResponse<Integer>();
   224             response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());
   225             return response;
   226         }
   227     };
   228 }