1 package org.apidesign.apifest08.currency;
3 import java.util.ArrayList;
4 import java.util.Calendar;
5 import java.util.Currency;
7 import java.util.Hashtable;
10 import org.apidesign.apifest08.currency.exceptions.ConvertorException;
11 import org.apidesign.apifest08.currency.exceptions.InvalidCurrencyException;
12 import org.apidesign.apifest08.currency.exceptions.UnknownConvertorException;
15 * This is the skeleton class for your API. You need to make it public, so it is accessible to your client code
16 * (currently in Task1Test.java) file.
18 * Feel free to create additional classes or rename this one, just keep all the API and its implementation in this
19 * package. Do not spread it outside to other packages.
21 public class Convertor {
23 private static Hashtable<String, List<ExchangeRate>> exchangeRates;
25 private List<ExchangeRateInstance> exchangeRateInstances;
28 * Constructor. Checks if all selected currencies are not null and has defined exchange rates for both
30 * @param currencies currencies for new instance of convertor
31 * @throws UnknownConvertorException if there are not defined exchange rates for both directions for each
34 private Convertor(Currency[] currencies) throws UnknownConvertorException {
35 exchangeRateInstances = new ArrayList<ExchangeRateInstance>();
37 for (Currency currency1 : currencies) {
38 for (Currency currency2 : currencies) {
39 if(currency1 == null || currency2 == null) {
40 throw new ConvertorException("None of the currencies should be null!!!");
43 if(!currency1.getCurrencyCode().equals(currency2.getCurrencyCode())) {
44 String key = currency1.getCurrencyCode() + currency2.getCurrencyCode();
45 if (!exchangeRates.containsKey(key)) {
46 throw new UnknownConvertorException("Selected convertor (" + currency1.getCurrencyCode() + "->"
47 + currency2.getCurrencyCode() + ") has not defined exchange rates!!!");
50 exchangeRateInstances.add(new ExchangeRateInstance(key, null, null));
57 * Sets convertor rate for selected currencies.
59 * one of the currencies we want to convert to/from
63 * exchange rate from currency1 to currency2
65 * unit of exchangeRate (USD->CZK - unit=1, you exchange one dollar, SKK->CZK unit=100, exchange rate is for
68 public static void setConvertorRates(Currency currency1, Currency currency2, double rate, double unit) {
69 if (currency1 == null || currency2 == null) {
70 throw new ConvertorException("None of the currencies should be null!!!");
73 if (rate <= 0 || unit <= 0) {
74 throw new ConvertorException("Rate(" + rate + ") and unit(" + unit + ") has to be grater then zero!!!");
77 if (exchangeRates == null) {
78 exchangeRates = new Hashtable<String, List<ExchangeRate>>();
81 String key12 = currency1.getCurrencyCode() + currency2.getCurrencyCode();
82 String key21 = currency2.getCurrencyCode() + currency1.getCurrencyCode();
83 double recountedRate = (unit / rate) * unit;
85 exchangeRates.put(key12, addNewExchangeRate(key12, currency1, currency2, rate, unit, null, null));
86 exchangeRates.put(key21, addNewExchangeRate(key21, currency2, currency1, recountedRate, unit, null, null));
89 public static Convertor limitExchangeRatesValidity(Convertor convertor, Date validFrom, Date validTo) {
90 if(convertor == null || validFrom == null || validTo == null) {
91 throw new ConvertorException("None of parameters of method limitExchangeRatesValidity should be null!!!");
94 List<ExchangeRateInstance> exchangeRateInstances = convertor.getExchangeRateInstances();
95 for (ExchangeRateInstance exchangeRateInstance : exchangeRateInstances) {
96 // get actual convertor rates for actual validity
97 ExchangeRate actualExchangeRate = getExchangeRate(exchangeRateInstance.getKey(), exchangeRateInstance.getValidFrom(), exchangeRateInstance.getValidTo());
98 // set new validity for theese rates
99 actualExchangeRate.setValidFrom(validFrom);
100 actualExchangeRate.setValidTo(validTo);
101 // and for selected currency convertor
102 exchangeRateInstance.setValidFrom(validFrom);
103 exchangeRateInstance.setValidTo(substractSecond(validTo));
110 * Merge exchange rates of actual convertor with exchange rates from selected
111 * convertor. If there are same currencies in both convertors, these from selected
112 * convertor rewrites these in actual convertor.
113 * @param convertor convertor to merge with actual one
114 * @return convertor with merged exchange rates
116 public Convertor merge(Convertor convertor) {
117 if(convertor == null) {
118 throw new ConvertorException("It's impossible to merge with null convertor!!!");
121 exchangeRateInstances.addAll(convertor.getExchangeRateInstances());
126 * Creates new instance of convertor.
128 * one of the currencies we want to convert to/from
131 * @return new instance of convertor
132 * @throws UnknownConvertorException
133 * thrown if convertor for selected currencies has not been defined
135 public static Convertor getConvertorInstance(Currency... currencies) throws UnknownConvertorException {
136 if(currencies.length < 2) {
137 throw new ConvertorException("To get convertor instance, you have to select at least two currencies!!!");
140 return new Convertor(currencies);
144 * Converts selected amout of selected currency to other currency of this convertor instance.
147 * @param originalCurrency
148 * currency of this amount
150 * currency to which we want convert
151 * @return converted amount
152 * @throws InvalidCurrencyException
153 * while one or both currencies doesn't fit for this convertor
155 public double convert(double amount, Currency originalCurrency, Currency newCurrency) throws InvalidCurrencyException {
156 ExchangeRate actualyUsedExchangeRate = null;
158 if (originalCurrency == null) {
159 throw new ConvertorException("Original currency is null!!!");
162 if (newCurrency == null) {
163 throw new ConvertorException("Destination currency is null!!!");
166 actualyUsedExchangeRate = getExchangeRate(originalCurrency, newCurrency);
168 return countResult(actualyUsedExchangeRate, amount);
171 private double countResult(ExchangeRate actualyUsedExchangeRate, double amount) {
172 return amount * actualyUsedExchangeRate.getRate() / actualyUsedExchangeRate.getUnit();
176 * Decides the direction of conversion and returns actual exchange rate
177 * for selected currencies and actual moment.
178 * @param actualCurrency
179 * actual currency we want to convert
180 * @return actual exchange rate of this convertor for selected currency
182 private ExchangeRate getExchangeRate(Currency originalCurrency, Currency newCurrency) throws InvalidCurrencyException {
183 ExchangeRate actualyUsedExchangeRate = null;
185 String key = originalCurrency.getCurrencyCode() + newCurrency.getCurrencyCode();
187 ExchangeRateInstance exchangeRateInstance = findExchangeRateInstance(key);
188 if(exchangeRateInstance != null) {
189 actualyUsedExchangeRate = getExchangeRate(exchangeRateInstance.getKey(), exchangeRateInstance.getValidFrom(), exchangeRateInstance.getValidTo());
191 throw new InvalidCurrencyException("This convertor could not be used for converting selected currencies (" + originalCurrency.getCurrencyCode() + "->"
192 + newCurrency.getCurrencyCode() + ") !!!");
195 return actualyUsedExchangeRate;
199 * Finds instance of exchange rate for actual instance of convertor and actual moment.
200 * @param key exchange rate instance key
201 * @return exchange rate instance
203 private ExchangeRateInstance findExchangeRateInstance(String key) {
204 ExchangeRateInstance instance = null;
206 Date now = new Date();
207 for (ExchangeRateInstance item : exchangeRateInstances) {
208 if(item.getKey().equals(key) && item.getValidFrom() == null && item.getValidTo() == null) {
211 } else if(item.getKey().equals(key) && item.getValidFrom().compareTo(now) <= 0 && item.getValidTo().compareTo(now) >= 0) {
222 * Returns currency convertors for actual instance of convertor.
223 * @return currency convertors for actual instance of convertor
225 private List<ExchangeRateInstance> getExchangeRateInstances() {
226 return exchangeRateInstances;
229 private static ExchangeRate getExchangeRate(String key, Date validFrom, Date validTo) {
230 ExchangeRate exchangeRate = null;
232 List<ExchangeRate> currencyExchangeRates = exchangeRates.get(key);
233 for (ExchangeRate currencyExchangeRate : currencyExchangeRates) {
234 Date actValidFrom = currencyExchangeRate.getValidFrom();
235 Date actValidTo = currencyExchangeRate.getValidTo();
237 if(actValidFrom == null && validFrom == null && actValidTo == null && validTo == null) {
238 exchangeRate = currencyExchangeRate;
240 } else if(actValidFrom != null && validFrom != null && actValidTo != null && validTo != null && actValidFrom.compareTo(validFrom) <= 0 && actValidTo.compareTo(validTo) > 0) {
241 exchangeRate = currencyExchangeRate;
246 if(exchangeRate == null) {
247 throw new ConvertorException("Exchange rate for actual exchange rate instance not found!!!");
253 private static List<ExchangeRate> addNewExchangeRate(String key, Currency currency1, Currency currency2, double rate, double unit, Date validFrom, Date validTo) {
254 List<ExchangeRate> actualExchangeRates = new ArrayList<ExchangeRate>();
255 ExchangeRate newExchangeRate = null;
257 if(exchangeRates.containsKey(key)) {
258 List<ExchangeRate> rates = exchangeRates.get(key);
259 for (ExchangeRate exchangeRate : rates) {
260 if(exchangeRate.getValidFrom() == null && exchangeRate.getValidTo() == null && validFrom == null && validTo == null) {
261 newExchangeRate = exchangeRate;
263 } else if(exchangeRate.getValidFrom() != null && exchangeRate.getValidTo() != null && validFrom != null && validTo != null) {
264 if(exchangeRate.getValidFrom().compareTo(validFrom) == 0 && exchangeRate.getValidTo().compareTo(validTo) == 0) {
265 newExchangeRate = exchangeRate;
270 actualExchangeRates.addAll(rates);
273 if(newExchangeRate == null) {
274 actualExchangeRates.add(new ExchangeRate(currency1, currency2, rate, unit, validFrom, validTo));
276 newExchangeRate.setRate(rate);
277 newExchangeRate.setUnit(unit);
278 actualExchangeRates.add(newExchangeRate);
281 return actualExchangeRates;
285 * Substracts one second from selected date.
289 private static Date substractSecond(Date date) {
290 Calendar calendar = Calendar.getInstance();
291 calendar.setTime(date);
292 calendar.set(Calendar.SECOND, -1);
294 return calendar.getTime();