# HG changeset patch # User Jaroslav Tulach # Date 1224260231 -7200 # Node ID c6b50876b5cfbfc60afd8b2cc0f94c8494a621ac # Parent 978f6a78c22e0a2e9870c4c53a15904e6a37a09d I need to remove solution 12 as it did not allow to query a history with one convertor. There was no way to provide arbitrary date, one could query only about the present state. As such the API was quite simplified and it would be unfair for others if this solution advanced to the final round. Sorry. diff -r 978f6a78c22e -r c6b50876b5cf task4/solution12/build.xml --- a/task4/solution12/build.xml Fri Oct 17 17:54:38 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ - - - - - - Builds, tests, and runs the project. - - - diff -r 978f6a78c22e -r c6b50876b5cf task4/solution12/nbproject/build-impl.xml --- a/task4/solution12/nbproject/build-impl.xml Fri Oct 17 17:54:38 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,642 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must set src.dir - Must set test.src.dir - Must set build.dir - Must set dist.dir - Must set build.classes.dir - Must set dist.javadoc.dir - Must set build.test.classes.dir - Must set build.test.results.dir - Must set build.classes.excludes - Must set dist.jar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must set javac.includes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select some files in the IDE or set javac.includes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - To run this application from the command line without Ant, try: - - - - - - - java -cp "${run.classpath.with.dist.jar}" ${main.class} - - - - - - - - - - - - - - - - - - - - - - - To run this application from the command line without Ant, try: - - java -jar "${dist.jar.resolved}" - - - - - - - - - - - - - - - - - - - Must select one file in the IDE or set run.class - - - - - - - - - - - - - - - - - - - - Must select one file in the IDE or set debug.class - - - - - Must set fix.includes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select some files in the IDE or set javac.includes - - - - - - - - - - - - - - - - - - - - Some tests failed; see details above. - - - - - - - - - Must select some files in the IDE or set test.includes - - - - Some tests failed; see details above. - - - - - Must select one file in the IDE or set test.class - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select one file in the IDE or set applet.url - - - - - - - - - Must select one file in the IDE or set applet.url - - - - - - - - - - - - - - - - - - - diff -r 978f6a78c22e -r c6b50876b5cf task4/solution12/nbproject/genfiles.properties --- a/task4/solution12/nbproject/genfiles.properties Fri Oct 17 17:54:38 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -build.xml.data.CRC32=2ab820eb -build.xml.script.CRC32=58a52595 -build.xml.stylesheet.CRC32=be360661 -# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. -# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. -nbproject/build-impl.xml.data.CRC32=b63e115b -nbproject/build-impl.xml.script.CRC32=3bdfc4fa -nbproject/build-impl.xml.stylesheet.CRC32=e55b27f5 diff -r 978f6a78c22e -r c6b50876b5cf task4/solution12/nbproject/project.properties --- a/task4/solution12/nbproject/project.properties Fri Oct 17 17:54:38 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -application.title=currency -application.vendor=apidesign.org -auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8 -auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80 -auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=default -build.classes.dir=${build.dir}/classes -build.classes.excludes=**/*.java,**/*.form -# This directory is removed when the project is cleaned: -build.dir=build -build.generated.dir=${build.dir}/generated -# Only compile against the classpath explicitly listed here: -build.sysclasspath=ignore -build.test.classes.dir=${build.dir}/test/classes -build.test.results.dir=${build.dir}/test/results -debug.classpath=\ - ${run.classpath} -debug.test.classpath=\ - ${run.test.classpath} -# This directory is removed when the project is cleaned: -dist.dir=dist -dist.jar=${dist.dir}/currency.jar -dist.javadoc.dir=${dist.dir}/javadoc -excludes= -file.reference.junit-4.4.jar=../../libs/junit-4.4.jar -file.reference.src-apifest08=.. -includes=** -jar.compress=false -javac.classpath= -# Space-separated list of extra javac options -javac.compilerargs= -javac.deprecation=false -javac.source=1.5 -javac.target=1.5 -javac.test.classpath=\ - ${javac.classpath}:\ - ${build.classes.dir}:\ - ${file.reference.junit-4.4.jar} -javadoc.additionalparam= -javadoc.author=false -javadoc.encoding= -javadoc.noindex=false -javadoc.nonavbar=false -javadoc.notree=false -javadoc.private=false -javadoc.splitindex=true -javadoc.use=true -javadoc.version=false -javadoc.windowtitle= -jnlp.codebase.type=local -jnlp.codebase.url=file:/home/jarda/src/apifest08/currency/dist -jnlp.descriptor=application -jnlp.enabled=false -jnlp.offline-allowed=false -jnlp.signed=false -meta.inf.dir=${src.dir}/META-INF -platform.active=default_platform -run.classpath=\ - ${javac.classpath}:\ - ${build.classes.dir} -# Space-separated list of JVM arguments used when running the project -# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value -# or test-sys-prop.name=value to set system properties for unit tests): -run.jvmargs= -run.test.classpath=\ - ${javac.test.classpath}:\ - ${build.test.classes.dir} -src.dir=src -test.src.dir=test diff -r 978f6a78c22e -r c6b50876b5cf task4/solution12/nbproject/project.xml --- a/task4/solution12/nbproject/project.xml Fri Oct 17 17:54:38 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ - - - org.netbeans.modules.java.j2seproject - - - Currency Convertor Solution 12 - 1.6.5 - - - - - - - - - diff -r 978f6a78c22e -r c6b50876b5cf task4/solution12/src/org/apidesign/apifest08/currency/Convertor.java --- a/task4/solution12/src/org/apidesign/apifest08/currency/Convertor.java Fri Oct 17 17:54:38 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,297 +0,0 @@ -package org.apidesign.apifest08.currency; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Currency; -import java.util.Date; -import java.util.Hashtable; -import java.util.List; - -import org.apidesign.apifest08.currency.exceptions.ConvertorException; -import org.apidesign.apifest08.currency.exceptions.InvalidCurrencyException; -import org.apidesign.apifest08.currency.exceptions.UnknownConvertorException; - -/** - * This is the skeleton class for your API. You need to make it public, so it is accessible to your client code - * (currently in Task1Test.java) file. - *

- * Feel free to create additional classes or rename this one, just keep all the API and its implementation in this - * package. Do not spread it outside to other packages. - */ -public class Convertor { - - private static Hashtable> exchangeRates; - - private List exchangeRateInstances; - - /** - * Constructor. Checks if all selected currencies are not null and has defined exchange rates for both - * directions. - * @param currencies currencies for new instance of convertor - * @throws UnknownConvertorException if there are not defined exchange rates for both directions for each - * pair of currencies - */ - private Convertor(Currency[] currencies) throws UnknownConvertorException { - exchangeRateInstances = new ArrayList(); - - for (Currency currency1 : currencies) { - for (Currency currency2 : currencies) { - if(currency1 == null || currency2 == null) { - throw new ConvertorException("None of the currencies should be null!!!"); - } - - if(!currency1.getCurrencyCode().equals(currency2.getCurrencyCode())) { - String key = currency1.getCurrencyCode() + currency2.getCurrencyCode(); - if (!exchangeRates.containsKey(key)) { - throw new UnknownConvertorException("Selected convertor (" + currency1.getCurrencyCode() + "->" - + currency2.getCurrencyCode() + ") has not defined exchange rates!!!"); - } - - exchangeRateInstances.add(new ExchangeRateInstance(key, null, null)); - } - } - } - } - - /** - * Sets convertor rate for selected currencies. - * @param currency1 - * one of the currencies we want to convert to/from - * @param currency2 - * the other currency - * @param rate - * exchange rate from currency1 to currency2 - * @param unit - * unit of exchangeRate (USD->CZK - unit=1, you exchange one dollar, SKK->CZK unit=100, exchange rate is for - * 100SKK) - */ - public static void setConvertorRates(Currency currency1, Currency currency2, double rate, double unit) { - if (currency1 == null || currency2 == null) { - throw new ConvertorException("None of the currencies should be null!!!"); - } - - if (rate <= 0 || unit <= 0) { - throw new ConvertorException("Rate(" + rate + ") and unit(" + unit + ") has to be grater then zero!!!"); - } - - if (exchangeRates == null) { - exchangeRates = new Hashtable>(); - } - - String key12 = currency1.getCurrencyCode() + currency2.getCurrencyCode(); - String key21 = currency2.getCurrencyCode() + currency1.getCurrencyCode(); - double recountedRate = (unit / rate) * unit; - - exchangeRates.put(key12, addNewExchangeRate(key12, currency1, currency2, rate, unit, null, null)); - exchangeRates.put(key21, addNewExchangeRate(key21, currency2, currency1, recountedRate, unit, null, null)); - } - - public static Convertor limitExchangeRatesValidity(Convertor convertor, Date validFrom, Date validTo) { - if(convertor == null || validFrom == null || validTo == null) { - throw new ConvertorException("None of parameters of method limitExchangeRatesValidity should be null!!!"); - } - - List exchangeRateInstances = convertor.getExchangeRateInstances(); - for (ExchangeRateInstance exchangeRateInstance : exchangeRateInstances) { - // get actual convertor rates for actual validity - ExchangeRate actualExchangeRate = getExchangeRate(exchangeRateInstance.getKey(), exchangeRateInstance.getValidFrom(), exchangeRateInstance.getValidTo()); - // set new validity for theese rates - actualExchangeRate.setValidFrom(validFrom); - actualExchangeRate.setValidTo(validTo); - // and for selected currency convertor - exchangeRateInstance.setValidFrom(validFrom); - exchangeRateInstance.setValidTo(substractSecond(validTo)); - } - - return convertor; - } - - /** - * Merge exchange rates of actual convertor with exchange rates from selected - * convertor. If there are same currencies in both convertors, these from selected - * convertor rewrites these in actual convertor. - * @param convertor convertor to merge with actual one - * @return convertor with merged exchange rates - */ - public Convertor merge(Convertor convertor) { - if(convertor == null) { - throw new ConvertorException("It's impossible to merge with null convertor!!!"); - } - - exchangeRateInstances.addAll(convertor.getExchangeRateInstances()); - return this; - } - - /** - * Creates new instance of convertor. - * @param currency1 - * one of the currencies we want to convert to/from - * @param currency2 - * the other currency - * @return new instance of convertor - * @throws UnknownConvertorException - * thrown if convertor for selected currencies has not been defined - */ - public static Convertor getConvertorInstance(Currency... currencies) throws UnknownConvertorException { - if(currencies.length < 2) { - throw new ConvertorException("To get convertor instance, you have to select at least two currencies!!!"); - } - - return new Convertor(currencies); - } - - /** - * Converts selected amout of selected currency to other currency of this convertor instance. - * @param amount - * amount to convert - * @param originalCurrency - * currency of this amount - * @param newCurrency - * currency to which we want convert - * @return converted amount - * @throws InvalidCurrencyException - * while one or both currencies doesn't fit for this convertor - */ - public double convert(double amount, Currency originalCurrency, Currency newCurrency) throws InvalidCurrencyException { - ExchangeRate actualyUsedExchangeRate = null; - - if (originalCurrency == null) { - throw new ConvertorException("Original currency is null!!!"); - } - - if (newCurrency == null) { - throw new ConvertorException("Destination currency is null!!!"); - } - - actualyUsedExchangeRate = getExchangeRate(originalCurrency, newCurrency); - - return countResult(actualyUsedExchangeRate, amount); - } - - private double countResult(ExchangeRate actualyUsedExchangeRate, double amount) { - return amount * actualyUsedExchangeRate.getRate() / actualyUsedExchangeRate.getUnit(); - } - - /** - * Decides the direction of conversion and returns actual exchange rate - * for selected currencies and actual moment. - * @param actualCurrency - * actual currency we want to convert - * @return actual exchange rate of this convertor for selected currency - */ - private ExchangeRate getExchangeRate(Currency originalCurrency, Currency newCurrency) throws InvalidCurrencyException { - ExchangeRate actualyUsedExchangeRate = null; - - String key = originalCurrency.getCurrencyCode() + newCurrency.getCurrencyCode(); - - ExchangeRateInstance exchangeRateInstance = findExchangeRateInstance(key); - if(exchangeRateInstance != null) { - actualyUsedExchangeRate = getExchangeRate(exchangeRateInstance.getKey(), exchangeRateInstance.getValidFrom(), exchangeRateInstance.getValidTo()); - } else { - throw new InvalidCurrencyException("This convertor could not be used for converting selected currencies (" + originalCurrency.getCurrencyCode() + "->" - + newCurrency.getCurrencyCode() + ") !!!"); - } - - return actualyUsedExchangeRate; - } - - /** - * Finds instance of exchange rate for actual instance of convertor and actual moment. - * @param key exchange rate instance key - * @return exchange rate instance - */ - private ExchangeRateInstance findExchangeRateInstance(String key) { - ExchangeRateInstance instance = null; - - Date now = new Date(); - for (ExchangeRateInstance item : exchangeRateInstances) { - if(item.getKey().equals(key) && item.getValidFrom() == null && item.getValidTo() == null) { - instance = item; - break; - } else if(item.getKey().equals(key) && item.getValidFrom().compareTo(now) <= 0 && item.getValidTo().compareTo(now) >= 0) { - instance = item; - break; - } - } - - return instance; - } - - - /** - * Returns currency convertors for actual instance of convertor. - * @return currency convertors for actual instance of convertor - */ - private List getExchangeRateInstances() { - return exchangeRateInstances; - } - - private static ExchangeRate getExchangeRate(String key, Date validFrom, Date validTo) { - ExchangeRate exchangeRate = null; - - List currencyExchangeRates = exchangeRates.get(key); - for (ExchangeRate currencyExchangeRate : currencyExchangeRates) { - Date actValidFrom = currencyExchangeRate.getValidFrom(); - Date actValidTo = currencyExchangeRate.getValidTo(); - - if(actValidFrom == null && validFrom == null && actValidTo == null && validTo == null) { - exchangeRate = currencyExchangeRate; - break; - } else if(actValidFrom != null && validFrom != null && actValidTo != null && validTo != null && actValidFrom.compareTo(validFrom) <= 0 && actValidTo.compareTo(validTo) > 0) { - exchangeRate = currencyExchangeRate; - break; - } - } - - if(exchangeRate == null) { - throw new ConvertorException("Exchange rate for actual exchange rate instance not found!!!"); - } - - return exchangeRate; - } - - private static List addNewExchangeRate(String key, Currency currency1, Currency currency2, double rate, double unit, Date validFrom, Date validTo) { - List actualExchangeRates = new ArrayList(); - ExchangeRate newExchangeRate = null; - - if(exchangeRates.containsKey(key)) { - List rates = exchangeRates.get(key); - for (ExchangeRate exchangeRate : rates) { - if(exchangeRate.getValidFrom() == null && exchangeRate.getValidTo() == null && validFrom == null && validTo == null) { - newExchangeRate = exchangeRate; - break; - } else if(exchangeRate.getValidFrom() != null && exchangeRate.getValidTo() != null && validFrom != null && validTo != null) { - if(exchangeRate.getValidFrom().compareTo(validFrom) == 0 && exchangeRate.getValidTo().compareTo(validTo) == 0) { - newExchangeRate = exchangeRate; - break; - } - } - } - actualExchangeRates.addAll(rates); - } - - if(newExchangeRate == null) { - actualExchangeRates.add(new ExchangeRate(currency1, currency2, rate, unit, validFrom, validTo)); - } else { - newExchangeRate.setRate(rate); - newExchangeRate.setUnit(unit); - actualExchangeRates.add(newExchangeRate); - } - - return actualExchangeRates; - } - - /** - * Substracts one second from selected date. - * @param date date - * @return date -1s - */ - private static Date substractSecond(Date date) { - Calendar calendar = Calendar.getInstance(); - calendar.setTime(date); - calendar.set(Calendar.SECOND, -1); - - return calendar.getTime(); - } - -} diff -r 978f6a78c22e -r c6b50876b5cf task4/solution12/src/org/apidesign/apifest08/currency/ExchangeRate.java --- a/task4/solution12/src/org/apidesign/apifest08/currency/ExchangeRate.java Fri Oct 17 17:54:38 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -package org.apidesign.apifest08.currency; - -import java.util.Currency; -import java.util.Date; - -public class ExchangeRate { - - private Currency originalCurrency; - private Currency newCurrency; - private double unit; - private double rate; - private Date validFrom; - private Date validTo; - - public ExchangeRate(Currency originalCurrency, Currency newCurrency, double rate, double unit) { - this.newCurrency = newCurrency; - this.originalCurrency = originalCurrency; - this.rate = rate; - this.unit = unit; - } - - public ExchangeRate(Currency originalCurrency, Currency newCurrency, double rate, double unit, Date validFrom, Date validTo) { - this.newCurrency = newCurrency; - this.originalCurrency = originalCurrency; - this.rate = rate; - this.unit = unit; - this.validFrom = validFrom; - this.validTo = validTo; - } - - /** - * @return the originalCurrency - */ - public Currency getOriginalCurrency() { - return originalCurrency; - } - - /** - * @return the newCurrency - */ - public Currency getNewCurrency() { - return newCurrency; - } - - /** - * @return the unit - */ - public double getUnit() { - return unit; - } - - /** - * @param unit the unit to set - */ - public void setUnit(double unit) { - this.unit = unit; - } - - /** - * @return the rate - */ - public double getRate() { - return rate; - } - - /** - * @param rate the rate to set - */ - public void setRate(double rate) { - this.rate = rate; - } - - /** - * @return the validFrom - */ - public Date getValidFrom() { - return validFrom; - } - - /** - * @param validFrom the validFrom to set - */ - public void setValidFrom(Date validFrom) { - this.validFrom = validFrom; - } - - /** - * @return the validTo - */ - public Date getValidTo() { - return validTo; - } - - /** - * @param validTo the validTo to set - */ - public void setValidTo(Date validTo) { - this.validTo = validTo; - } - -} diff -r 978f6a78c22e -r c6b50876b5cf task4/solution12/src/org/apidesign/apifest08/currency/ExchangeRateInstance.java --- a/task4/solution12/src/org/apidesign/apifest08/currency/ExchangeRateInstance.java Fri Oct 17 17:54:38 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -package org.apidesign.apifest08.currency; - -import java.util.Date; - -public class ExchangeRateInstance { - - private String key; - private Date validFrom; - private Date validTo; - - public ExchangeRateInstance(String key, Date validFrom, Date validTo) { - super(); - this.key = key; - this.validFrom = validFrom; - this.validTo = validTo; - } - - /** - * @return the validFrom - */ - public Date getValidFrom() { - return validFrom; - } - - /** - * @param validFrom the validFrom to set - */ - public void setValidFrom(Date validFrom) { - this.validFrom = validFrom; - } - - /** - * @return the validTo - */ - public Date getValidTo() { - return validTo; - } - - /** - * @param validTo the validTo to set - */ - public void setValidTo(Date validTo) { - this.validTo = validTo; - } - - /** - * @return the key - */ - public String getKey() { - return key; - } - -} diff -r 978f6a78c22e -r c6b50876b5cf task4/solution12/src/org/apidesign/apifest08/currency/exceptions/ConvertorException.java --- a/task4/solution12/src/org/apidesign/apifest08/currency/exceptions/ConvertorException.java Fri Oct 17 17:54:38 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -package org.apidesign.apifest08.currency.exceptions; - -public class ConvertorException extends RuntimeException { - - public ConvertorException() { - } - - public ConvertorException(String message) { - super(message); - } - - public ConvertorException(Throwable cause) { - super(cause); - } - - public ConvertorException(String message, Throwable cause) { - super(message, cause); - } - -} diff -r 978f6a78c22e -r c6b50876b5cf task4/solution12/src/org/apidesign/apifest08/currency/exceptions/InvalidCurrencyException.java --- a/task4/solution12/src/org/apidesign/apifest08/currency/exceptions/InvalidCurrencyException.java Fri Oct 17 17:54:38 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -package org.apidesign.apifest08.currency.exceptions; - -public class InvalidCurrencyException extends Exception { - - public InvalidCurrencyException() { - } - - public InvalidCurrencyException(String message) { - super(message); - } - - public InvalidCurrencyException(Throwable cause) { - super(cause); - } - - public InvalidCurrencyException(String message, Throwable cause) { - super(message, cause); - } - -} diff -r 978f6a78c22e -r c6b50876b5cf task4/solution12/src/org/apidesign/apifest08/currency/exceptions/UnknownConvertorException.java --- a/task4/solution12/src/org/apidesign/apifest08/currency/exceptions/UnknownConvertorException.java Fri Oct 17 17:54:38 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -package org.apidesign.apifest08.currency.exceptions; - -public class UnknownConvertorException extends Exception { - - public UnknownConvertorException() { - } - - public UnknownConvertorException(String message) { - super(message); - } - - public UnknownConvertorException(Throwable cause) { - super(cause); - } - - public UnknownConvertorException(String message, Throwable cause) { - super(message, cause); - } - -} diff -r 978f6a78c22e -r c6b50876b5cf task4/solution12/test/org/apidesign/apifest08/test/Task1Test.java --- a/task4/solution12/test/org/apidesign/apifest08/test/Task1Test.java Fri Oct 17 17:54:38 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,174 +0,0 @@ -package org.apidesign.apifest08.test; - -import java.util.Currency; - -import junit.framework.TestCase; - -import org.apidesign.apifest08.currency.Convertor; -import org.apidesign.apifest08.currency.exceptions.InvalidCurrencyException; -import org.apidesign.apifest08.currency.exceptions.UnknownConvertorException; - -/** - * Finish the Convertor API, and then write bodies of methods inside of this class to match the given tasks. To fullfil - * your task, use the API define in the org.apidesign.apifest08.currency package. Do not you reflection, or - * other hacks as your code shall run without any runtime permissions. - */ -public class Task1Test extends TestCase { - public Task1Test(String testName) { - super(testName); - } - - @Override - protected void setUp() throws Exception { - } - - @Override - protected void tearDown() throws Exception { - } - - // - // Imagine that there are three parts of the whole system: - // 1. there is someone who knows the current exchange rate - // 2. there is someone who wants to do the conversion - // 3. there is the API between 1. and 2. which allows them to communicate - // Please design such API - // - - /** - * Create convertor that understands two currencies, CZK and USD. Make 1 USD == 17 CZK. This is a method provided for - * #1 group - e.g. those that know the exchange rate. They somehow need to create the objects from the API and tell - * them the exchange rate. The API itself knows nothing about any rates, before the createCZKtoUSD method is called. - * Creation of the convertor shall not require subclassing of any class or interface on the client side. - * @return prepared convertor ready for converting USD to CZK and CZK to USD - */ - public static Convertor createCZKtoUSD() { - // set exchange rates - Convertor.setConvertorRates(Currency.getInstance("USD"), Currency.getInstance("CZK"), 17d, 1d); - - // create new instance - Convertor convertor = null; - try { - convertor = Convertor.getConvertorInstance(Currency.getInstance("USD"), Currency.getInstance("CZK")); - } catch (UnknownConvertorException e) { - e.printStackTrace(); - } - - return convertor; - } - - /** - * Create convertor that understands two currencies, CZK and SKK. Make 100 SKK == 80 CZK. Again this is method for the - * #1 group - it knows the exchange rate, and needs to use the API to create objects with the exchange rate. Anyone - * shall be ready to call this method without any other method being called previously. The API itself shall know - * nothing about any rates, before this method is called. Creation of the convertor shall not require subclassing of - * any class or interface on the client side. - * @return prepared convertor ready for converting SKK to CZK and CZK to SKK - */ - public static Convertor createSKKtoCZK() { - // set exchange rates - Convertor.setConvertorRates(Currency.getInstance("SKK"), Currency.getInstance("CZK"), 80d, 100d); - - // create new instance - Convertor convertor = null; - try { - convertor = Convertor.getConvertorInstance(Currency.getInstance("SKK"), Currency.getInstance("CZK")); - } catch (UnknownConvertorException e) { - e.printStackTrace(); - } - - return convertor; - } - - // - // now the methods for group #2 follow: - // this group knows nothing about exchange rates, but knows how to use - // the API to do conversions. It somehow (by calling one of the factory - // methods) gets objects from the API and uses them to do the conversions. - // - - /** - * Use the convertor from createCZKtoUSD method and do few conversions with it. - */ - public void testCurrencyCZKUSD() throws Exception { - Convertor c = createCZKtoUSD(); - // convert $5 to CZK using c: - double result = c.convert(5, Currency.getInstance("USD"), Currency.getInstance("CZK")); - assertEquals("Result is not 85 CZK", 85.0, result); - - // convert $8 to CZK - result = c.convert(8, Currency.getInstance("USD"), Currency.getInstance("CZK")); - assertEquals("Result is not 136 CZK", 136.0, result); - - // convert 1003CZK to USD - result = c.convert(1003, Currency.getInstance("CZK"), Currency.getInstance("USD")); - assertEquals("Result is not 59 USD", 59.0, result); - } - - /** - * Use the convertor from createSKKtoCZK method and do few conversions with it. - */ - public void testCurrencySKKCZK() throws Exception { - Convertor c = createSKKtoCZK(); - - // convert 16CZK using c: - double result = c.convert(16, Currency.getInstance("CZK"), Currency.getInstance("SKK")); - assertEquals("Result is not 20 SKK", 20.0, result); - - // convert 500SKK to CZK - result = c.convert(500, Currency.getInstance("SKK"), Currency.getInstance("CZK")); - assertEquals("Result is not 400 CZK", 400.0, result); - } - - /** - * Verify that the CZK to USD convertor knows nothing about SKK. - */ - public void testCannotConvertToSKKwithCZKUSDConvertor() throws Exception { - Convertor c = createCZKtoUSD(); - boolean exceptionThrown = false; - - // convert $5 to SKK, the API shall say this is not possible - try { - c.convert(5, Currency.getInstance("USD"), Currency.getInstance("SKK")); - exceptionThrown = false; - } catch (InvalidCurrencyException e) { - exceptionThrown = true; - } - assertEquals("It should be impossible to convert to SKK with USD->CZK convertor", true, exceptionThrown); - - // convert 500 SKK to CZK, the API shall say this is not possible - try { - c.convert(500, Currency.getInstance("SKK"), Currency.getInstance("CZK")); - exceptionThrown = false; - } catch (InvalidCurrencyException e) { - exceptionThrown = true; - } - assertEquals("It should be impossible to convert from SKK with USD->CZK convertor", true, exceptionThrown); - - } - - /** - * Verify that the CZK to SKK convertor knows nothing about USD. - */ - public void testCannotConvertToSKKwithSKKCZKConvertor() throws Exception { - Convertor c = createSKKtoCZK(); - boolean exceptionThrown = false; - - // convert $5 to SKK, the API shall say this is not possible - try { - c.convert(5, Currency.getInstance("USD"), Currency.getInstance("SKK")); - exceptionThrown = false; - } catch (InvalidCurrencyException e) { - exceptionThrown = true; - } - assertEquals("It should be impossible to convert form USD with SKK->CZK convertor", true, exceptionThrown); - - // convert 500 CZK to USD, the API shall say this is not possible - try { - c.convert(500, Currency.getInstance("CZK"), Currency.getInstance("USD")); - exceptionThrown = false; - } catch (InvalidCurrencyException e) { - exceptionThrown = true; - } - assertEquals("It should be impossible to convert to USD with SKK->CZK convertor", true, exceptionThrown); - } -} diff -r 978f6a78c22e -r c6b50876b5cf task4/solution12/test/org/apidesign/apifest08/test/Task2Test.java --- a/task4/solution12/test/org/apidesign/apifest08/test/Task2Test.java Fri Oct 17 17:54:38 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -package org.apidesign.apifest08.test; - -import java.util.Currency; - -import junit.framework.TestCase; - -import org.apidesign.apifest08.currency.Convertor; -import org.apidesign.apifest08.currency.exceptions.UnknownConvertorException; - -/** There are many currencies around the world and many banks manipulate - * with more than one or two at the same time. As banks are usually the - * best paying clients, which is true even in case of your Convertor API, - * it is reasonable to listen to their requests. - *

- * The quest for today is to enhance your existing convertor API to hold - * information about many currencies and allow conversions between any of them. - * Also, as conversion rates for diferent currencies usually arise from various - * bank departments, there is another important need. There is a need to - * compose two convertors into one by merging all the information about - * currencies they know about. - */ -public class Task2Test extends TestCase { - public Task2Test(String testName) { - super(testName); - } - - @Override - protected void setUp() throws Exception { - } - - @Override - protected void tearDown() throws Exception { - } - - // As in Task1Test, keep in mind, that there are three parts - // of the whole system: - // 1. there is someone who knows the current exchange rate - // 2. there is someone who wants to do the conversion - // 3. there is the API between 1. and 2. which allows them to communicate - // - // Please backward compatibly enhance your existing API to support following - // usecases: - // - - /** Create convertor that understands two currencies, CZK and - * SKK. Make 100 SKK == 75 CZK. This is method for the group of users that - * knows the exchange rate, and needs to use the API to create objects - * with the exchange rate. Anyone shall be ready to call this method without - * any other method being called previously. The API itself shall know - * nothing about any rates, before this method is called. - */ - public static Convertor createTripleConvertor() { - // Rates: 1USD = 15CZK - // Rates: 1USD = 20SKK - // Rates: 75CZK = 100SKK - // set exchange rates - Convertor.setConvertorRates(Currency.getInstance("USD"), Currency.getInstance("CZK"), 15, 1); - Convertor.setConvertorRates(Currency.getInstance("USD"), Currency.getInstance("SKK"), 20, 1); - Convertor.setConvertorRates(Currency.getInstance("SKK"), Currency.getInstance("CZK"), 75, 100); - - // create new instance - Convertor convertor = null; - try { - convertor = Convertor.getConvertorInstance(Currency.getInstance("USD"), Currency.getInstance("SKK"), Currency.getInstance("CZK")); - } catch (UnknownConvertorException e) { - e.printStackTrace(); - } - return convertor; - } - - /** Define convertor that understands three currencies. Use it. - */ - public void testConvertorForUSDandCZKandSKK() throws Exception { - Convertor c = createTripleConvertor(); - - // convert $5 to CZK using c: - double result = c.convert(5d, Currency.getInstance("USD"), Currency.getInstance("CZK")); - assertEquals("Result is not 75 CZK", 75.0, result); - - // convert $5 to SKK using c: - result = c.convert(5d, Currency.getInstance("USD"), Currency.getInstance("SKK")); - assertEquals("Result is not 100 SKK", 100.0, result); - - // convert 200SKK to CZK using c: - result = c.convert(200d, Currency.getInstance("SKK"), Currency.getInstance("CZK")); - assertEquals("Result is not 150 CZK", 150.0, result); - - // convert 200SKK to USK using c: - result = c.convert(200d, Currency.getInstance("SKK"), Currency.getInstance("USD")); - assertEquals("Result is not 10 USD", 10.0, result); - } - - /** Merge all currency rates of convertor 1 with convertor 2. - * Implement this using your API, preferably this method just delegates - * into some API method which does the actual work, without requiring - * API clients to code anything complex. - */ - public static Convertor merge(Convertor one, Convertor two) { - return one.merge(two); - } - - /** Join the convertors from previous task, Task1Test and show that it - * can be used to do reasonable conversions. - */ - public void testConvertorComposition() throws Exception { - Convertor c = merge( - Task1Test.createCZKtoUSD(), - Task1Test.createSKKtoCZK() - ); - - // convert $5 to CZK using c: - double result = c.convert(5d, Currency.getInstance("USD"), Currency.getInstance("CZK")); - assertEquals("Result is not 85 CZK", 85.0, result); - - // convert $8 to CZK using c: - result = c.convert(8d, Currency.getInstance("USD"), Currency.getInstance("CZK")); - assertEquals("Result is not 136 CZK", 136.0, result); - - // convert 1003CZK to USD using c: - result = c.convert(1003d, Currency.getInstance("CZK"), Currency.getInstance("USD")); - assertEquals("Result is not 59 USD", 59.0, result); - - // convert 16CZK using c: - result = c.convert(16d, Currency.getInstance("CZK"), Currency.getInstance("SKK")); - assertEquals("Result is not 20 SKK", 20.0, result); - - // convert 500SKK to CZK using c: - result = c.convert(500d, Currency.getInstance("SKK"), Currency.getInstance("CZK")); - assertEquals("Result is not 400 CZK", 400.0, result); - - } -} diff -r 978f6a78c22e -r c6b50876b5cf task4/solution12/test/org/apidesign/apifest08/test/Task3Test.java --- a/task4/solution12/test/org/apidesign/apifest08/test/Task3Test.java Fri Oct 17 17:54:38 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,145 +0,0 @@ -package org.apidesign.apifest08.test; - -import java.util.Currency; - -import junit.framework.TestCase; -import org.apidesign.apifest08.currency.Convertor; -import org.apidesign.apifest08.currency.exceptions.UnknownConvertorException; - -/** The exchange rates are not always the same. They are changing. Day by day, - * hour by hour, minute by minute. For every bank it is important to always - * have the actual exchange rate available in the system. That is why let's - * create a pluggable convertor that will always have up to date value of its - * exchange rate. - *

- * The quest for today is to allow 3rd party developer to write a convertor - * that adjusts its exchange rate everytime it is queried. This convertor is - * written by independent vendor, the vendor knows only your Convertor API, - * he does not know how the whole system looks and how the convertor is supposed - * to be used. - */ -public class Task3Test extends TestCase { - - private static double actualRate; - private static boolean increasing; - - private static final double EXCHANGE_RATE_MAX = 16.0; - private static final double EXCHANGE_RATE_MIN = 15.0; - - public Task3Test(String testName) { - super(testName); - } - - @Override - protected void setUp() throws Exception { - } - - @Override - protected void tearDown() throws Exception { - } - - // Backward compatibly enhance your existing API to support following - // usecases: - // - - - /** Without knowing anything about the surrounding system, write an - * implementation of convertor that will return different rates everytime - * it is queried. Convert USD to CZK and vice versa. Start with the rate of - * 1USD = 16CZK and adjust it in favor of CZK by 0.01 CZK with every query. - * As soon as you reach 1USD = 15CZK adjust it by 0.01 CZK in favor of USD - * until you reach 1USD = 16CZK - * - * @return new instance of "online" USD and CZK convertor starting with rate 1USD = 16CZK - */ - public static Convertor createOnlineCZKUSDConvertor() { - actualRate = 16.01; - increasing = false; - - // sets actual exchange rates - setRates(); - - // create new instance - Convertor convertor = null; - try { - convertor = Convertor.getConvertorInstance(Currency.getInstance("USD"), Currency.getInstance("CZK")); - } catch (UnknownConvertorException e) { - e.printStackTrace(); - } - - return convertor; - } - - public void testFewQueriesForOnlineConvertor() throws Exception { - Convertor c = createOnlineCZKUSDConvertor(); - doFewQueriesForOnlineConvertor(c); - } - - static void doFewQueriesForOnlineConvertor(Convertor c) throws Exception { - // convert $5 to CZK using c: - double result = c.convert(5d, Currency.getInstance("USD"), Currency.getInstance("CZK")); - double expectedResult = actualRate * 5; - assertEquals("Result is not " + expectedResult + " CZK", expectedResult, result); - - // change exchange rates - setRates(); - - // convert $8 to CZK using c: - result = c.convert(8d, Currency.getInstance("USD"), Currency.getInstance("CZK")); - expectedResult = actualRate * 8; - assertEquals("Result is not " + expectedResult + " CZK", expectedResult, result); - - // change exchange rates - setRates(); - - // convert $1 to CZK using c: - result = c.convert(1d, Currency.getInstance("USD"), Currency.getInstance("CZK")); - expectedResult = actualRate * 1; - assertEquals("Result is not " + expectedResult + " CZK", expectedResult, result); - - // change exchange rates - setRates(); - - // convert 15.97CZK to USD using c: - result = c.convert(15.97d, Currency.getInstance("CZK"), Currency.getInstance("USD")); - expectedResult = 15.97 / actualRate ; - assertEquals("Result is not " + expectedResult + " USD", expectedResult, result); - } - - /** Join the convertors and show they behave sane. - */ - public void testOnlineConvertorComposition() throws Exception { - Convertor c = Task2Test.merge( - createOnlineCZKUSDConvertor(), - Task1Test.createSKKtoCZK() - ); - - // convert 16CZK to SKK using c: - double result = c.convert(16d, Currency.getInstance("CZK"), Currency.getInstance("SKK")); - assertEquals("Result is not 20 SKK", 20d, result); - - // convert 500SKK to CZK using c: - result = c.convert(500d, Currency.getInstance("SKK"), Currency.getInstance("CZK")); - assertEquals("Result is not 400 CZK", 400d, result); - - doFewQueriesForOnlineConvertor(c); - } - - private static void setRates() { - // logic for change of actual exchange rate - if(increasing) { - actualRate += 0.01; - if(actualRate == EXCHANGE_RATE_MAX){ - increasing = false; - } - } else { - actualRate -= 0.01; - if(actualRate == EXCHANGE_RATE_MIN){ - increasing = true; - } - } - - // set exchange rates - Convertor.setConvertorRates(Currency.getInstance("USD"), Currency.getInstance("CZK"), actualRate, 1d); - } -} diff -r 978f6a78c22e -r c6b50876b5cf task4/solution12/test/org/apidesign/apifest08/test/Task4Test.java --- a/task4/solution12/test/org/apidesign/apifest08/test/Task4Test.java Fri Oct 17 17:54:38 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,211 +0,0 @@ -package org.apidesign.apifest08.test; - -import java.text.SimpleDateFormat; -import java.util.Currency; -import java.util.Date; -import junit.framework.TestCase; -import org.apidesign.apifest08.currency.Convertor; -import org.apidesign.apifest08.currency.exceptions.UnknownConvertorException; - -/** The exchange rates are not always the same. They are changing. However - * as in order to predict the future, one needs to understand own past. That is - * why it is important to know the exchange rate as it was at any time during - * the past. - *

- * Today's quest is to enhance the convertor API to deal with dates. - * One shall be able to convert a currency at any date. Each currencies rate shall - * be associated with a range between two Date objects. In order - * to keep compatibility with old API that knew nothing about dates, the - * rates associated then are applicable "for eternity". Any use of existing - * convert methods that do not accept a Date argument, uses the current - * System.currentTimeMillis() as default date. - */ -public class Task4Test extends TestCase { - public Task4Test(String testName) { - super(testName); - } - - @Override - protected void setUp() throws Exception { - } - - @Override - protected void tearDown() throws Exception { - } - - // Backward compatibly enhance your existing API to support following - // usecases: - // - - /** Takes a convertor with any rates associated and creates new convertor - * that returns the same values as the old one for time between from to till. - * Otherwise it returns no results. This is just a helper method that - * shall call some real one in the API. - * - * @param old existing convertor - * @param from initial date (inclusive) - * @param till final date (exclusive) - * @return new convertor - */ - public static Convertor limitTo(Convertor old, Date from, Date till) { - return Convertor.limitExchangeRatesValidity(old, from, till); - } - - - public void testCompositionOfLimitedConvertors() throws Exception { - SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm zzz"); - Date d1 = format.parse("2008-10-01 00:00 GMT"); // 2008-10-01 0:00 GMT - Date d2 = format.parse("2008-10-02 00:00 GMT"); // 2008-10-02 0:00 GMT - Date d3 = format.parse("2008-10-03 00:00 GMT"); // 2008-10-03 0:00 GMT - - Convertor c = Task2Test.merge( - limitTo(Task1Test.createCZKtoUSD(), d1, d2), - limitTo(Task1Test.createSKKtoCZK(), d2, d3) - ); - - Date now = new Date(); - - // convert $5 to CZK using c: - double result = 0; - boolean exceptionThrown = false; - try { - result = c.convert(5, Currency.getInstance("USD"), Currency.getInstance("CZK")); - } catch (Exception e) { - exceptionThrown = true; - } - - if(d1.compareTo(now) <= 0 && d2.compareTo(now) > 0) { - System.out.println("Result."); - assertEquals("Result is not 85 CZK.", 85d, result); - } else { - System.out.println("Exception."); - assertEquals("There is no Exception while using convertor at wrong day!", true, exceptionThrown); - } - - // convert $8 to CZK using c: - exceptionThrown = false; - try { - result = c.convert(8, Currency.getInstance("USD"), Currency.getInstance("CZK")); - } catch (Exception e) { - exceptionThrown = true; - } - - if(d1.compareTo(now) <= 0 && d2.compareTo(now) > 0) { - System.out.println("Result."); - assertEquals("Result is not 136 CZK.", 136d, result); - } else { - System.out.println("Exception."); - assertEquals("There is no Exception while using convertor at wrong day!", true, exceptionThrown); - } - - // convert 1003CZK to USD using c: - exceptionThrown = false; - try { - result = c.convert(1003, Currency.getInstance("CZK"), Currency.getInstance("USD")); - } catch (Exception e) { - exceptionThrown = true; - } - - if(d1.compareTo(now) <= 0 && d2.compareTo(now) > 0) { - System.out.println("Result."); - assertEquals("Result is not 59 USD.", 59d, result); - } else { - System.out.println("Exception."); - assertEquals("There is no Exception while using convertor at wrong day!", true, exceptionThrown); - } - - // convert 16CZK using c: - exceptionThrown = false; - try { - result = c.convert(16, Currency.getInstance("CZK"), Currency.getInstance("SKK")); - } catch (Exception e) { - exceptionThrown = true; - } - - if(d2.compareTo(now) <= 0 && d3.compareTo(now) > 0) { - System.out.println("Result."); - assertEquals("Result is not 20 SKK.", 20d, result); - } else { - System.out.println("Exception."); - assertEquals("There is no Exception while using convertor at wrong day!", true, exceptionThrown); - } - - // convert 500SKK to CZK using c: - exceptionThrown = false; - try { - result = c.convert(500, Currency.getInstance("SKK"), Currency.getInstance("CZK")); - } catch (Exception e) { - exceptionThrown = true; - } - - if(d2.compareTo(now) <= 0 && d3.compareTo(now) > 0) { - System.out.println("Result."); - assertEquals("Result is not 400 CZK.", 400d, result); - } else { - System.out.println("Exception."); - assertEquals("There is no Exception while using convertor at wrong day!", true, exceptionThrown); - } - - } - - /** Create convertor that understands two currencies, CZK and - * SKK. Make 100 SKK == 90 CZK. - * - * @return prepared convertor ready for converting SKK to CZK and CZK to SKK - */ - public static Convertor createSKKtoCZK2() { - // set exchange rates - Convertor.setConvertorRates(Currency.getInstance("SKK"), Currency.getInstance("CZK"), 90d, 100d); - - // create new instance - Convertor convertor = null; - try { - convertor = Convertor.getConvertorInstance(Currency.getInstance("SKK"), Currency.getInstance("CZK")); - } catch (UnknownConvertorException e) { - e.printStackTrace(); - } - - return convertor; - } - - public void testDateConvetorWithTwoDifferentRates() throws Exception { - - SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm zzz"); - Date d1 = format.parse("2008-10-01 00:00 GMT"); // 2008-10-01 0:00 GMT - Date d2 = format.parse("2008-10-02 00:00 GMT"); // 2008-10-02 0:00 GMT - Date d3 = format.parse("2008-10-03 00:00 GMT"); // 2008-10-03 0:00 GMT - - Convertor c = Task2Test.merge( - limitTo(createSKKtoCZK2(), d1, d2), - limitTo(Task1Test.createSKKtoCZK(), d2, d3) - ); - - // convert 500SKK to CZK using c at 2008-10-02 9:00 GMT: - // assertEquals("Result is 400 CZK"); - - // convert 500SKK to CZK using c at 2008-10-01 6:00 GMT: - // assertEquals("Result is 450 CZK"); - Date now = new Date(); - - // convert 500SKK to CZK using c: - double result = 0; - boolean exceptionThrown = false; - try { - result = c.convert(500, Currency.getInstance("SKK"), Currency.getInstance("CZK")); - } catch (Exception e) { - exceptionThrown = true; - } - - if(d1.compareTo(now) <= 0 && d2.compareTo(now) > 0) { - System.out.println("\nResult"); - assertEquals("Result is not 450 CZK.", 450d, result); - } else if(d2.compareTo(now) <= 0 && d3.compareTo(now) > 0) { - System.out.println("\nResult"); - assertEquals("Result is not 400 CZK.", 400d, result); - } else { - System.out.println("\nException"); - assertEquals("There is no Exception while using convertor at wrong day!", true, exceptionThrown); - } - } - -}