Copying all solution that advanced into round #3 into task3 directory
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 07 Oct 2008 11:05:34 +0200
changeset 45251d0ed461fb
parent 44 6a500cd1e467
child 46 b61dcd332269
Copying all solution that advanced into round #3 into task3 directory
task3/solution02/build.xml
task3/solution02/nbproject/build-impl.xml
task3/solution02/nbproject/genfiles.properties
task3/solution02/nbproject/project.properties
task3/solution02/nbproject/project.xml
task3/solution02/src/org/apidesign/apifest08/currency/CompositeConvertor.java
task3/solution02/src/org/apidesign/apifest08/currency/Convertor.java
task3/solution02/src/org/apidesign/apifest08/currency/ConvertorFactory.java
task3/solution02/src/org/apidesign/apifest08/currency/DefaultConvertor.java
task3/solution02/src/org/apidesign/apifest08/currency/ExtendedConvertor.java
task3/solution02/src/org/apidesign/apifest08/currency/Money.java
task3/solution02/src/org/apidesign/apifest08/currency/MoneyImpl.java
task3/solution02/test/org/apidesign/apifest08/currency/CompositeConvertorTest.java
task3/solution02/test/org/apidesign/apifest08/test/ConvertorFactoryTest.java
task3/solution02/test/org/apidesign/apifest08/test/ConvertorTest.java
task3/solution02/test/org/apidesign/apifest08/test/MoneyTest.java
task3/solution02/test/org/apidesign/apifest08/test/Task1Test.java
task3/solution02/test/org/apidesign/apifest08/test/Task2Test.java
task3/solution04/build.xml
task3/solution04/nbproject/build-impl.xml
task3/solution04/nbproject/genfiles.properties
task3/solution04/nbproject/project.properties
task3/solution04/nbproject/project.xml
task3/solution04/src/org/apidesign/apifest08/currency/CompositeConvertorImpl.java
task3/solution04/src/org/apidesign/apifest08/currency/ConverterImpl.java
task3/solution04/src/org/apidesign/apifest08/currency/Convertor.java
task3/solution04/src/org/apidesign/apifest08/currency/ConvertorFactory.java
task3/solution04/src/org/apidesign/apifest08/currency/InvalidConversionException.java
task3/solution04/test/org/apidesign/apifest08/test/Task1Test.java
task3/solution04/test/org/apidesign/apifest08/test/Task2Test.java
task3/solution06/build.xml
task3/solution06/nbproject/build-impl.xml
task3/solution06/nbproject/genfiles.properties
task3/solution06/nbproject/project.properties
task3/solution06/nbproject/project.xml
task3/solution06/src/org/apidesign/apifest08/currency/Amount.java
task3/solution06/src/org/apidesign/apifest08/currency/Assert.java
task3/solution06/src/org/apidesign/apifest08/currency/ConversionException.java
task3/solution06/src/org/apidesign/apifest08/currency/Convertor.java
task3/solution06/src/org/apidesign/apifest08/currency/CurrencyException.java
task3/solution06/src/org/apidesign/apifest08/currency/UnsupportedConversionException.java
task3/solution06/test/org/apidesign/apifest08/test/Currencies.java
task3/solution06/test/org/apidesign/apifest08/test/Task1Test.java
task3/solution06/test/org/apidesign/apifest08/test/Task2Test.java
task3/solution07/build.xml
task3/solution07/nbproject/build-impl.xml
task3/solution07/nbproject/genfiles.properties
task3/solution07/nbproject/project.properties
task3/solution07/nbproject/project.xml
task3/solution07/src/org/apidesign/apifest08/currency/ConversionRate.java
task3/solution07/src/org/apidesign/apifest08/currency/Convertor.java
task3/solution07/src/org/apidesign/apifest08/currency/DelegatingConvertor.java
task3/solution07/src/org/apidesign/apifest08/currency/IllegalRequestSubtypeException.java
task3/solution07/src/org/apidesign/apifest08/currency/MonetaryAmount.java
task3/solution07/src/org/apidesign/apifest08/currency/TableConvertor.java
task3/solution07/test/org/apidesign/apifest08/test/ContractImposingDelegatingConvertor.java
task3/solution07/test/org/apidesign/apifest08/test/Task1Test.java
task3/solution07/test/org/apidesign/apifest08/test/Task2Test.java
task3/solution11/build.xml
task3/solution11/nbproject/build-impl.xml
task3/solution11/nbproject/genfiles.properties
task3/solution11/nbproject/project.properties
task3/solution11/nbproject/project.xml
task3/solution11/src/org/apidesign/apifest08/currency/Computer.java
task3/solution11/src/org/apidesign/apifest08/currency/Convertor.java
task3/solution11/src/org/apidesign/apifest08/currency/CurrencyValue.java
task3/solution11/src/org/apidesign/apifest08/currency/ExchangeRateValue.java
task3/solution11/test/org/apidesign/apifest08/test/Task1Test.java
task3/solution11/test/org/apidesign/apifest08/test/Task2Test.java
task3/solution12/build.xml
task3/solution12/nbproject/build-impl.xml
task3/solution12/nbproject/genfiles.properties
task3/solution12/nbproject/project.properties
task3/solution12/nbproject/project.xml
task3/solution12/src/org/apidesign/apifest08/currency/Convertor.java
task3/solution12/src/org/apidesign/apifest08/currency/ExchangeRate.java
task3/solution12/src/org/apidesign/apifest08/currency/exceptions/ConvertorException.java
task3/solution12/src/org/apidesign/apifest08/currency/exceptions/InvalidCurrencyException.java
task3/solution12/src/org/apidesign/apifest08/currency/exceptions/UnknownConvertorException.java
task3/solution12/test/org/apidesign/apifest08/test/Task1Test.java
task3/solution12/test/org/apidesign/apifest08/test/Task2Test.java
task3/solution13/build.xml
task3/solution13/nbproject/build-impl.xml
task3/solution13/nbproject/genfiles.properties
task3/solution13/nbproject/project.properties
task3/solution13/nbproject/project.xml
task3/solution13/src/org/apidesign/apifest08/currency/ConversionNotSupportedException.java
task3/solution13/src/org/apidesign/apifest08/currency/ConversionResult.java
task3/solution13/src/org/apidesign/apifest08/currency/Convertor.java
task3/solution13/src/org/apidesign/apifest08/currency/ConvertorCurrency.java
task3/solution13/src/org/apidesign/apifest08/currency/ConvertorException.java
task3/solution13/src/org/apidesign/apifest08/currency/ExchangeRate.java
task3/solution13/src/org/apidesign/apifest08/currency/ExchangeRateProvider.java
task3/solution13/test/org/apidesign/apifest08/test/Task1Test.java
task3/solution13/test/org/apidesign/apifest08/test/Task2Test.java
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/task3/solution02/build.xml	Tue Oct 07 11:05:34 2008 +0200
     1.3 @@ -0,0 +1,69 @@
     1.4 +<?xml version="1.0" encoding="UTF-8"?>
     1.5 +<!-- You may freely edit this file. See commented blocks below for -->
     1.6 +<!-- some examples of how to customize the build. -->
     1.7 +<!-- (If you delete it and reopen the project it will be recreated.) -->
     1.8 +<project name="currency" default="default" basedir=".">
     1.9 +    <description>Builds, tests, and runs the project.</description>
    1.10 +    <import file="nbproject/build-impl.xml"/>
    1.11 +    <!--
    1.12 +
    1.13 +    There exist several targets which are by default empty and which can be 
    1.14 +    used for execution of your tasks. These targets are usually executed 
    1.15 +    before and after some main targets. They are: 
    1.16 +
    1.17 +      -pre-init:                 called before initialization of project properties
    1.18 +      -post-init:                called after initialization of project properties
    1.19 +      -pre-compile:              called before javac compilation
    1.20 +      -post-compile:             called after javac compilation
    1.21 +      -pre-compile-single:       called before javac compilation of single file
    1.22 +      -post-compile-single:      called after javac compilation of single file
    1.23 +      -pre-compile-test:         called before javac compilation of JUnit tests
    1.24 +      -post-compile-test:        called after javac compilation of JUnit tests
    1.25 +      -pre-compile-test-single:  called before javac compilation of single JUnit test
    1.26 +      -post-compile-test-single: called after javac compilation of single JUunit test
    1.27 +      -pre-jar:                  called before JAR building
    1.28 +      -post-jar:                 called after JAR building
    1.29 +      -post-clean:               called after cleaning build products
    1.30 +
    1.31 +    (Targets beginning with '-' are not intended to be called on their own.)
    1.32 +
    1.33 +    Example of inserting an obfuscator after compilation could look like this:
    1.34 +
    1.35 +        <target name="-post-compile">
    1.36 +            <obfuscate>
    1.37 +                <fileset dir="${build.classes.dir}"/>
    1.38 +            </obfuscate>
    1.39 +        </target>
    1.40 +
    1.41 +    For list of available properties check the imported 
    1.42 +    nbproject/build-impl.xml file. 
    1.43 +
    1.44 +
    1.45 +    Another way to customize the build is by overriding existing main targets.
    1.46 +    The targets of interest are: 
    1.47 +
    1.48 +      -init-macrodef-javac:     defines macro for javac compilation
    1.49 +      -init-macrodef-junit:     defines macro for junit execution
    1.50 +      -init-macrodef-debug:     defines macro for class debugging
    1.51 +      -init-macrodef-java:      defines macro for class execution
    1.52 +      -do-jar-with-manifest:    JAR building (if you are using a manifest)
    1.53 +      -do-jar-without-manifest: JAR building (if you are not using a manifest)
    1.54 +      run:                      execution of project 
    1.55 +      -javadoc-build:           Javadoc generation
    1.56 +      test-report:              JUnit report generation
    1.57 +
    1.58 +    An example of overriding the target for project execution could look like this:
    1.59 +
    1.60 +        <target name="run" depends="currency-impl.jar">
    1.61 +            <exec dir="bin" executable="launcher.exe">
    1.62 +                <arg file="${dist.jar}"/>
    1.63 +            </exec>
    1.64 +        </target>
    1.65 +
    1.66 +    Notice that the overridden target depends on the jar target and not only on 
    1.67 +    the compile target as the regular run target does. Again, for a list of available 
    1.68 +    properties which you can use, check the target you are overriding in the
    1.69 +    nbproject/build-impl.xml file. 
    1.70 +
    1.71 +    -->
    1.72 +</project>
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/task3/solution02/nbproject/build-impl.xml	Tue Oct 07 11:05:34 2008 +0200
     2.3 @@ -0,0 +1,642 @@
     2.4 +<?xml version="1.0" encoding="UTF-8"?>
     2.5 +<!--
     2.6 +*** GENERATED FROM project.xml - DO NOT EDIT  ***
     2.7 +***         EDIT ../build.xml INSTEAD         ***
     2.8 +
     2.9 +For the purpose of easier reading the script
    2.10 +is divided into following sections:
    2.11 +
    2.12 +  - initialization
    2.13 +  - compilation
    2.14 +  - jar
    2.15 +  - execution
    2.16 +  - debugging
    2.17 +  - javadoc
    2.18 +  - junit compilation
    2.19 +  - junit execution
    2.20 +  - junit debugging
    2.21 +  - applet
    2.22 +  - cleanup
    2.23 +
    2.24 +        -->
    2.25 +<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="Currency_Convertor_Solution_02-impl">
    2.26 +    <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
    2.27 +    <!-- 
    2.28 +                ======================
    2.29 +                INITIALIZATION SECTION 
    2.30 +                ======================
    2.31 +            -->
    2.32 +    <target name="-pre-init">
    2.33 +        <!-- Empty placeholder for easier customization. -->
    2.34 +        <!-- You can override this target in the ../build.xml file. -->
    2.35 +    </target>
    2.36 +    <target depends="-pre-init" name="-init-private">
    2.37 +        <property file="nbproject/private/config.properties"/>
    2.38 +        <property file="nbproject/private/configs/${config}.properties"/>
    2.39 +        <property file="nbproject/private/private.properties"/>
    2.40 +    </target>
    2.41 +    <target depends="-pre-init,-init-private" name="-init-user">
    2.42 +        <property file="${user.properties.file}"/>
    2.43 +        <!-- The two properties below are usually overridden -->
    2.44 +        <!-- by the active platform. Just a fallback. -->
    2.45 +        <property name="default.javac.source" value="1.4"/>
    2.46 +        <property name="default.javac.target" value="1.4"/>
    2.47 +    </target>
    2.48 +    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
    2.49 +        <property file="nbproject/configs/${config}.properties"/>
    2.50 +        <property file="nbproject/project.properties"/>
    2.51 +    </target>
    2.52 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
    2.53 +        <available file="${manifest.file}" property="manifest.available"/>
    2.54 +        <condition property="manifest.available+main.class">
    2.55 +            <and>
    2.56 +                <isset property="manifest.available"/>
    2.57 +                <isset property="main.class"/>
    2.58 +                <not>
    2.59 +                    <equals arg1="${main.class}" arg2="" trim="true"/>
    2.60 +                </not>
    2.61 +            </and>
    2.62 +        </condition>
    2.63 +        <condition property="manifest.available+main.class+mkdist.available">
    2.64 +            <and>
    2.65 +                <istrue value="${manifest.available+main.class}"/>
    2.66 +                <isset property="libs.CopyLibs.classpath"/>
    2.67 +            </and>
    2.68 +        </condition>
    2.69 +        <condition property="have.tests">
    2.70 +            <or>
    2.71 +                <available file="${test.src.dir}"/>
    2.72 +            </or>
    2.73 +        </condition>
    2.74 +        <condition property="have.sources">
    2.75 +            <or>
    2.76 +                <available file="${src.dir}"/>
    2.77 +            </or>
    2.78 +        </condition>
    2.79 +        <condition property="netbeans.home+have.tests">
    2.80 +            <and>
    2.81 +                <isset property="netbeans.home"/>
    2.82 +                <isset property="have.tests"/>
    2.83 +            </and>
    2.84 +        </condition>
    2.85 +        <condition property="no.javadoc.preview">
    2.86 +            <and>
    2.87 +                <isset property="javadoc.preview"/>
    2.88 +                <isfalse value="${javadoc.preview}"/>
    2.89 +            </and>
    2.90 +        </condition>
    2.91 +        <property name="run.jvmargs" value=""/>
    2.92 +        <property name="javac.compilerargs" value=""/>
    2.93 +        <property name="work.dir" value="${basedir}"/>
    2.94 +        <condition property="no.deps">
    2.95 +            <and>
    2.96 +                <istrue value="${no.dependencies}"/>
    2.97 +            </and>
    2.98 +        </condition>
    2.99 +        <property name="javac.debug" value="true"/>
   2.100 +        <property name="javadoc.preview" value="true"/>
   2.101 +        <property name="application.args" value=""/>
   2.102 +        <property name="source.encoding" value="${file.encoding}"/>
   2.103 +        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
   2.104 +            <and>
   2.105 +                <isset property="javadoc.encoding"/>
   2.106 +                <not>
   2.107 +                    <equals arg1="${javadoc.encoding}" arg2=""/>
   2.108 +                </not>
   2.109 +            </and>
   2.110 +        </condition>
   2.111 +        <property name="javadoc.encoding.used" value="${source.encoding}"/>
   2.112 +        <property name="includes" value="**"/>
   2.113 +        <property name="excludes" value=""/>
   2.114 +        <property name="do.depend" value="false"/>
   2.115 +        <condition property="do.depend.true">
   2.116 +            <istrue value="${do.depend}"/>
   2.117 +        </condition>
   2.118 +        <condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
   2.119 +            <and>
   2.120 +                <isset property="jaxws.endorsed.dir"/>
   2.121 +                <available file="nbproject/jaxws-build.xml"/>
   2.122 +            </and>
   2.123 +        </condition>
   2.124 +    </target>
   2.125 +    <target name="-post-init">
   2.126 +        <!-- Empty placeholder for easier customization. -->
   2.127 +        <!-- You can override this target in the ../build.xml file. -->
   2.128 +    </target>
   2.129 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
   2.130 +        <fail unless="src.dir">Must set src.dir</fail>
   2.131 +        <fail unless="test.src.dir">Must set test.src.dir</fail>
   2.132 +        <fail unless="build.dir">Must set build.dir</fail>
   2.133 +        <fail unless="dist.dir">Must set dist.dir</fail>
   2.134 +        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
   2.135 +        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
   2.136 +        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
   2.137 +        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
   2.138 +        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
   2.139 +        <fail unless="dist.jar">Must set dist.jar</fail>
   2.140 +    </target>
   2.141 +    <target name="-init-macrodef-property">
   2.142 +        <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
   2.143 +            <attribute name="name"/>
   2.144 +            <attribute name="value"/>
   2.145 +            <sequential>
   2.146 +                <property name="@{name}" value="${@{value}}"/>
   2.147 +            </sequential>
   2.148 +        </macrodef>
   2.149 +    </target>
   2.150 +    <target name="-init-macrodef-javac">
   2.151 +        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
   2.152 +            <attribute default="${src.dir}" name="srcdir"/>
   2.153 +            <attribute default="${build.classes.dir}" name="destdir"/>
   2.154 +            <attribute default="${javac.classpath}" name="classpath"/>
   2.155 +            <attribute default="${includes}" name="includes"/>
   2.156 +            <attribute default="${excludes}" name="excludes"/>
   2.157 +            <attribute default="${javac.debug}" name="debug"/>
   2.158 +            <attribute default="" name="sourcepath"/>
   2.159 +            <element name="customize" optional="true"/>
   2.160 +            <sequential>
   2.161 +                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
   2.162 +                    <classpath>
   2.163 +                        <path path="@{classpath}"/>
   2.164 +                    </classpath>
   2.165 +                    <compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
   2.166 +                    <customize/>
   2.167 +                </javac>
   2.168 +            </sequential>
   2.169 +        </macrodef>
   2.170 +        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
   2.171 +            <attribute default="${src.dir}" name="srcdir"/>
   2.172 +            <attribute default="${build.classes.dir}" name="destdir"/>
   2.173 +            <attribute default="${javac.classpath}" name="classpath"/>
   2.174 +            <sequential>
   2.175 +                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
   2.176 +                    <classpath>
   2.177 +                        <path path="@{classpath}"/>
   2.178 +                    </classpath>
   2.179 +                </depend>
   2.180 +            </sequential>
   2.181 +        </macrodef>
   2.182 +        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
   2.183 +            <attribute default="${build.classes.dir}" name="destdir"/>
   2.184 +            <sequential>
   2.185 +                <fail unless="javac.includes">Must set javac.includes</fail>
   2.186 +                <pathconvert pathsep="," property="javac.includes.binary">
   2.187 +                    <path>
   2.188 +                        <filelist dir="@{destdir}" files="${javac.includes}"/>
   2.189 +                    </path>
   2.190 +                    <globmapper from="*.java" to="*.class"/>
   2.191 +                </pathconvert>
   2.192 +                <delete>
   2.193 +                    <files includes="${javac.includes.binary}"/>
   2.194 +                </delete>
   2.195 +            </sequential>
   2.196 +        </macrodef>
   2.197 +    </target>
   2.198 +    <target name="-init-macrodef-junit">
   2.199 +        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
   2.200 +            <attribute default="${includes}" name="includes"/>
   2.201 +            <attribute default="${excludes}" name="excludes"/>
   2.202 +            <attribute default="**" name="testincludes"/>
   2.203 +            <sequential>
   2.204 +                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
   2.205 +                    <batchtest todir="${build.test.results.dir}">
   2.206 +                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
   2.207 +                            <filename name="@{testincludes}"/>
   2.208 +                        </fileset>
   2.209 +                    </batchtest>
   2.210 +                    <classpath>
   2.211 +                        <path path="${run.test.classpath}"/>
   2.212 +                    </classpath>
   2.213 +                    <syspropertyset>
   2.214 +                        <propertyref prefix="test-sys-prop."/>
   2.215 +                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
   2.216 +                    </syspropertyset>
   2.217 +                    <formatter type="brief" usefile="false"/>
   2.218 +                    <formatter type="xml"/>
   2.219 +                    <jvmarg line="${run.jvmargs}"/>
   2.220 +                </junit>
   2.221 +            </sequential>
   2.222 +        </macrodef>
   2.223 +    </target>
   2.224 +    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
   2.225 +        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
   2.226 +            <attribute default="${main.class}" name="name"/>
   2.227 +            <attribute default="${debug.classpath}" name="classpath"/>
   2.228 +            <attribute default="" name="stopclassname"/>
   2.229 +            <sequential>
   2.230 +                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
   2.231 +                    <classpath>
   2.232 +                        <path path="@{classpath}"/>
   2.233 +                    </classpath>
   2.234 +                </nbjpdastart>
   2.235 +            </sequential>
   2.236 +        </macrodef>
   2.237 +        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
   2.238 +            <attribute default="${build.classes.dir}" name="dir"/>
   2.239 +            <sequential>
   2.240 +                <nbjpdareload>
   2.241 +                    <fileset dir="@{dir}" includes="${fix.classes}">
   2.242 +                        <include name="${fix.includes}*.class"/>
   2.243 +                    </fileset>
   2.244 +                </nbjpdareload>
   2.245 +            </sequential>
   2.246 +        </macrodef>
   2.247 +    </target>
   2.248 +    <target name="-init-debug-args">
   2.249 +        <property name="version-output" value="java version &quot;${ant.java.version}"/>
   2.250 +        <condition property="have-jdk-older-than-1.4">
   2.251 +            <or>
   2.252 +                <contains string="${version-output}" substring="java version &quot;1.0"/>
   2.253 +                <contains string="${version-output}" substring="java version &quot;1.1"/>
   2.254 +                <contains string="${version-output}" substring="java version &quot;1.2"/>
   2.255 +                <contains string="${version-output}" substring="java version &quot;1.3"/>
   2.256 +            </or>
   2.257 +        </condition>
   2.258 +        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
   2.259 +            <istrue value="${have-jdk-older-than-1.4}"/>
   2.260 +        </condition>
   2.261 +        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
   2.262 +            <os family="windows"/>
   2.263 +        </condition>
   2.264 +        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
   2.265 +            <isset property="debug.transport"/>
   2.266 +        </condition>
   2.267 +    </target>
   2.268 +    <target depends="-init-debug-args" name="-init-macrodef-debug">
   2.269 +        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
   2.270 +            <attribute default="${main.class}" name="classname"/>
   2.271 +            <attribute default="${debug.classpath}" name="classpath"/>
   2.272 +            <element name="customize" optional="true"/>
   2.273 +            <sequential>
   2.274 +                <java classname="@{classname}" dir="${work.dir}" fork="true">
   2.275 +                    <jvmarg line="${debug-args-line}"/>
   2.276 +                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
   2.277 +                    <jvmarg line="${run.jvmargs}"/>
   2.278 +                    <classpath>
   2.279 +                        <path path="@{classpath}"/>
   2.280 +                    </classpath>
   2.281 +                    <syspropertyset>
   2.282 +                        <propertyref prefix="run-sys-prop."/>
   2.283 +                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
   2.284 +                    </syspropertyset>
   2.285 +                    <customize/>
   2.286 +                </java>
   2.287 +            </sequential>
   2.288 +        </macrodef>
   2.289 +    </target>
   2.290 +    <target name="-init-macrodef-java">
   2.291 +        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
   2.292 +            <attribute default="${main.class}" name="classname"/>
   2.293 +            <element name="customize" optional="true"/>
   2.294 +            <sequential>
   2.295 +                <java classname="@{classname}" dir="${work.dir}" fork="true">
   2.296 +                    <jvmarg line="${run.jvmargs}"/>
   2.297 +                    <classpath>
   2.298 +                        <path path="${run.classpath}"/>
   2.299 +                    </classpath>
   2.300 +                    <syspropertyset>
   2.301 +                        <propertyref prefix="run-sys-prop."/>
   2.302 +                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
   2.303 +                    </syspropertyset>
   2.304 +                    <customize/>
   2.305 +                </java>
   2.306 +            </sequential>
   2.307 +        </macrodef>
   2.308 +    </target>
   2.309 +    <target name="-init-presetdef-jar">
   2.310 +        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
   2.311 +            <jar compress="${jar.compress}" jarfile="${dist.jar}">
   2.312 +                <j2seproject1:fileset dir="${build.classes.dir}"/>
   2.313 +            </jar>
   2.314 +        </presetdef>
   2.315 +    </target>
   2.316 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar" name="init"/>
   2.317 +    <!--
   2.318 +                ===================
   2.319 +                COMPILATION SECTION
   2.320 +                ===================
   2.321 +            -->
   2.322 +    <target depends="init" name="deps-jar" unless="no.deps"/>
   2.323 +    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
   2.324 +    <target depends="init" name="-check-automatic-build">
   2.325 +        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
   2.326 +    </target>
   2.327 +    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
   2.328 +        <antcall target="clean"/>
   2.329 +    </target>
   2.330 +    <target depends="init,deps-jar" name="-pre-pre-compile">
   2.331 +        <mkdir dir="${build.classes.dir}"/>
   2.332 +    </target>
   2.333 +    <target name="-pre-compile">
   2.334 +        <!-- Empty placeholder for easier customization. -->
   2.335 +        <!-- You can override this target in the ../build.xml file. -->
   2.336 +    </target>
   2.337 +    <target if="do.depend.true" name="-compile-depend">
   2.338 +        <j2seproject3:depend/>
   2.339 +    </target>
   2.340 +    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
   2.341 +        <j2seproject3:javac/>
   2.342 +        <copy todir="${build.classes.dir}">
   2.343 +            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
   2.344 +        </copy>
   2.345 +    </target>
   2.346 +    <target name="-post-compile">
   2.347 +        <!-- Empty placeholder for easier customization. -->
   2.348 +        <!-- You can override this target in the ../build.xml file. -->
   2.349 +    </target>
   2.350 +    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
   2.351 +    <target name="-pre-compile-single">
   2.352 +        <!-- Empty placeholder for easier customization. -->
   2.353 +        <!-- You can override this target in the ../build.xml file. -->
   2.354 +    </target>
   2.355 +    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
   2.356 +        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
   2.357 +        <j2seproject3:force-recompile/>
   2.358 +        <j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
   2.359 +    </target>
   2.360 +    <target name="-post-compile-single">
   2.361 +        <!-- Empty placeholder for easier customization. -->
   2.362 +        <!-- You can override this target in the ../build.xml file. -->
   2.363 +    </target>
   2.364 +    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
   2.365 +    <!--
   2.366 +                ====================
   2.367 +                JAR BUILDING SECTION
   2.368 +                ====================
   2.369 +            -->
   2.370 +    <target depends="init" name="-pre-pre-jar">
   2.371 +        <dirname file="${dist.jar}" property="dist.jar.dir"/>
   2.372 +        <mkdir dir="${dist.jar.dir}"/>
   2.373 +    </target>
   2.374 +    <target name="-pre-jar">
   2.375 +        <!-- Empty placeholder for easier customization. -->
   2.376 +        <!-- You can override this target in the ../build.xml file. -->
   2.377 +    </target>
   2.378 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
   2.379 +        <j2seproject1:jar/>
   2.380 +    </target>
   2.381 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
   2.382 +        <j2seproject1:jar manifest="${manifest.file}"/>
   2.383 +    </target>
   2.384 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
   2.385 +        <j2seproject1:jar manifest="${manifest.file}">
   2.386 +            <j2seproject1:manifest>
   2.387 +                <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
   2.388 +            </j2seproject1:manifest>
   2.389 +        </j2seproject1:jar>
   2.390 +        <echo>To run this application from the command line without Ant, try:</echo>
   2.391 +        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
   2.392 +        <property location="${dist.jar}" name="dist.jar.resolved"/>
   2.393 +        <pathconvert property="run.classpath.with.dist.jar">
   2.394 +            <path path="${run.classpath}"/>
   2.395 +            <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
   2.396 +        </pathconvert>
   2.397 +        <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
   2.398 +    </target>
   2.399 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
   2.400 +        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
   2.401 +        <pathconvert property="run.classpath.without.build.classes.dir">
   2.402 +            <path path="${run.classpath}"/>
   2.403 +            <map from="${build.classes.dir.resolved}" to=""/>
   2.404 +        </pathconvert>
   2.405 +        <pathconvert pathsep=" " property="jar.classpath">
   2.406 +            <path path="${run.classpath.without.build.classes.dir}"/>
   2.407 +            <chainedmapper>
   2.408 +                <flattenmapper/>
   2.409 +                <globmapper from="*" to="lib/*"/>
   2.410 +            </chainedmapper>
   2.411 +        </pathconvert>
   2.412 +        <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
   2.413 +        <copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
   2.414 +            <fileset dir="${build.classes.dir}"/>
   2.415 +            <manifest>
   2.416 +                <attribute name="Main-Class" value="${main.class}"/>
   2.417 +                <attribute name="Class-Path" value="${jar.classpath}"/>
   2.418 +            </manifest>
   2.419 +        </copylibs>
   2.420 +        <echo>To run this application from the command line without Ant, try:</echo>
   2.421 +        <property location="${dist.jar}" name="dist.jar.resolved"/>
   2.422 +        <echo>java -jar "${dist.jar.resolved}"</echo>
   2.423 +    </target>
   2.424 +    <target name="-post-jar">
   2.425 +        <!-- Empty placeholder for easier customization. -->
   2.426 +        <!-- You can override this target in the ../build.xml file. -->
   2.427 +    </target>
   2.428 +    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
   2.429 +    <!--
   2.430 +                =================
   2.431 +                EXECUTION SECTION
   2.432 +                =================
   2.433 +            -->
   2.434 +    <target depends="init,compile" description="Run a main class." name="run">
   2.435 +        <j2seproject1:java>
   2.436 +            <customize>
   2.437 +                <arg line="${application.args}"/>
   2.438 +            </customize>
   2.439 +        </j2seproject1:java>
   2.440 +    </target>
   2.441 +    <target name="-do-not-recompile">
   2.442 +        <property name="javac.includes.binary" value=""/>
   2.443 +    </target>
   2.444 +    <target depends="init,-do-not-recompile,compile-single" name="run-single">
   2.445 +        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
   2.446 +        <j2seproject1:java classname="${run.class}"/>
   2.447 +    </target>
   2.448 +    <!--
   2.449 +                =================
   2.450 +                DEBUGGING SECTION
   2.451 +                =================
   2.452 +            -->
   2.453 +    <target depends="init" if="netbeans.home" name="-debug-start-debugger">
   2.454 +        <j2seproject1:nbjpdastart name="${debug.class}"/>
   2.455 +    </target>
   2.456 +    <target depends="init,compile" name="-debug-start-debuggee">
   2.457 +        <j2seproject3:debug>
   2.458 +            <customize>
   2.459 +                <arg line="${application.args}"/>
   2.460 +            </customize>
   2.461 +        </j2seproject3:debug>
   2.462 +    </target>
   2.463 +    <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
   2.464 +    <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
   2.465 +        <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
   2.466 +    </target>
   2.467 +    <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
   2.468 +    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
   2.469 +        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
   2.470 +        <j2seproject3:debug classname="${debug.class}"/>
   2.471 +    </target>
   2.472 +    <target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
   2.473 +    <target depends="init" name="-pre-debug-fix">
   2.474 +        <fail unless="fix.includes">Must set fix.includes</fail>
   2.475 +        <property name="javac.includes" value="${fix.includes}.java"/>
   2.476 +    </target>
   2.477 +    <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
   2.478 +        <j2seproject1:nbjpdareload/>
   2.479 +    </target>
   2.480 +    <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
   2.481 +    <!--
   2.482 +                ===============
   2.483 +                JAVADOC SECTION
   2.484 +                ===============
   2.485 +            -->
   2.486 +    <target depends="init" name="-javadoc-build">
   2.487 +        <mkdir dir="${dist.javadoc.dir}"/>
   2.488 +        <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
   2.489 +            <classpath>
   2.490 +                <path path="${javac.classpath}"/>
   2.491 +            </classpath>
   2.492 +            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
   2.493 +                <filename name="**/*.java"/>
   2.494 +            </fileset>
   2.495 +        </javadoc>
   2.496 +    </target>
   2.497 +    <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
   2.498 +        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
   2.499 +    </target>
   2.500 +    <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
   2.501 +    <!--
   2.502 +                =========================
   2.503 +                JUNIT COMPILATION SECTION
   2.504 +                =========================
   2.505 +            -->
   2.506 +    <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
   2.507 +        <mkdir dir="${build.test.classes.dir}"/>
   2.508 +    </target>
   2.509 +    <target name="-pre-compile-test">
   2.510 +        <!-- Empty placeholder for easier customization. -->
   2.511 +        <!-- You can override this target in the ../build.xml file. -->
   2.512 +    </target>
   2.513 +    <target if="do.depend.true" name="-compile-test-depend">
   2.514 +        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
   2.515 +    </target>
   2.516 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
   2.517 +        <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
   2.518 +        <copy todir="${build.test.classes.dir}">
   2.519 +            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
   2.520 +        </copy>
   2.521 +    </target>
   2.522 +    <target name="-post-compile-test">
   2.523 +        <!-- Empty placeholder for easier customization. -->
   2.524 +        <!-- You can override this target in the ../build.xml file. -->
   2.525 +    </target>
   2.526 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
   2.527 +    <target name="-pre-compile-test-single">
   2.528 +        <!-- Empty placeholder for easier customization. -->
   2.529 +        <!-- You can override this target in the ../build.xml file. -->
   2.530 +    </target>
   2.531 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
   2.532 +        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
   2.533 +        <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
   2.534 +        <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
   2.535 +        <copy todir="${build.test.classes.dir}">
   2.536 +            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
   2.537 +        </copy>
   2.538 +    </target>
   2.539 +    <target name="-post-compile-test-single">
   2.540 +        <!-- Empty placeholder for easier customization. -->
   2.541 +        <!-- You can override this target in the ../build.xml file. -->
   2.542 +    </target>
   2.543 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
   2.544 +    <!--
   2.545 +                =======================
   2.546 +                JUNIT EXECUTION SECTION
   2.547 +                =======================
   2.548 +            -->
   2.549 +    <target depends="init" if="have.tests" name="-pre-test-run">
   2.550 +        <mkdir dir="${build.test.results.dir}"/>
   2.551 +    </target>
   2.552 +    <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
   2.553 +        <j2seproject3:junit testincludes="**/*Test.java"/>
   2.554 +    </target>
   2.555 +    <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
   2.556 +        <fail if="tests.failed">Some tests failed; see details above.</fail>
   2.557 +    </target>
   2.558 +    <target depends="init" if="have.tests" name="test-report"/>
   2.559 +    <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
   2.560 +    <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
   2.561 +    <target depends="init" if="have.tests" name="-pre-test-run-single">
   2.562 +        <mkdir dir="${build.test.results.dir}"/>
   2.563 +    </target>
   2.564 +    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
   2.565 +        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
   2.566 +        <j2seproject3:junit excludes="" includes="${test.includes}"/>
   2.567 +    </target>
   2.568 +    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
   2.569 +        <fail if="tests.failed">Some tests failed; see details above.</fail>
   2.570 +    </target>
   2.571 +    <target depends="init,-do-not-recompile,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
   2.572 +    <!--
   2.573 +                =======================
   2.574 +                JUNIT DEBUGGING SECTION
   2.575 +                =======================
   2.576 +            -->
   2.577 +    <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
   2.578 +        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
   2.579 +        <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
   2.580 +        <delete file="${test.report.file}"/>
   2.581 +        <mkdir dir="${build.test.results.dir}"/>
   2.582 +        <j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
   2.583 +            <customize>
   2.584 +                <syspropertyset>
   2.585 +                    <propertyref prefix="test-sys-prop."/>
   2.586 +                    <mapper from="test-sys-prop.*" to="*" type="glob"/>
   2.587 +                </syspropertyset>
   2.588 +                <arg value="${test.class}"/>
   2.589 +                <arg value="showoutput=true"/>
   2.590 +                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
   2.591 +                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
   2.592 +            </customize>
   2.593 +        </j2seproject3:debug>
   2.594 +    </target>
   2.595 +    <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
   2.596 +        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
   2.597 +    </target>
   2.598 +    <target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
   2.599 +    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
   2.600 +        <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
   2.601 +    </target>
   2.602 +    <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
   2.603 +    <!--
   2.604 +                =========================
   2.605 +                APPLET EXECUTION SECTION
   2.606 +                =========================
   2.607 +            -->
   2.608 +    <target depends="init,compile-single" name="run-applet">
   2.609 +        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
   2.610 +        <j2seproject1:java classname="sun.applet.AppletViewer">
   2.611 +            <customize>
   2.612 +                <arg value="${applet.url}"/>
   2.613 +            </customize>
   2.614 +        </j2seproject1:java>
   2.615 +    </target>
   2.616 +    <!--
   2.617 +                =========================
   2.618 +                APPLET DEBUGGING  SECTION
   2.619 +                =========================
   2.620 +            -->
   2.621 +    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
   2.622 +        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
   2.623 +        <j2seproject3:debug classname="sun.applet.AppletViewer">
   2.624 +            <customize>
   2.625 +                <arg value="${applet.url}"/>
   2.626 +            </customize>
   2.627 +        </j2seproject3:debug>
   2.628 +    </target>
   2.629 +    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
   2.630 +    <!--
   2.631 +                ===============
   2.632 +                CLEANUP SECTION
   2.633 +                ===============
   2.634 +            -->
   2.635 +    <target depends="init" name="deps-clean" unless="no.deps"/>
   2.636 +    <target depends="init" name="-do-clean">
   2.637 +        <delete dir="${build.dir}"/>
   2.638 +        <delete dir="${dist.dir}"/>
   2.639 +    </target>
   2.640 +    <target name="-post-clean">
   2.641 +        <!-- Empty placeholder for easier customization. -->
   2.642 +        <!-- You can override this target in the ../build.xml file. -->
   2.643 +    </target>
   2.644 +    <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
   2.645 +</project>
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/task3/solution02/nbproject/genfiles.properties	Tue Oct 07 11:05:34 2008 +0200
     3.3 @@ -0,0 +1,8 @@
     3.4 +build.xml.data.CRC32=2ab820eb
     3.5 +build.xml.script.CRC32=58a52595
     3.6 +build.xml.stylesheet.CRC32=be360661
     3.7 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
     3.8 +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
     3.9 +nbproject/build-impl.xml.data.CRC32=848e6267
    3.10 +nbproject/build-impl.xml.script.CRC32=6be86987
    3.11 +nbproject/build-impl.xml.stylesheet.CRC32=e55b27f5
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/task3/solution02/nbproject/project.properties	Tue Oct 07 11:05:34 2008 +0200
     4.3 @@ -0,0 +1,68 @@
     4.4 +application.title=currency
     4.5 +application.vendor=apidesign.org
     4.6 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
     4.7 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
     4.8 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=default
     4.9 +build.classes.dir=${build.dir}/classes
    4.10 +build.classes.excludes=**/*.java,**/*.form
    4.11 +# This directory is removed when the project is cleaned:
    4.12 +build.dir=build
    4.13 +build.generated.dir=${build.dir}/generated
    4.14 +# Only compile against the classpath explicitly listed here:
    4.15 +build.sysclasspath=ignore
    4.16 +build.test.classes.dir=${build.dir}/test/classes
    4.17 +build.test.results.dir=${build.dir}/test/results
    4.18 +debug.classpath=\
    4.19 +    ${run.classpath}
    4.20 +debug.test.classpath=\
    4.21 +    ${run.test.classpath}
    4.22 +# This directory is removed when the project is cleaned:
    4.23 +dist.dir=dist
    4.24 +dist.jar=${dist.dir}/currency.jar
    4.25 +dist.javadoc.dir=${dist.dir}/javadoc
    4.26 +excludes=
    4.27 +file.reference.junit-4.4.jar=../../libs/junit-4.4.jar
    4.28 +file.reference.src-apifest08=..
    4.29 +includes=**
    4.30 +jar.compress=false
    4.31 +javac.classpath=
    4.32 +# Space-separated list of extra javac options
    4.33 +javac.compilerargs=
    4.34 +javac.deprecation=false
    4.35 +javac.source=1.5
    4.36 +javac.target=1.5
    4.37 +javac.test.classpath=\
    4.38 +    ${javac.classpath}:\
    4.39 +    ${build.classes.dir}:\
    4.40 +    ${file.reference.junit-4.4.jar}
    4.41 +javadoc.additionalparam=
    4.42 +javadoc.author=false
    4.43 +javadoc.encoding=
    4.44 +javadoc.noindex=false
    4.45 +javadoc.nonavbar=false
    4.46 +javadoc.notree=false
    4.47 +javadoc.private=false
    4.48 +javadoc.splitindex=true
    4.49 +javadoc.use=true
    4.50 +javadoc.version=false
    4.51 +javadoc.windowtitle=
    4.52 +jnlp.codebase.type=local
    4.53 +jnlp.codebase.url=file:/home/jarda/src/apifest08/currency/dist
    4.54 +jnlp.descriptor=application
    4.55 +jnlp.enabled=false
    4.56 +jnlp.offline-allowed=false
    4.57 +jnlp.signed=false
    4.58 +meta.inf.dir=${src.dir}/META-INF
    4.59 +platform.active=default_platform
    4.60 +run.classpath=\
    4.61 +    ${javac.classpath}:\
    4.62 +    ${build.classes.dir}
    4.63 +# Space-separated list of JVM arguments used when running the project
    4.64 +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
    4.65 +# or test-sys-prop.name=value to set system properties for unit tests):
    4.66 +run.jvmargs=
    4.67 +run.test.classpath=\
    4.68 +    ${javac.test.classpath}:\
    4.69 +    ${build.test.classes.dir}
    4.70 +src.dir=src
    4.71 +test.src.dir=test
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/task3/solution02/nbproject/project.xml	Tue Oct 07 11:05:34 2008 +0200
     5.3 @@ -0,0 +1,16 @@
     5.4 +<?xml version="1.0" encoding="UTF-8"?>
     5.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
     5.6 +    <type>org.netbeans.modules.java.j2seproject</type>
     5.7 +    <configuration>
     5.8 +        <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
     5.9 +            <name>Currency Convertor Solution 02</name>
    5.10 +            <minimum-ant-version>1.6.5</minimum-ant-version>
    5.11 +            <source-roots>
    5.12 +                <root id="src.dir"/>
    5.13 +            </source-roots>
    5.14 +            <test-roots>
    5.15 +                <root id="test.src.dir"/>
    5.16 +            </test-roots>
    5.17 +        </data>
    5.18 +    </configuration>
    5.19 +</project>
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/task3/solution02/src/org/apidesign/apifest08/currency/CompositeConvertor.java	Tue Oct 07 11:05:34 2008 +0200
     6.3 @@ -0,0 +1,75 @@
     6.4 +package org.apidesign.apifest08.currency;
     6.5 +
     6.6 +import java.io.Serializable;
     6.7 +import java.util.Arrays;
     6.8 +import java.util.Currency;
     6.9 +
    6.10 +/**
    6.11 + * Convertor that is composed from other convertors. 
    6.12 + * @author lukas
    6.13 + *
    6.14 + */
    6.15 +class CompositeConvertor implements ExtendedConvertor, Serializable {
    6.16 +
    6.17 +	private static final long serialVersionUID = -2702026568249130055L;
    6.18 +	
    6.19 +	private final ExtendedConvertor[] convertors;
    6.20 +
    6.21 +
    6.22 +	public CompositeConvertor(ExtendedConvertor... convertors) {
    6.23 +		this.convertors = convertors.clone();
    6.24 +		for (ExtendedConvertor convertor: this.convertors)
    6.25 +		{
    6.26 +			if (convertor==null)
    6.27 +			{
    6.28 +				throw new NullPointerException("One of the convertors to be merged is null");
    6.29 +			}
    6.30 +		}
    6.31 +	}
    6.32 +
    6.33 +	/**
    6.34 +	 * Returns true if the composite contains convertor that supports given conversion.
    6.35 +	 */
    6.36 +	public boolean isConversionSupported(Currency from, Currency to) {
    6.37 +		return findConvertorFor(from, to)!=null;
    6.38 +	}
    6.39 +
    6.40 +
    6.41 +	/**
    6.42 +	 * If the composite contains convertor that supports given conversion, delegates to its convert method.
    6.43 +	 * Throws {@link IllegalArgumentException} convertor supporting given conversion is not found. 
    6.44 +	 */
    6.45 +	public Money convert(Money amount, Currency destinationCurrency) throws IllegalArgumentException {
    6.46 +		ExtendedConvertor convertor = findConvertorFor(amount.getCurrency(), destinationCurrency);
    6.47 +		if (convertor!=null)
    6.48 +		{
    6.49 +			return convertor.convert(amount, destinationCurrency);
    6.50 +		}
    6.51 +		throw new IllegalArgumentException("Conversion not supported. Can not convert to "+destinationCurrency+".");
    6.52 +	}
    6.53 +	
    6.54 +	/**
    6.55 +	 * Finds convertor for given currencies. If not found, returns null. 
    6.56 +	 * @param from
    6.57 +	 * @param to
    6.58 +	 * @return
    6.59 +	 */
    6.60 +	ExtendedConvertor findConvertorFor(Currency from, Currency to) {
    6.61 +		//does linear search, in the future can cache the results.
    6.62 +		for (ExtendedConvertor convertor:convertors)
    6.63 +		{
    6.64 +			if (convertor.isConversionSupported(from, to))
    6.65 +			{
    6.66 +				return convertor;
    6.67 +			}
    6.68 +		}
    6.69 +		return null;
    6.70 +	}
    6.71 +	
    6.72 +
    6.73 +	@Override
    6.74 +	public String toString() {
    6.75 +		return getClass().getName()+" converts "+Arrays.toString(convertors);
    6.76 +	}
    6.77 +
    6.78 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/task3/solution02/src/org/apidesign/apifest08/currency/Convertor.java	Tue Oct 07 11:05:34 2008 +0200
     7.3 @@ -0,0 +1,18 @@
     7.4 +package org.apidesign.apifest08.currency;
     7.5 +
     7.6 +import java.util.Currency;
     7.7 +
     7.8 +
     7.9 +/** 
    7.10 + * Converts currencies. To create an instance call {@link ConvertorFactory#createConvertor(Money, Money)}.
    7.11 + */
    7.12 +public interface Convertor {
    7.13 +	/**
    7.14 +	 * Converts amount to its equivalent in the destination currency. 
    7.15 +	 * @param amount 
    7.16 +	 * @param destinationCurrency
    7.17 +	 * @return
    7.18 +	 * @throws IllegalArgumentException if currency of the amount is not supported or if it is not possible to convert it to the destination currency.
    7.19 +	 */
    7.20 +	public Money convert(Money amount, Currency destinationCurrency) throws IllegalArgumentException;
    7.21 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/task3/solution02/src/org/apidesign/apifest08/currency/ConvertorFactory.java	Tue Oct 07 11:05:34 2008 +0200
     8.3 @@ -0,0 +1,46 @@
     8.4 +package org.apidesign.apifest08.currency;
     8.5 +
     8.6 +
     8.7 +
     8.8 +/**
     8.9 + * Creates {@link Convertor} implementations.
    8.10 + * @author lukas
    8.11 + *
    8.12 + */
    8.13 +public class ConvertorFactory {
    8.14 +	private ConvertorFactory()
    8.15 +	{
    8.16 +		//nothing
    8.17 +	}
    8.18 +		
    8.19 +	/**
    8.20 +	 * Creates {@link Convertor} that converts from sourceEquivalent.currency to destinationEquivalent.currency. 
    8.21 +	 * Exchange rate is set as equivalents. It means if you want to create USD to CZK convertor where USD1 = CZK17 
    8.22 +     * call createConvertor(new MoneyImpl(1, USD), new MoneyImpl(17, CZK)). Convertor created by this method 
    8.23 +     * rounds the result to two decimal places.
    8.24 +	 * @param sourceEquivalent
    8.25 +	 * @param destinationEquivalent
    8.26 +	 * @return
    8.27 +	 */
    8.28 +	public static final ExtendedConvertor createConvertor(Money sourceEquivalent, Money destinationEquivalent)
    8.29 +	{
    8.30 +		return mergeConvertors(
    8.31 +				new DefaultConvertor(sourceEquivalent, destinationEquivalent),
    8.32 +				new DefaultConvertor(destinationEquivalent ,sourceEquivalent)
    8.33 +		);
    8.34 +	}
    8.35 +	
    8.36 +	/**
    8.37 +	 * Merges convertors. The resulting convertor has ability to do all conversions that its underlying 
    8.38 +	 * convertors could do. No consistency validation is done, inconsistent input will result in a convertor with
    8.39 +	 * inconsistent behavior.
    8.40 +	 * @param convertors
    8.41 +	 * @return
    8.42 +	 */
    8.43 +	public static final ExtendedConvertor mergeConvertors(ExtendedConvertor... convertors)
    8.44 +	{
    8.45 +		return new CompositeConvertor(convertors);
    8.46 +	}
    8.47 +	
    8.48 +
    8.49 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/task3/solution02/src/org/apidesign/apifest08/currency/DefaultConvertor.java	Tue Oct 07 11:05:34 2008 +0200
     9.3 @@ -0,0 +1,95 @@
     9.4 +package org.apidesign.apifest08.currency;
     9.5 +
     9.6 +import java.io.Serializable;
     9.7 +import java.math.BigDecimal;
     9.8 +import java.math.RoundingMode;
     9.9 +import java.util.Currency;
    9.10 +
    9.11 +/**
    9.12 + * Default {@link Convertor} implementation. Exchange rate is stored as equivalents. It means if we have USD to CZK convertor and USD1 = CZK17 
    9.13 + * we store 1 in sourceEquivalent and 17 in destinationEquivalent. This class is immutable.
    9.14 + * @author lukas
    9.15 + *
    9.16 + */
    9.17 +class DefaultConvertor implements ExtendedConvertor, Serializable {
    9.18 +
    9.19 +	private static final long serialVersionUID = 6660014633685135034L;
    9.20 +
    9.21 +	/**
    9.22 +	 * Equivalent in source currency.
    9.23 +	 */
    9.24 +	private final BigDecimal sourceEquivalent;
    9.25 +	
    9.26 +	/**
    9.27 +	 * Equivalent in destination currency.
    9.28 +	 */
    9.29 +	private final BigDecimal destinationEquivalent;
    9.30 +	
    9.31 +	private final Currency sourceCurrency;
    9.32 +	
    9.33 +	private final Currency destinationCurrency;
    9.34 +	
    9.35 +	public DefaultConvertor(Money sourceEquivalent, Money destinationEquivalent) {
    9.36 +		super();
    9.37 +		if (BigDecimal.ZERO.compareTo(sourceEquivalent.getAmount())==0)
    9.38 +		{
    9.39 +			throw new IllegalArgumentException("Source equivalent amount can not be 0.");
    9.40 +		}
    9.41 +		if (BigDecimal.ZERO.compareTo(destinationEquivalent.getAmount())==0)
    9.42 +		{
    9.43 +			throw new IllegalArgumentException("Destination equivalent amount can not be 0.");
    9.44 +		}
    9.45 +		this.sourceEquivalent = sourceEquivalent.getAmount();
    9.46 +		this.destinationEquivalent = destinationEquivalent.getAmount();
    9.47 +		this.sourceCurrency = sourceEquivalent.getCurrency();
    9.48 +		this.destinationCurrency = destinationEquivalent.getCurrency();
    9.49 +	}
    9.50 +	
    9.51 +	public Money convert(Money amount, Currency destinationCurrency) {
    9.52 +		if (amount==null)
    9.53 +		{
    9.54 +			throw new NullPointerException("Money is null");
    9.55 +		}
    9.56 +		if (destinationCurrency==null)
    9.57 +		{
    9.58 +			throw new NullPointerException("destionationCurrency is null");
    9.59 +		}
    9.60 +		if (!amount.getCurrency().equals(getSourceCurrency()))
    9.61 +		{
    9.62 +			throw new IllegalArgumentException("Can not convert from "+amount.getCurrency()+". Converts between "+getSourceCurrency()+" and "+getDestinationCurrency());
    9.63 +		}
    9.64 +		if (!getDestinationCurrency().equals(destinationCurrency))
    9.65 +		{
    9.66 +			throw new IllegalArgumentException("Can not convert to "+destinationCurrency+". Converts between "+getSourceCurrency()+" and "+getDestinationCurrency());
    9.67 +		}
    9.68 +		BigDecimal sourceAmount = amount.getAmount();
    9.69 +		BigDecimal destinationAmount = sourceAmount.multiply(destinationEquivalent).divide(sourceEquivalent, 2, RoundingMode.HALF_UP);
    9.70 +		return new MoneyImpl(destinationAmount, getDestinationCurrency());
    9.71 +	}
    9.72 +	
    9.73 +	public boolean isConversionSupported(Currency from, Currency to) {
    9.74 +		return sourceCurrency.equals(from) && destinationCurrency.equals(to);
    9.75 +	}
    9.76 +
    9.77 +	public BigDecimal getSourceEquivalent() {
    9.78 +		return sourceEquivalent;
    9.79 +	}
    9.80 +
    9.81 +	public BigDecimal getDestinationEquivalent() {
    9.82 +		return destinationEquivalent;
    9.83 +	}
    9.84 +
    9.85 +	public Currency getSourceCurrency() {
    9.86 +		return sourceCurrency;
    9.87 +	}
    9.88 +
    9.89 +	public Currency getDestinationCurrency() {
    9.90 +		return destinationCurrency;
    9.91 +	}
    9.92 +	
    9.93 +	@Override
    9.94 +	public String toString() {
    9.95 +		return getClass().getName()+" converts "+getSourceCurrency()+" to "+getDestinationCurrency()+" "
    9.96 +			+getSourceCurrency()+getSourceEquivalent()+"="+getDestinationCurrency()+getDestinationEquivalent();
    9.97 +	}
    9.98 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/task3/solution02/src/org/apidesign/apifest08/currency/ExtendedConvertor.java	Tue Oct 07 11:05:34 2008 +0200
    10.3 @@ -0,0 +1,18 @@
    10.4 +package org.apidesign.apifest08.currency;
    10.5 +
    10.6 +import java.util.Currency;
    10.7 +
    10.8 +/**
    10.9 + * Extended convertor interface. 
   10.10 + * @author lukas
   10.11 + *
   10.12 + */
   10.13 +public interface ExtendedConvertor extends Convertor {
   10.14 +	/**
   10.15 +	 * Returns true if given conversion is supported.
   10.16 +	 * @param from
   10.17 +	 * @param to
   10.18 +	 * @return
   10.19 +	 */
   10.20 +	public boolean isConversionSupported(Currency from, Currency to);
   10.21 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/task3/solution02/src/org/apidesign/apifest08/currency/Money.java	Tue Oct 07 11:05:34 2008 +0200
    11.3 @@ -0,0 +1,29 @@
    11.4 +package org.apidesign.apifest08.currency;
    11.5 +
    11.6 +import java.math.BigDecimal;
    11.7 +import java.util.Currency;
    11.8 +
    11.9 +/**
   11.10 + * Money representation. Default implementation {@link MoneyImpl} is provided. This interface can
   11.11 + * be implemented by a DTO used in client application.
   11.12 + * @author lukas
   11.13 + *
   11.14 + */
   11.15 +/*
   11.16 + * Whether we need such interface depends on the context. I can imagine than in a desktop application this interface 
   11.17 + * would be useless, Money could be a class. In J2EE environment it can be useful.
   11.18 + */
   11.19 +public interface Money {
   11.20 +
   11.21 +	/**
   11.22 +	 * Returns amount.
   11.23 +	 * @return
   11.24 +	 */
   11.25 +	public BigDecimal getAmount();
   11.26 +
   11.27 +	/**
   11.28 +	 * Returns currency.
   11.29 +	 */
   11.30 +	public Currency getCurrency();
   11.31 +
   11.32 +}
   11.33 \ No newline at end of file
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/task3/solution02/src/org/apidesign/apifest08/currency/MoneyImpl.java	Tue Oct 07 11:05:34 2008 +0200
    12.3 @@ -0,0 +1,121 @@
    12.4 +package org.apidesign.apifest08.currency;
    12.5 +
    12.6 +import java.io.Serializable;
    12.7 +import java.math.BigDecimal;
    12.8 +import java.util.Currency;
    12.9 +
   12.10 +/**
   12.11 + * Default implementation of {@link Money} interface. This class is immutable.
   12.12 + * @author lukas
   12.13 + *
   12.14 + */
   12.15 +public final class MoneyImpl implements Serializable, Money{
   12.16 +	private static final long serialVersionUID = -6091808475616516136L;
   12.17 +
   12.18 +	private final BigDecimal amount;
   12.19 +	
   12.20 +	private final Currency currency;
   12.21 +	
   12.22 +	public MoneyImpl(BigDecimal amount, Currency currency) {
   12.23 +		if (amount==null) throw new NullPointerException("Amount is null");
   12.24 +		if (currency==null) throw new NullPointerException("Currency is null"+currency);
   12.25 +		this.amount = amount;
   12.26 +		this.currency = currency;
   12.27 +	}
   12.28 +	
   12.29 +	
   12.30 +	
   12.31 +	public MoneyImpl(long amount, Currency currency) {
   12.32 +		this(BigDecimal.valueOf(amount), currency);
   12.33 +	}
   12.34 +	
   12.35 +	public MoneyImpl(double amount, Currency currency) {
   12.36 +		this(BigDecimal.valueOf(amount), currency);
   12.37 +	}
   12.38 +	
   12.39 +	/**
   12.40 +	 * Factory method.
   12.41 +	 * @param amount
   12.42 +	 * @param currency
   12.43 +	 * @return
   12.44 +	 */
   12.45 +	public static final Money money(BigDecimal amount, Currency currency)
   12.46 +	{
   12.47 +		return new MoneyImpl(amount, currency);
   12.48 +	}
   12.49 +	/**
   12.50 +	 * Factory method.
   12.51 +	 * @param amount
   12.52 +	 * @param currency
   12.53 +	 * @return
   12.54 +	 */
   12.55 +	public static final Money money(long amount, Currency currency)
   12.56 +	{
   12.57 +		return new MoneyImpl(amount, currency);
   12.58 +	}
   12.59 +	/**
   12.60 +	 * Factory method.
   12.61 +	 * @param amount
   12.62 +	 * @param currency
   12.63 +	 * @return
   12.64 +	 */
   12.65 +	public static final Money money(double amount, Currency currency)
   12.66 +	{
   12.67 +		return new MoneyImpl(amount, currency);
   12.68 +	}
   12.69 +
   12.70 +	/**
   12.71 +	 * Returns amount.
   12.72 +	 * @return
   12.73 +	 */
   12.74 +	public BigDecimal getAmount() {
   12.75 +		return amount;
   12.76 +	}
   12.77 +	
   12.78 +	/**
   12.79 +	 * Returns currency.
   12.80 +	 */
   12.81 +	public Currency getCurrency() {
   12.82 +		return currency;
   12.83 +	}
   12.84 +
   12.85 +	@Override
   12.86 +	public int hashCode() {
   12.87 +		final int prime = 31;
   12.88 +		int result = 1;
   12.89 +		result = prime * result + ((amount == null) ? 0 : amount.hashCode());
   12.90 +		result = prime * result
   12.91 +				+ ((currency == null) ? 0 : currency.hashCode());
   12.92 +		return result;
   12.93 +	}
   12.94 +
   12.95 +	@Override
   12.96 +	public boolean equals(Object obj) {
   12.97 +		if (this == obj)
   12.98 +			return true;
   12.99 +		if (obj == null)
  12.100 +			return false;
  12.101 +		if (!(obj instanceof MoneyImpl))
  12.102 +			return false;
  12.103 +		MoneyImpl other = (MoneyImpl) obj;
  12.104 +		if (amount == null) {
  12.105 +			if (other.amount != null)
  12.106 +				return false;
  12.107 +		} else if (amount.compareTo(other.amount)!=0)
  12.108 +			return false;
  12.109 +		if (currency == null) {
  12.110 +			if (other.currency != null)
  12.111 +				return false;
  12.112 +		} else if (!currency.equals(other.currency))
  12.113 +			return false;
  12.114 +		return true;
  12.115 +	}
  12.116 +	
  12.117 +	@Override
  12.118 +	public String toString() {
  12.119 +		return getClass().getName()+"["+currency+amount+"]";
  12.120 +	}
  12.121 +
  12.122 +	
  12.123 +	
  12.124 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/task3/solution02/test/org/apidesign/apifest08/currency/CompositeConvertorTest.java	Tue Oct 07 11:05:34 2008 +0200
    13.3 @@ -0,0 +1,56 @@
    13.4 +package org.apidesign.apifest08.currency;
    13.5 +
    13.6 +import static junit.framework.Assert.assertEquals;
    13.7 +import static junit.framework.Assert.assertFalse;
    13.8 +import static junit.framework.Assert.assertTrue;
    13.9 +import static junit.framework.Assert.fail;
   13.10 +import static org.apidesign.apifest08.test.Task1Test.CZK;
   13.11 +import static org.apidesign.apifest08.test.Task1Test.SKK;
   13.12 +import static org.apidesign.apifest08.test.Task1Test.USD;
   13.13 +
   13.14 +import org.junit.Test;
   13.15 +
   13.16 +public class CompositeConvertorTest {
   13.17 +	private static final ExtendedConvertor USD_CZK_CONVERTOR = ConvertorFactory.createConvertor(new MoneyImpl(1,USD), new MoneyImpl(17,CZK));
   13.18 +	private static final ExtendedConvertor SKK_CZK_CONVERTOR = ConvertorFactory.createConvertor(new MoneyImpl(100,SKK), new MoneyImpl(80,CZK));
   13.19 +
   13.20 +	@Test
   13.21 +	public void testCompose()
   13.22 +	{
   13.23 +		ExtendedConvertor convertor = new CompositeConvertor(USD_CZK_CONVERTOR, SKK_CZK_CONVERTOR);
   13.24 +		assertTrue(convertor.isConversionSupported(CZK, SKK));
   13.25 +		assertTrue(convertor.isConversionSupported(CZK, USD));
   13.26 +		assertFalse(convertor.isConversionSupported(SKK, USD));
   13.27 +		assertEquals(new MoneyImpl(10,SKK), convertor.convert(new MoneyImpl(8,CZK), SKK));
   13.28 +		assertEquals(new MoneyImpl(2,USD), convertor.convert(new MoneyImpl(34,CZK), USD));
   13.29 +		try
   13.30 +		{
   13.31 +			convertor.convert(new MoneyImpl(34,SKK), USD);
   13.32 +			fail("Exception expected");
   13.33 +		}
   13.34 +		catch(IllegalArgumentException e)
   13.35 +		{
   13.36 +			assertTrue("Ok", true);
   13.37 +		}
   13.38 +	}
   13.39 +	@Test
   13.40 +	public void testEmpty()
   13.41 +	{
   13.42 +		ExtendedConvertor convertor = new CompositeConvertor();
   13.43 +		assertFalse(convertor.isConversionSupported(SKK, USD));
   13.44 +		try
   13.45 +		{
   13.46 +			convertor.convert(new MoneyImpl(34,SKK), USD);
   13.47 +			fail("Exception expected");
   13.48 +		}
   13.49 +		catch(IllegalArgumentException e)
   13.50 +		{
   13.51 +			assertTrue("Ok", true);
   13.52 +		}
   13.53 +	}
   13.54 +	@Test(expected=NullPointerException.class)
   13.55 +	public void testCreateNull()
   13.56 +	{
   13.57 +		new CompositeConvertor(USD_CZK_CONVERTOR, null);
   13.58 +	}
   13.59 +}
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/task3/solution02/test/org/apidesign/apifest08/test/ConvertorFactoryTest.java	Tue Oct 07 11:05:34 2008 +0200
    14.3 @@ -0,0 +1,52 @@
    14.4 +package org.apidesign.apifest08.test;
    14.5 +
    14.6 +import static junit.framework.Assert.assertNotNull;
    14.7 +import static org.apidesign.apifest08.test.Task1Test.CZK;
    14.8 +import static org.apidesign.apifest08.test.Task1Test.USD;
    14.9 +import static org.junit.Assert.assertEquals;
   14.10 +import static org.junit.Assert.assertTrue;
   14.11 +import static org.junit.Assert.fail;
   14.12 +
   14.13 +import org.apidesign.apifest08.currency.Convertor;
   14.14 +import org.apidesign.apifest08.currency.ConvertorFactory;
   14.15 +import org.apidesign.apifest08.currency.MoneyImpl;
   14.16 +import org.junit.Test;
   14.17 +
   14.18 +
   14.19 +public class ConvertorFactoryTest {
   14.20 +	@Test(expected=NullPointerException.class)
   14.21 +	public void testNullSource()
   14.22 +	{
   14.23 +		ConvertorFactory.createConvertor(null, new MoneyImpl(1,USD));
   14.24 +	}
   14.25 +	@Test(expected=NullPointerException.class)
   14.26 +	public void testNullDestination()
   14.27 +	{
   14.28 +		ConvertorFactory.createConvertor(new MoneyImpl(17,CZK), null);
   14.29 +	}
   14.30 +	@Test
   14.31 +	public void testOk()
   14.32 +	{
   14.33 +		assertNotNull(ConvertorFactory.createConvertor(new MoneyImpl(17,CZK),  new MoneyImpl(1,USD)));
   14.34 +	}
   14.35 +	@Test
   14.36 +	public void testOkDecimalRate()
   14.37 +	{
   14.38 +		Convertor c = ConvertorFactory.createConvertor(new MoneyImpl(1,CZK),  new MoneyImpl(1d/17d,USD));
   14.39 +		assertNotNull(c);
   14.40 +		assertEquals(new MoneyImpl(17,CZK),c.convert(new MoneyImpl(1,USD), CZK));
   14.41 +	}
   14.42 +	@Test
   14.43 +	public void testZeroEquivalentRate()
   14.44 +	{
   14.45 +		try
   14.46 +		{
   14.47 +			ConvertorFactory.createConvertor(new MoneyImpl(1,CZK),  new MoneyImpl(0,USD));
   14.48 +			fail("Exception expected");
   14.49 +		}
   14.50 +		catch(IllegalArgumentException e)
   14.51 +		{
   14.52 +			assertTrue("OK",true);
   14.53 +		}
   14.54 +	}
   14.55 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/task3/solution02/test/org/apidesign/apifest08/test/ConvertorTest.java	Tue Oct 07 11:05:34 2008 +0200
    15.3 @@ -0,0 +1,44 @@
    15.4 +package org.apidesign.apifest08.test;
    15.5 +
    15.6 +import static junit.framework.Assert.assertEquals;
    15.7 +import static junit.framework.Assert.assertFalse;
    15.8 +import static junit.framework.Assert.assertTrue;
    15.9 +import static org.apidesign.apifest08.test.Task1Test.CZK;
   15.10 +import static org.apidesign.apifest08.test.Task1Test.SKK;
   15.11 +import static org.apidesign.apifest08.test.Task1Test.USD;
   15.12 +
   15.13 +import java.math.BigDecimal;
   15.14 +
   15.15 +import org.apidesign.apifest08.currency.ConvertorFactory;
   15.16 +import org.apidesign.apifest08.currency.ExtendedConvertor;
   15.17 +import org.apidesign.apifest08.currency.Money;
   15.18 +import org.apidesign.apifest08.currency.MoneyImpl;
   15.19 +import org.junit.Test;
   15.20 +
   15.21 +
   15.22 +public class ConvertorTest {
   15.23 +
   15.24 +	private static final ExtendedConvertor CZK_TO_USD_CONVERTOR = ConvertorFactory.createConvertor(new MoneyImpl(17,CZK), new MoneyImpl(1,USD));
   15.25 +	@Test
   15.26 +	public void testConvertSmall()
   15.27 +	{
   15.28 +		Money converted = CZK_TO_USD_CONVERTOR.convert(new MoneyImpl(0.17,CZK),USD);
   15.29 +		assertEquals(new MoneyImpl(new BigDecimal("0.01"),USD),converted);
   15.30 +		assertEquals(USD,converted.getCurrency());
   15.31 +	}
   15.32 +	@Test
   15.33 +	public void testConvertSmallReverse()
   15.34 +	{
   15.35 +		Money converted = CZK_TO_USD_CONVERTOR.convert(new MoneyImpl(0.01,USD),CZK);
   15.36 +		assertEquals(new MoneyImpl(new BigDecimal("0.17"),CZK),converted);
   15.37 +	}
   15.38 +	@Test
   15.39 +	public void testSupports()
   15.40 +	{
   15.41 +		assertTrue(CZK_TO_USD_CONVERTOR.isConversionSupported(USD,CZK));
   15.42 +		assertTrue(CZK_TO_USD_CONVERTOR.isConversionSupported(CZK,USD));
   15.43 +		assertFalse(CZK_TO_USD_CONVERTOR.isConversionSupported(CZK,CZK));
   15.44 +		assertFalse(CZK_TO_USD_CONVERTOR.isConversionSupported(CZK,SKK));
   15.45 +		
   15.46 +	}
   15.47 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/task3/solution02/test/org/apidesign/apifest08/test/MoneyTest.java	Tue Oct 07 11:05:34 2008 +0200
    16.3 @@ -0,0 +1,24 @@
    16.4 +package org.apidesign.apifest08.test;
    16.5 +
    16.6 +import static junit.framework.Assert.assertEquals;
    16.7 +import static org.apidesign.apifest08.test.Task1Test.CZK;
    16.8 +
    16.9 +import java.math.BigDecimal;
   16.10 +
   16.11 +import org.apidesign.apifest08.currency.MoneyImpl;
   16.12 +import org.junit.Test;
   16.13 +
   16.14 +public class MoneyTest {
   16.15 +	@Test(expected=NullPointerException.class)
   16.16 +	public void testNullAmount(){
   16.17 +		new MoneyImpl(null,CZK);
   16.18 +	}
   16.19 +	@Test(expected=NullPointerException.class)
   16.20 +	public void testNullCurrency(){
   16.21 +		new MoneyImpl(1,null);
   16.22 +	}
   16.23 +	@Test
   16.24 +	public void testOk(){
   16.25 +		assertEquals(0,new MoneyImpl(123,CZK).getAmount().compareTo(new BigDecimal("123")));
   16.26 +	}
   16.27 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/task3/solution02/test/org/apidesign/apifest08/test/Task1Test.java	Tue Oct 07 11:05:34 2008 +0200
    17.3 @@ -0,0 +1,160 @@
    17.4 +package org.apidesign.apifest08.test;
    17.5 +
    17.6 +import java.util.Currency;
    17.7 +
    17.8 +import junit.framework.TestCase;
    17.9 +
   17.10 +import org.apidesign.apifest08.currency.Convertor;
   17.11 +import org.apidesign.apifest08.currency.ConvertorFactory;
   17.12 +import org.apidesign.apifest08.currency.MoneyImpl;
   17.13 +
   17.14 +/** Finish the Convertor API, and then write bodies of methods inside
   17.15 + * of this class to match the given tasks. To fullfil your task, use the
   17.16 + * API define in the <code>org.apidesign.apifest08.currency</code> package.
   17.17 + * Do not you reflection, or other hacks as your code
   17.18 + * shall run without any runtime permissions.
   17.19 + */
   17.20 +public class Task1Test extends TestCase {
   17.21 +	
   17.22 +	public static final Currency USD = Currency.getInstance("USD");
   17.23 +	public static final Currency CZK = Currency.getInstance("CZK");
   17.24 +	public static final Currency SKK = Currency.getInstance("SKK");
   17.25 +	
   17.26 +    public Task1Test(String testName) {
   17.27 +        super(testName);
   17.28 +    }
   17.29 +
   17.30 +    @Override
   17.31 +    protected void setUp() throws Exception {
   17.32 +    }
   17.33 +
   17.34 +    @Override
   17.35 +    protected void tearDown() throws Exception {
   17.36 +    }
   17.37 +
   17.38 +    //
   17.39 +    // Imagine that there are three parts of the whole system:
   17.40 +    // 1. there is someone who knows the current exchange rate
   17.41 +    // 2. there is someone who wants to do the conversion
   17.42 +    // 3. there is the API between 1. and 2. which allows them to communicate
   17.43 +    // Please design such API
   17.44 +    //
   17.45 +
   17.46 +    /** Create convertor that understands two currencies, CZK and
   17.47 +     *  USD. Make 1 USD == 17 CZK. This is a method provided for #1 group -
   17.48 +     *  e.g. those that know the exchange rate. They somehow need to create
   17.49 +     *  the objects from the API and tell them the exchange rate. The API itself
   17.50 +     *  knows nothing about any rates, before the createCZKtoUSD method is called.
   17.51 +     *
   17.52 +     * Creation of the convertor shall not require subclassing of any class
   17.53 +     * or interface on the client side.
   17.54 +     *
   17.55 +     * @return prepared convertor ready for converting USD to CZK and CZK to USD
   17.56 +     */
   17.57 +    public static Convertor createCZKtoUSD() {
   17.58 +    	return ConvertorFactory.createConvertor(new MoneyImpl(17,CZK), new MoneyImpl(1,USD));
   17.59 +    }
   17.60 +
   17.61 +    /** Create convertor that understands two currencies, CZK and
   17.62 +     *  SKK. Make 100 SKK == 80 CZK. Again this is method for the #1 group -
   17.63 +     *  it knows the exchange rate, and needs to use the API to create objects
   17.64 +     *  with the exchange rate. Anyone shall be ready to call this method without
   17.65 +     *  any other method being called previously. The API itself shall know
   17.66 +     *  nothing about any rates, before this method is called.
   17.67 +     *
   17.68 +     * Creation of the convertor shall not require subclassing of any class
   17.69 +     * or interface on the client side.
   17.70 +     * 
   17.71 +     * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
   17.72 +     */
   17.73 +    public static Convertor createSKKtoCZK() {
   17.74 +    	return ConvertorFactory.createConvertor(new MoneyImpl(100,SKK), new MoneyImpl(80,CZK));
   17.75 +    }
   17.76 +
   17.77 +    //
   17.78 +    // now the methods for group #2 follow:
   17.79 +    // this group knows nothing about exchange rates, but knows how to use
   17.80 +    // the API to do conversions. It somehow (by calling one of the factory
   17.81 +    // methods) gets objects from the API and uses them to do the conversions.
   17.82 +    //
   17.83 +    
   17.84 +    /** Use the convertor from <code>createCZKtoUSD</code> method and do few conversions
   17.85 +     * with it.
   17.86 +     */
   17.87 +    public void testCurrencyCZKUSD() throws Exception {
   17.88 +    	Convertor c = createCZKtoUSD();
   17.89 +        // convert $5 to CZK using c:
   17.90 +        assertEquals("Result is 85 CZK",new MoneyImpl(85,CZK), c.convert(new MoneyImpl(5,USD),CZK));
   17.91 +
   17.92 +        // convert $8 to CZK
   17.93 +        assertEquals("Result is 136 CZK",new MoneyImpl(136,CZK), c.convert(new MoneyImpl(8,USD),CZK));
   17.94 +
   17.95 +        // convert 1003CZK to USD
   17.96 +        assertEquals("Result is 59 USD", new MoneyImpl(59,USD), c.convert(new MoneyImpl(1003,CZK),USD));
   17.97 +        
   17.98 +    }
   17.99 +
  17.100 +    /** Use the convertor from <code>createSKKtoCZK</code> method and do few conversions
  17.101 +     * with it.
  17.102 +     */
  17.103 +    public void testCurrencySKKCZK() throws Exception {
  17.104 +        Convertor c = createSKKtoCZK();
  17.105 +        // convert 16CZK using c:
  17.106 +        assertEquals("Result is 20 SKK", new MoneyImpl(20,SKK), c.convert(new MoneyImpl(16,CZK),SKK));
  17.107 +
  17.108 +        // convert 500SKK to CZK
  17.109 +        assertEquals("Result is 400 CZK", new MoneyImpl(400,CZK), c.convert(new MoneyImpl(500,SKK),CZK));
  17.110 +    }
  17.111 +
  17.112 +    /** Verify that the CZK to USD convertor knows nothing about SKK.
  17.113 +     */
  17.114 +    public void testCannotConvertToSKKwithCZKUSDConvertor() throws Exception {
  17.115 +        Convertor c = createCZKtoUSD();
  17.116 +        // convert $5 to SKK, the API shall say this is not possible
  17.117 +        try
  17.118 +        {
  17.119 +        	c.convert(new MoneyImpl(5, USD), SKK);
  17.120 +        	fail("Exception expected");
  17.121 +        }
  17.122 +        catch(IllegalArgumentException e)
  17.123 +        {
  17.124 +        	assertTrue("Ok",true);
  17.125 +        }
  17.126 +        // convert 500 SKK to CZK, the API shall say this is not possible
  17.127 +        try
  17.128 +        {
  17.129 +        	c.convert(new MoneyImpl(500, SKK), CZK);
  17.130 +        	fail("Exception expected");
  17.131 +        }
  17.132 +        catch(IllegalArgumentException e)
  17.133 +        {
  17.134 +        	assertTrue("Ok",true);
  17.135 +        }
  17.136 +    }
  17.137 +
  17.138 +    /** Verify that the CZK to SKK convertor knows nothing about USD.
  17.139 +     */
  17.140 +    public void testCannotConvertToUSDwithCZKSKKConvertor() throws Exception {
  17.141 +        Convertor c = createSKKtoCZK();
  17.142 +        // convert $5 to SKK, the API shall say this is not possible
  17.143 +        try
  17.144 +        {
  17.145 +        	c.convert(new MoneyImpl(5, USD), SKK);
  17.146 +        	fail("Exception expected");
  17.147 +        }
  17.148 +        catch(IllegalArgumentException e)
  17.149 +        {
  17.150 +        	assertTrue("Ok",true);
  17.151 +        }
  17.152 +        // convert 500 CZK to USD, the API shall say this is not possible
  17.153 +        try
  17.154 +        {
  17.155 +        	c.convert(new MoneyImpl(500, CZK), USD);
  17.156 +        	fail("Exception expected");
  17.157 +        }
  17.158 +        catch(IllegalArgumentException e)
  17.159 +        {
  17.160 +        	assertTrue("Ok",true);
  17.161 +        }
  17.162 +    }
  17.163 +}
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/task3/solution02/test/org/apidesign/apifest08/test/Task2Test.java	Tue Oct 07 11:05:34 2008 +0200
    18.3 @@ -0,0 +1,119 @@
    18.4 +package org.apidesign.apifest08.test;
    18.5 +
    18.6 +import static org.apidesign.apifest08.currency.ConvertorFactory.createConvertor;
    18.7 +import static org.apidesign.apifest08.currency.ConvertorFactory.mergeConvertors;
    18.8 +import static org.apidesign.apifest08.currency.MoneyImpl.money;
    18.9 +import static org.apidesign.apifest08.test.Task1Test.CZK;
   18.10 +import static org.apidesign.apifest08.test.Task1Test.SKK;
   18.11 +import static org.apidesign.apifest08.test.Task1Test.USD;
   18.12 +import junit.framework.TestCase;
   18.13 +
   18.14 +import org.apidesign.apifest08.currency.Convertor;
   18.15 +import org.apidesign.apifest08.currency.ExtendedConvertor;
   18.16 +
   18.17 +/** There are many currencies around the world and many banks manipulate
   18.18 + * with more than one or two at the same time. As banks are usually the
   18.19 + * best paying clients, which is true even in case of your Convertor API,
   18.20 + * it is reasonable to listen to their requests.
   18.21 + * <p>
   18.22 + * The quest for today is to enhance your existing convertor API to hold
   18.23 + * information about many currencies and allow conversions between any of them.
   18.24 + * Also, as conversion rates for diferent currencies usually arise from various
   18.25 + * bank departments, there is another important need. There is a need to
   18.26 + * compose two convertors into one by merging all the information about
   18.27 + * currencies they know about.
   18.28 + */
   18.29 +public class Task2Test extends TestCase {
   18.30 +    public Task2Test(String testName) {
   18.31 +        super(testName);
   18.32 +    }
   18.33 +
   18.34 +    @Override
   18.35 +    protected void setUp() throws Exception {
   18.36 +    }
   18.37 +
   18.38 +    @Override
   18.39 +    protected void tearDown() throws Exception {
   18.40 +    }
   18.41 +
   18.42 +    // As in Task1Test, keep in mind, that there are three parts
   18.43 +    // of the whole system:
   18.44 +    // 1. there is someone who knows the current exchange rate
   18.45 +    // 2. there is someone who wants to do the conversion
   18.46 +    // 3. there is the API between 1. and 2. which allows them to communicate
   18.47 +    // 
   18.48 +    // Please backward compatibly enhance your existing API to support following
   18.49 +    // usecases:
   18.50 +    //
   18.51 +    
   18.52 +    /** Create convertor that understands two currencies, CZK and
   18.53 +     *  SKK. Make 100 SKK == 75 CZK. This is method for the group of users that
   18.54 +     *  knows the exchange rate, and needs to use the API to create objects
   18.55 +     *  with the exchange rate. Anyone shall be ready to call this method without
   18.56 +     *  any other method being called previously. The API itself shall know
   18.57 +     *  nothing about any rates, before this method is called.
   18.58 +     */
   18.59 +    public static Convertor createTripleConvertor() {
   18.60 +        // Rates: 1USD = 15CZK
   18.61 +        // Rates: 1USD = 20SKK
   18.62 +        // Rates: 75CZK = 100SKK
   18.63 +	   return mergeConvertors(
   18.64 +			   createConvertor(money(1, USD),  money(15, CZK)),
   18.65 +			   createConvertor(money(1, USD),  money(20, SKK)),
   18.66 +			   createConvertor(money(75, CZK), money(100, SKK))
   18.67 +       );
   18.68 +    }
   18.69 +
   18.70 +    /** Define convertor that understands three currencies. Use it.
   18.71 +     */
   18.72 +    public void testConvertorForUSDandCZKandSKK() throws Exception {
   18.73 +        Convertor c = createTripleConvertor();
   18.74 +
   18.75 +        // convert $5 to CZK using c:
   18.76 +        assertEquals("Result is 75 CZK", money(75, CZK),c.convert(money(5,USD), CZK));
   18.77 +
   18.78 +        // convert $5 to SKK using c:
   18.79 +        assertEquals("Result is 100 SKK", money(100, SKK),c.convert(money(5,USD), SKK));
   18.80 +
   18.81 +        // convert 200SKK to CZK using c:
   18.82 +        assertEquals("Result is 150 CZK", money(150, CZK),c.convert(money(200,SKK), CZK));
   18.83 +
   18.84 +        // convert 200SKK to USK using c:
   18.85 +        assertEquals("Result is 10 USD", money(10, USD),c.convert(money(200,SKK), USD));
   18.86 +    }
   18.87 +
   18.88 +    /** Merge all currency rates of convertor 1 with convertor 2.
   18.89 +     * Implement this using your API, preferably this method just delegates
   18.90 +     * into some API method which does the actual work, without requiring
   18.91 +     * API clients to code anything complex.
   18.92 +     */
   18.93 +    public static Convertor merge(Convertor one, Convertor two) {
   18.94 +        return mergeConvertors((ExtendedConvertor)one, (ExtendedConvertor)two);
   18.95 +    }
   18.96 +
   18.97 +    /** Join the convertors from previous task, Task1Test and show that it
   18.98 +     * can be used to do reasonable conversions.
   18.99 +     */
  18.100 +    public void testConvertorComposition() throws Exception {
  18.101 +        Convertor c = merge(
  18.102 +            Task1Test.createCZKtoUSD(),
  18.103 +            Task1Test.createSKKtoCZK()
  18.104 +        );
  18.105 +
  18.106 +        // convert $5 to CZK using c:
  18.107 +        assertEquals("Result is 85 CZK", money(85, CZK),c.convert(money(5,USD), CZK));
  18.108 +
  18.109 +        // convert $8 to CZK using c:
  18.110 +        assertEquals("Result is 136 CZK", money(136, CZK),c.convert(money(8,USD), CZK));
  18.111 +
  18.112 +        // convert 1003CZK to USD using c:
  18.113 +        assertEquals("Result is 59 USD", money(59, USD),c.convert(money(1003,CZK), USD));
  18.114 +
  18.115 +        // convert 16CZK using c:
  18.116 +        assertEquals("Result is 20 SKK", money(20, SKK),c.convert(money(16,CZK), SKK));
  18.117 +
  18.118 +        // convert 500SKK to CZK using c:
  18.119 +        assertEquals("Result is 400 CZK", money(400, CZK),c.convert(money(500,SKK), CZK));
  18.120 +
  18.121 +    }
  18.122 +}
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/task3/solution04/build.xml	Tue Oct 07 11:05:34 2008 +0200
    19.3 @@ -0,0 +1,69 @@
    19.4 +<?xml version="1.0" encoding="UTF-8"?>
    19.5 +<!-- You may freely edit this file. See commented blocks below for -->
    19.6 +<!-- some examples of how to customize the build. -->
    19.7 +<!-- (If you delete it and reopen the project it will be recreated.) -->
    19.8 +<project name="currency" default="default" basedir=".">
    19.9 +    <description>Builds, tests, and runs the project.</description>
   19.10 +    <import file="nbproject/build-impl.xml"/>
   19.11 +    <!--
   19.12 +
   19.13 +    There exist several targets which are by default empty and which can be 
   19.14 +    used for execution of your tasks. These targets are usually executed 
   19.15 +    before and after some main targets. They are: 
   19.16 +
   19.17 +      -pre-init:                 called before initialization of project properties
   19.18 +      -post-init:                called after initialization of project properties
   19.19 +      -pre-compile:              called before javac compilation
   19.20 +      -post-compile:             called after javac compilation
   19.21 +      -pre-compile-single:       called before javac compilation of single file
   19.22 +      -post-compile-single:      called after javac compilation of single file
   19.23 +      -pre-compile-test:         called before javac compilation of JUnit tests
   19.24 +      -post-compile-test:        called after javac compilation of JUnit tests
   19.25 +      -pre-compile-test-single:  called before javac compilation of single JUnit test
   19.26 +      -post-compile-test-single: called after javac compilation of single JUunit test
   19.27 +      -pre-jar:                  called before JAR building
   19.28 +      -post-jar:                 called after JAR building
   19.29 +      -post-clean:               called after cleaning build products
   19.30 +
   19.31 +    (Targets beginning with '-' are not intended to be called on their own.)
   19.32 +
   19.33 +    Example of inserting an obfuscator after compilation could look like this:
   19.34 +
   19.35 +        <target name="-post-compile">
   19.36 +            <obfuscate>
   19.37 +                <fileset dir="${build.classes.dir}"/>
   19.38 +            </obfuscate>
   19.39 +        </target>
   19.40 +
   19.41 +    For list of available properties check the imported 
   19.42 +    nbproject/build-impl.xml file. 
   19.43 +
   19.44 +
   19.45 +    Another way to customize the build is by overriding existing main targets.
   19.46 +    The targets of interest are: 
   19.47 +
   19.48 +      -init-macrodef-javac:     defines macro for javac compilation
   19.49 +      -init-macrodef-junit:     defines macro for junit execution
   19.50 +      -init-macrodef-debug:     defines macro for class debugging
   19.51 +      -init-macrodef-java:      defines macro for class execution
   19.52 +      -do-jar-with-manifest:    JAR building (if you are using a manifest)
   19.53 +      -do-jar-without-manifest: JAR building (if you are not using a manifest)
   19.54 +      run:                      execution of project 
   19.55 +      -javadoc-build:           Javadoc generation
   19.56 +      test-report:              JUnit report generation
   19.57 +
   19.58 +    An example of overriding the target for project execution could look like this:
   19.59 +
   19.60 +        <target name="run" depends="currency-impl.jar">
   19.61 +            <exec dir="bin" executable="launcher.exe">
   19.62 +                <arg file="${dist.jar}"/>
   19.63 +            </exec>
   19.64 +        </target>
   19.65 +
   19.66 +    Notice that the overridden target depends on the jar target and not only on 
   19.67 +    the compile target as the regular run target does. Again, for a list of available 
   19.68 +    properties which you can use, check the target you are overriding in the
   19.69 +    nbproject/build-impl.xml file. 
   19.70 +
   19.71 +    -->
   19.72 +</project>
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/task3/solution04/nbproject/build-impl.xml	Tue Oct 07 11:05:34 2008 +0200
    20.3 @@ -0,0 +1,642 @@
    20.4 +<?xml version="1.0" encoding="UTF-8"?>
    20.5 +<!--
    20.6 +*** GENERATED FROM project.xml - DO NOT EDIT  ***
    20.7 +***         EDIT ../build.xml INSTEAD         ***
    20.8 +
    20.9 +For the purpose of easier reading the script
   20.10 +is divided into following sections:
   20.11 +
   20.12 +  - initialization
   20.13 +  - compilation
   20.14 +  - jar
   20.15 +  - execution
   20.16 +  - debugging
   20.17 +  - javadoc
   20.18 +  - junit compilation
   20.19 +  - junit execution
   20.20 +  - junit debugging
   20.21 +  - applet
   20.22 +  - cleanup
   20.23 +
   20.24 +        -->
   20.25 +<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="Currency_Convertor_Solution_04-impl">
   20.26 +    <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
   20.27 +    <!-- 
   20.28 +                ======================
   20.29 +                INITIALIZATION SECTION 
   20.30 +                ======================
   20.31 +            -->
   20.32 +    <target name="-pre-init">
   20.33 +        <!-- Empty placeholder for easier customization. -->
   20.34 +        <!-- You can override this target in the ../build.xml file. -->
   20.35 +    </target>
   20.36 +    <target depends="-pre-init" name="-init-private">
   20.37 +        <property file="nbproject/private/config.properties"/>
   20.38 +        <property file="nbproject/private/configs/${config}.properties"/>
   20.39 +        <property file="nbproject/private/private.properties"/>
   20.40 +    </target>
   20.41 +    <target depends="-pre-init,-init-private" name="-init-user">
   20.42 +        <property file="${user.properties.file}"/>
   20.43 +        <!-- The two properties below are usually overridden -->
   20.44 +        <!-- by the active platform. Just a fallback. -->
   20.45 +        <property name="default.javac.source" value="1.4"/>
   20.46 +        <property name="default.javac.target" value="1.4"/>
   20.47 +    </target>
   20.48 +    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
   20.49 +        <property file="nbproject/configs/${config}.properties"/>
   20.50 +        <property file="nbproject/project.properties"/>
   20.51 +    </target>
   20.52 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
   20.53 +        <available file="${manifest.file}" property="manifest.available"/>
   20.54 +        <condition property="manifest.available+main.class">
   20.55 +            <and>
   20.56 +                <isset property="manifest.available"/>
   20.57 +                <isset property="main.class"/>
   20.58 +                <not>
   20.59 +                    <equals arg1="${main.class}" arg2="" trim="true"/>
   20.60 +                </not>
   20.61 +            </and>
   20.62 +        </condition>
   20.63 +        <condition property="manifest.available+main.class+mkdist.available">
   20.64 +            <and>
   20.65 +                <istrue value="${manifest.available+main.class}"/>
   20.66 +                <isset property="libs.CopyLibs.classpath"/>
   20.67 +            </and>
   20.68 +        </condition>
   20.69 +        <condition property="have.tests">
   20.70 +            <or>
   20.71 +                <available file="${test.src.dir}"/>
   20.72 +            </or>
   20.73 +        </condition>
   20.74 +        <condition property="have.sources">
   20.75 +            <or>
   20.76 +                <available file="${src.dir}"/>
   20.77 +            </or>
   20.78 +        </condition>
   20.79 +        <condition property="netbeans.home+have.tests">
   20.80 +            <and>
   20.81 +                <isset property="netbeans.home"/>
   20.82 +                <isset property="have.tests"/>
   20.83 +            </and>
   20.84 +        </condition>
   20.85 +        <condition property="no.javadoc.preview">
   20.86 +            <and>
   20.87 +                <isset property="javadoc.preview"/>
   20.88 +                <isfalse value="${javadoc.preview}"/>
   20.89 +            </and>
   20.90 +        </condition>
   20.91 +        <property name="run.jvmargs" value=""/>
   20.92 +        <property name="javac.compilerargs" value=""/>
   20.93 +        <property name="work.dir" value="${basedir}"/>
   20.94 +        <condition property="no.deps">
   20.95 +            <and>
   20.96 +                <istrue value="${no.dependencies}"/>
   20.97 +            </and>
   20.98 +        </condition>
   20.99 +        <property name="javac.debug" value="true"/>
  20.100 +        <property name="javadoc.preview" value="true"/>
  20.101 +        <property name="application.args" value=""/>
  20.102 +        <property name="source.encoding" value="${file.encoding}"/>
  20.103 +        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
  20.104 +            <and>
  20.105 +                <isset property="javadoc.encoding"/>
  20.106 +                <not>
  20.107 +                    <equals arg1="${javadoc.encoding}" arg2=""/>
  20.108 +                </not>
  20.109 +            </and>
  20.110 +        </condition>
  20.111 +        <property name="javadoc.encoding.used" value="${source.encoding}"/>
  20.112 +        <property name="includes" value="**"/>
  20.113 +        <property name="excludes" value=""/>
  20.114 +        <property name="do.depend" value="false"/>
  20.115 +        <condition property="do.depend.true">
  20.116 +            <istrue value="${do.depend}"/>
  20.117 +        </condition>
  20.118 +        <condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
  20.119 +            <and>
  20.120 +                <isset property="jaxws.endorsed.dir"/>
  20.121 +                <available file="nbproject/jaxws-build.xml"/>
  20.122 +            </and>
  20.123 +        </condition>
  20.124 +    </target>
  20.125 +    <target name="-post-init">
  20.126 +        <!-- Empty placeholder for easier customization. -->
  20.127 +        <!-- You can override this target in the ../build.xml file. -->
  20.128 +    </target>
  20.129 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
  20.130 +        <fail unless="src.dir">Must set src.dir</fail>
  20.131 +        <fail unless="test.src.dir">Must set test.src.dir</fail>
  20.132 +        <fail unless="build.dir">Must set build.dir</fail>
  20.133 +        <fail unless="dist.dir">Must set dist.dir</fail>
  20.134 +        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
  20.135 +        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
  20.136 +        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
  20.137 +        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
  20.138 +        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
  20.139 +        <fail unless="dist.jar">Must set dist.jar</fail>
  20.140 +    </target>
  20.141 +    <target name="-init-macrodef-property">
  20.142 +        <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
  20.143 +            <attribute name="name"/>
  20.144 +            <attribute name="value"/>
  20.145 +            <sequential>
  20.146 +                <property name="@{name}" value="${@{value}}"/>
  20.147 +            </sequential>
  20.148 +        </macrodef>
  20.149 +    </target>
  20.150 +    <target name="-init-macrodef-javac">
  20.151 +        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
  20.152 +            <attribute default="${src.dir}" name="srcdir"/>
  20.153 +            <attribute default="${build.classes.dir}" name="destdir"/>
  20.154 +            <attribute default="${javac.classpath}" name="classpath"/>
  20.155 +            <attribute default="${includes}" name="includes"/>
  20.156 +            <attribute default="${excludes}" name="excludes"/>
  20.157 +            <attribute default="${javac.debug}" name="debug"/>
  20.158 +            <attribute default="" name="sourcepath"/>
  20.159 +            <element name="customize" optional="true"/>
  20.160 +            <sequential>
  20.161 +                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
  20.162 +                    <classpath>
  20.163 +                        <path path="@{classpath}"/>
  20.164 +                    </classpath>
  20.165 +                    <compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
  20.166 +                    <customize/>
  20.167 +                </javac>
  20.168 +            </sequential>
  20.169 +        </macrodef>
  20.170 +        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
  20.171 +            <attribute default="${src.dir}" name="srcdir"/>
  20.172 +            <attribute default="${build.classes.dir}" name="destdir"/>
  20.173 +            <attribute default="${javac.classpath}" name="classpath"/>
  20.174 +            <sequential>
  20.175 +                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
  20.176 +                    <classpath>
  20.177 +                        <path path="@{classpath}"/>
  20.178 +                    </classpath>
  20.179 +                </depend>
  20.180 +            </sequential>
  20.181 +        </macrodef>
  20.182 +        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
  20.183 +            <attribute default="${build.classes.dir}" name="destdir"/>
  20.184 +            <sequential>
  20.185 +                <fail unless="javac.includes">Must set javac.includes</fail>
  20.186 +                <pathconvert pathsep="," property="javac.includes.binary">
  20.187 +                    <path>
  20.188 +                        <filelist dir="@{destdir}" files="${javac.includes}"/>
  20.189 +                    </path>
  20.190 +                    <globmapper from="*.java" to="*.class"/>
  20.191 +                </pathconvert>
  20.192 +                <delete>
  20.193 +                    <files includes="${javac.includes.binary}"/>
  20.194 +                </delete>
  20.195 +            </sequential>
  20.196 +        </macrodef>
  20.197 +    </target>
  20.198 +    <target name="-init-macrodef-junit">
  20.199 +        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
  20.200 +            <attribute default="${includes}" name="includes"/>
  20.201 +            <attribute default="${excludes}" name="excludes"/>
  20.202 +            <attribute default="**" name="testincludes"/>
  20.203 +            <sequential>
  20.204 +                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
  20.205 +                    <batchtest todir="${build.test.results.dir}">
  20.206 +                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
  20.207 +                            <filename name="@{testincludes}"/>
  20.208 +                        </fileset>
  20.209 +                    </batchtest>
  20.210 +                    <classpath>
  20.211 +                        <path path="${run.test.classpath}"/>
  20.212 +                    </classpath>
  20.213 +                    <syspropertyset>
  20.214 +                        <propertyref prefix="test-sys-prop."/>
  20.215 +                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
  20.216 +                    </syspropertyset>
  20.217 +                    <formatter type="brief" usefile="false"/>
  20.218 +                    <formatter type="xml"/>
  20.219 +                    <jvmarg line="${run.jvmargs}"/>
  20.220 +                </junit>
  20.221 +            </sequential>
  20.222 +        </macrodef>
  20.223 +    </target>
  20.224 +    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
  20.225 +        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
  20.226 +            <attribute default="${main.class}" name="name"/>
  20.227 +            <attribute default="${debug.classpath}" name="classpath"/>
  20.228 +            <attribute default="" name="stopclassname"/>
  20.229 +            <sequential>
  20.230 +                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
  20.231 +                    <classpath>
  20.232 +                        <path path="@{classpath}"/>
  20.233 +                    </classpath>
  20.234 +                </nbjpdastart>
  20.235 +            </sequential>
  20.236 +        </macrodef>
  20.237 +        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
  20.238 +            <attribute default="${build.classes.dir}" name="dir"/>
  20.239 +            <sequential>
  20.240 +                <nbjpdareload>
  20.241 +                    <fileset dir="@{dir}" includes="${fix.classes}">
  20.242 +                        <include name="${fix.includes}*.class"/>
  20.243 +                    </fileset>
  20.244 +                </nbjpdareload>
  20.245 +            </sequential>
  20.246 +        </macrodef>
  20.247 +    </target>
  20.248 +    <target name="-init-debug-args">
  20.249 +        <property name="version-output" value="java version &quot;${ant.java.version}"/>
  20.250 +        <condition property="have-jdk-older-than-1.4">
  20.251 +            <or>
  20.252 +                <contains string="${version-output}" substring="java version &quot;1.0"/>
  20.253 +                <contains string="${version-output}" substring="java version &quot;1.1"/>
  20.254 +                <contains string="${version-output}" substring="java version &quot;1.2"/>
  20.255 +                <contains string="${version-output}" substring="java version &quot;1.3"/>
  20.256 +            </or>
  20.257 +        </condition>
  20.258 +        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
  20.259 +            <istrue value="${have-jdk-older-than-1.4}"/>
  20.260 +        </condition>
  20.261 +        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
  20.262 +            <os family="windows"/>
  20.263 +        </condition>
  20.264 +        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
  20.265 +            <isset property="debug.transport"/>
  20.266 +        </condition>
  20.267 +    </target>
  20.268 +    <target depends="-init-debug-args" name="-init-macrodef-debug">
  20.269 +        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
  20.270 +            <attribute default="${main.class}" name="classname"/>
  20.271 +            <attribute default="${debug.classpath}" name="classpath"/>
  20.272 +            <element name="customize" optional="true"/>
  20.273 +            <sequential>
  20.274 +                <java classname="@{classname}" dir="${work.dir}" fork="true">
  20.275 +                    <jvmarg line="${debug-args-line}"/>
  20.276 +                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
  20.277 +                    <jvmarg line="${run.jvmargs}"/>
  20.278 +                    <classpath>
  20.279 +                        <path path="@{classpath}"/>
  20.280 +                    </classpath>
  20.281 +                    <syspropertyset>
  20.282 +                        <propertyref prefix="run-sys-prop."/>
  20.283 +                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
  20.284 +                    </syspropertyset>
  20.285 +                    <customize/>
  20.286 +                </java>
  20.287 +            </sequential>
  20.288 +        </macrodef>
  20.289 +    </target>
  20.290 +    <target name="-init-macrodef-java">
  20.291 +        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
  20.292 +            <attribute default="${main.class}" name="classname"/>
  20.293 +            <element name="customize" optional="true"/>
  20.294 +            <sequential>
  20.295 +                <java classname="@{classname}" dir="${work.dir}" fork="true">
  20.296 +                    <jvmarg line="${run.jvmargs}"/>
  20.297 +                    <classpath>
  20.298 +                        <path path="${run.classpath}"/>
  20.299 +                    </classpath>
  20.300 +                    <syspropertyset>
  20.301 +                        <propertyref prefix="run-sys-prop."/>
  20.302 +                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
  20.303 +                    </syspropertyset>
  20.304 +                    <customize/>
  20.305 +                </java>
  20.306 +            </sequential>
  20.307 +        </macrodef>
  20.308 +    </target>
  20.309 +    <target name="-init-presetdef-jar">
  20.310 +        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
  20.311 +            <jar compress="${jar.compress}" jarfile="${dist.jar}">
  20.312 +                <j2seproject1:fileset dir="${build.classes.dir}"/>
  20.313 +            </jar>
  20.314 +        </presetdef>
  20.315 +    </target>
  20.316 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar" name="init"/>
  20.317 +    <!--
  20.318 +                ===================
  20.319 +                COMPILATION SECTION
  20.320 +                ===================
  20.321 +            -->
  20.322 +    <target depends="init" name="deps-jar" unless="no.deps"/>
  20.323 +    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
  20.324 +    <target depends="init" name="-check-automatic-build">
  20.325 +        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
  20.326 +    </target>
  20.327 +    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
  20.328 +        <antcall target="clean"/>
  20.329 +    </target>
  20.330 +    <target depends="init,deps-jar" name="-pre-pre-compile">
  20.331 +        <mkdir dir="${build.classes.dir}"/>
  20.332 +    </target>
  20.333 +    <target name="-pre-compile">
  20.334 +        <!-- Empty placeholder for easier customization. -->
  20.335 +        <!-- You can override this target in the ../build.xml file. -->
  20.336 +    </target>
  20.337 +    <target if="do.depend.true" name="-compile-depend">
  20.338 +        <j2seproject3:depend/>
  20.339 +    </target>
  20.340 +    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
  20.341 +        <j2seproject3:javac/>
  20.342 +        <copy todir="${build.classes.dir}">
  20.343 +            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  20.344 +        </copy>
  20.345 +    </target>
  20.346 +    <target name="-post-compile">
  20.347 +        <!-- Empty placeholder for easier customization. -->
  20.348 +        <!-- You can override this target in the ../build.xml file. -->
  20.349 +    </target>
  20.350 +    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
  20.351 +    <target name="-pre-compile-single">
  20.352 +        <!-- Empty placeholder for easier customization. -->
  20.353 +        <!-- You can override this target in the ../build.xml file. -->
  20.354 +    </target>
  20.355 +    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
  20.356 +        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
  20.357 +        <j2seproject3:force-recompile/>
  20.358 +        <j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
  20.359 +    </target>
  20.360 +    <target name="-post-compile-single">
  20.361 +        <!-- Empty placeholder for easier customization. -->
  20.362 +        <!-- You can override this target in the ../build.xml file. -->
  20.363 +    </target>
  20.364 +    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
  20.365 +    <!--
  20.366 +                ====================
  20.367 +                JAR BUILDING SECTION
  20.368 +                ====================
  20.369 +            -->
  20.370 +    <target depends="init" name="-pre-pre-jar">
  20.371 +        <dirname file="${dist.jar}" property="dist.jar.dir"/>
  20.372 +        <mkdir dir="${dist.jar.dir}"/>
  20.373 +    </target>
  20.374 +    <target name="-pre-jar">
  20.375 +        <!-- Empty placeholder for easier customization. -->
  20.376 +        <!-- You can override this target in the ../build.xml file. -->
  20.377 +    </target>
  20.378 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
  20.379 +        <j2seproject1:jar/>
  20.380 +    </target>
  20.381 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
  20.382 +        <j2seproject1:jar manifest="${manifest.file}"/>
  20.383 +    </target>
  20.384 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
  20.385 +        <j2seproject1:jar manifest="${manifest.file}">
  20.386 +            <j2seproject1:manifest>
  20.387 +                <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
  20.388 +            </j2seproject1:manifest>
  20.389 +        </j2seproject1:jar>
  20.390 +        <echo>To run this application from the command line without Ant, try:</echo>
  20.391 +        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
  20.392 +        <property location="${dist.jar}" name="dist.jar.resolved"/>
  20.393 +        <pathconvert property="run.classpath.with.dist.jar">
  20.394 +            <path path="${run.classpath}"/>
  20.395 +            <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
  20.396 +        </pathconvert>
  20.397 +        <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
  20.398 +    </target>
  20.399 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
  20.400 +        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
  20.401 +        <pathconvert property="run.classpath.without.build.classes.dir">
  20.402 +            <path path="${run.classpath}"/>
  20.403 +            <map from="${build.classes.dir.resolved}" to=""/>
  20.404 +        </pathconvert>
  20.405 +        <pathconvert pathsep=" " property="jar.classpath">
  20.406 +            <path path="${run.classpath.without.build.classes.dir}"/>
  20.407 +            <chainedmapper>
  20.408 +                <flattenmapper/>
  20.409 +                <globmapper from="*" to="lib/*"/>
  20.410 +            </chainedmapper>
  20.411 +        </pathconvert>
  20.412 +        <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
  20.413 +        <copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
  20.414 +            <fileset dir="${build.classes.dir}"/>
  20.415 +            <manifest>
  20.416 +                <attribute name="Main-Class" value="${main.class}"/>
  20.417 +                <attribute name="Class-Path" value="${jar.classpath}"/>
  20.418 +            </manifest>
  20.419 +        </copylibs>
  20.420 +        <echo>To run this application from the command line without Ant, try:</echo>
  20.421 +        <property location="${dist.jar}" name="dist.jar.resolved"/>
  20.422 +        <echo>java -jar "${dist.jar.resolved}"</echo>
  20.423 +    </target>
  20.424 +    <target name="-post-jar">
  20.425 +        <!-- Empty placeholder for easier customization. -->
  20.426 +        <!-- You can override this target in the ../build.xml file. -->
  20.427 +    </target>
  20.428 +    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
  20.429 +    <!--
  20.430 +                =================
  20.431 +                EXECUTION SECTION
  20.432 +                =================
  20.433 +            -->
  20.434 +    <target depends="init,compile" description="Run a main class." name="run">
  20.435 +        <j2seproject1:java>
  20.436 +            <customize>
  20.437 +                <arg line="${application.args}"/>
  20.438 +            </customize>
  20.439 +        </j2seproject1:java>
  20.440 +    </target>
  20.441 +    <target name="-do-not-recompile">
  20.442 +        <property name="javac.includes.binary" value=""/>
  20.443 +    </target>
  20.444 +    <target depends="init,-do-not-recompile,compile-single" name="run-single">
  20.445 +        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
  20.446 +        <j2seproject1:java classname="${run.class}"/>
  20.447 +    </target>
  20.448 +    <!--
  20.449 +                =================
  20.450 +                DEBUGGING SECTION
  20.451 +                =================
  20.452 +            -->
  20.453 +    <target depends="init" if="netbeans.home" name="-debug-start-debugger">
  20.454 +        <j2seproject1:nbjpdastart name="${debug.class}"/>
  20.455 +    </target>
  20.456 +    <target depends="init,compile" name="-debug-start-debuggee">
  20.457 +        <j2seproject3:debug>
  20.458 +            <customize>
  20.459 +                <arg line="${application.args}"/>
  20.460 +            </customize>
  20.461 +        </j2seproject3:debug>
  20.462 +    </target>
  20.463 +    <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
  20.464 +    <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
  20.465 +        <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
  20.466 +    </target>
  20.467 +    <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
  20.468 +    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
  20.469 +        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
  20.470 +        <j2seproject3:debug classname="${debug.class}"/>
  20.471 +    </target>
  20.472 +    <target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
  20.473 +    <target depends="init" name="-pre-debug-fix">
  20.474 +        <fail unless="fix.includes">Must set fix.includes</fail>
  20.475 +        <property name="javac.includes" value="${fix.includes}.java"/>
  20.476 +    </target>
  20.477 +    <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
  20.478 +        <j2seproject1:nbjpdareload/>
  20.479 +    </target>
  20.480 +    <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
  20.481 +    <!--
  20.482 +                ===============
  20.483 +                JAVADOC SECTION
  20.484 +                ===============
  20.485 +            -->
  20.486 +    <target depends="init" name="-javadoc-build">
  20.487 +        <mkdir dir="${dist.javadoc.dir}"/>
  20.488 +        <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
  20.489 +            <classpath>
  20.490 +                <path path="${javac.classpath}"/>
  20.491 +            </classpath>
  20.492 +            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
  20.493 +                <filename name="**/*.java"/>
  20.494 +            </fileset>
  20.495 +        </javadoc>
  20.496 +    </target>
  20.497 +    <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
  20.498 +        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
  20.499 +    </target>
  20.500 +    <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
  20.501 +    <!--
  20.502 +                =========================
  20.503 +                JUNIT COMPILATION SECTION
  20.504 +                =========================
  20.505 +            -->
  20.506 +    <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
  20.507 +        <mkdir dir="${build.test.classes.dir}"/>
  20.508 +    </target>
  20.509 +    <target name="-pre-compile-test">
  20.510 +        <!-- Empty placeholder for easier customization. -->
  20.511 +        <!-- You can override this target in the ../build.xml file. -->
  20.512 +    </target>
  20.513 +    <target if="do.depend.true" name="-compile-test-depend">
  20.514 +        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
  20.515 +    </target>
  20.516 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
  20.517 +        <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
  20.518 +        <copy todir="${build.test.classes.dir}">
  20.519 +            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  20.520 +        </copy>
  20.521 +    </target>
  20.522 +    <target name="-post-compile-test">
  20.523 +        <!-- Empty placeholder for easier customization. -->
  20.524 +        <!-- You can override this target in the ../build.xml file. -->
  20.525 +    </target>
  20.526 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
  20.527 +    <target name="-pre-compile-test-single">
  20.528 +        <!-- Empty placeholder for easier customization. -->
  20.529 +        <!-- You can override this target in the ../build.xml file. -->
  20.530 +    </target>
  20.531 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
  20.532 +        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
  20.533 +        <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
  20.534 +        <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
  20.535 +        <copy todir="${build.test.classes.dir}">
  20.536 +            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  20.537 +        </copy>
  20.538 +    </target>
  20.539 +    <target name="-post-compile-test-single">
  20.540 +        <!-- Empty placeholder for easier customization. -->
  20.541 +        <!-- You can override this target in the ../build.xml file. -->
  20.542 +    </target>
  20.543 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
  20.544 +    <!--
  20.545 +                =======================
  20.546 +                JUNIT EXECUTION SECTION
  20.547 +                =======================
  20.548 +            -->
  20.549 +    <target depends="init" if="have.tests" name="-pre-test-run">
  20.550 +        <mkdir dir="${build.test.results.dir}"/>
  20.551 +    </target>
  20.552 +    <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
  20.553 +        <j2seproject3:junit testincludes="**/*Test.java"/>
  20.554 +    </target>
  20.555 +    <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
  20.556 +        <fail if="tests.failed">Some tests failed; see details above.</fail>
  20.557 +    </target>
  20.558 +    <target depends="init" if="have.tests" name="test-report"/>
  20.559 +    <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
  20.560 +    <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
  20.561 +    <target depends="init" if="have.tests" name="-pre-test-run-single">
  20.562 +        <mkdir dir="${build.test.results.dir}"/>
  20.563 +    </target>
  20.564 +    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
  20.565 +        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
  20.566 +        <j2seproject3:junit excludes="" includes="${test.includes}"/>
  20.567 +    </target>
  20.568 +    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
  20.569 +        <fail if="tests.failed">Some tests failed; see details above.</fail>
  20.570 +    </target>
  20.571 +    <target depends="init,-do-not-recompile,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
  20.572 +    <!--
  20.573 +                =======================
  20.574 +                JUNIT DEBUGGING SECTION
  20.575 +                =======================
  20.576 +            -->
  20.577 +    <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
  20.578 +        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
  20.579 +        <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
  20.580 +        <delete file="${test.report.file}"/>
  20.581 +        <mkdir dir="${build.test.results.dir}"/>
  20.582 +        <j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
  20.583 +            <customize>
  20.584 +                <syspropertyset>
  20.585 +                    <propertyref prefix="test-sys-prop."/>
  20.586 +                    <mapper from="test-sys-prop.*" to="*" type="glob"/>
  20.587 +                </syspropertyset>
  20.588 +                <arg value="${test.class}"/>
  20.589 +                <arg value="showoutput=true"/>
  20.590 +                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
  20.591 +                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
  20.592 +            </customize>
  20.593 +        </j2seproject3:debug>
  20.594 +    </target>
  20.595 +    <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
  20.596 +        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
  20.597 +    </target>
  20.598 +    <target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
  20.599 +    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
  20.600 +        <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
  20.601 +    </target>
  20.602 +    <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
  20.603 +    <!--
  20.604 +                =========================
  20.605 +                APPLET EXECUTION SECTION
  20.606 +                =========================
  20.607 +            -->
  20.608 +    <target depends="init,compile-single" name="run-applet">
  20.609 +        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
  20.610 +        <j2seproject1:java classname="sun.applet.AppletViewer">
  20.611 +            <customize>
  20.612 +                <arg value="${applet.url}"/>
  20.613 +            </customize>
  20.614 +        </j2seproject1:java>
  20.615 +    </target>
  20.616 +    <!--
  20.617 +                =========================
  20.618 +                APPLET DEBUGGING  SECTION
  20.619 +                =========================
  20.620 +            -->
  20.621 +    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
  20.622 +        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
  20.623 +        <j2seproject3:debug classname="sun.applet.AppletViewer">
  20.624 +            <customize>
  20.625 +                <arg value="${applet.url}"/>
  20.626 +            </customize>
  20.627 +        </j2seproject3:debug>
  20.628 +    </target>
  20.629 +    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
  20.630 +    <!--
  20.631 +                ===============
  20.632 +                CLEANUP SECTION
  20.633 +                ===============
  20.634 +            -->
  20.635 +    <target depends="init" name="deps-clean" unless="no.deps"/>
  20.636 +    <target depends="init" name="-do-clean">
  20.637 +        <delete dir="${build.dir}"/>
  20.638 +        <delete dir="${dist.dir}"/>
  20.639 +    </target>
  20.640 +    <target name="-post-clean">
  20.641 +        <!-- Empty placeholder for easier customization. -->
  20.642 +        <!-- You can override this target in the ../build.xml file. -->
  20.643 +    </target>
  20.644 +    <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
  20.645 +</project>
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/task3/solution04/nbproject/genfiles.properties	Tue Oct 07 11:05:34 2008 +0200
    21.3 @@ -0,0 +1,8 @@
    21.4 +build.xml.data.CRC32=2ab820eb
    21.5 +build.xml.script.CRC32=58a52595
    21.6 +build.xml.stylesheet.CRC32=be360661
    21.7 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
    21.8 +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
    21.9 +nbproject/build-impl.xml.data.CRC32=2fbfa6ce
   21.10 +nbproject/build-impl.xml.script.CRC32=c521eea7
   21.11 +nbproject/build-impl.xml.stylesheet.CRC32=e55b27f5
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/task3/solution04/nbproject/project.properties	Tue Oct 07 11:05:34 2008 +0200
    22.3 @@ -0,0 +1,68 @@
    22.4 +application.title=currency
    22.5 +application.vendor=apidesign.org
    22.6 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
    22.7 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
    22.8 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=default
    22.9 +build.classes.dir=${build.dir}/classes
   22.10 +build.classes.excludes=**/*.java,**/*.form
   22.11 +# This directory is removed when the project is cleaned:
   22.12 +build.dir=build
   22.13 +build.generated.dir=${build.dir}/generated
   22.14 +# Only compile against the classpath explicitly listed here:
   22.15 +build.sysclasspath=ignore
   22.16 +build.test.classes.dir=${build.dir}/test/classes
   22.17 +build.test.results.dir=${build.dir}/test/results
   22.18 +debug.classpath=\
   22.19 +    ${run.classpath}
   22.20 +debug.test.classpath=\
   22.21 +    ${run.test.classpath}
   22.22 +# This directory is removed when the project is cleaned:
   22.23 +dist.dir=dist
   22.24 +dist.jar=${dist.dir}/currency.jar
   22.25 +dist.javadoc.dir=${dist.dir}/javadoc
   22.26 +excludes=
   22.27 +file.reference.junit-4.4.jar=../../libs/junit-4.4.jar
   22.28 +file.reference.src-apifest08=..
   22.29 +includes=**
   22.30 +jar.compress=false
   22.31 +javac.classpath=
   22.32 +# Space-separated list of extra javac options
   22.33 +javac.compilerargs=
   22.34 +javac.deprecation=false
   22.35 +javac.source=1.5
   22.36 +javac.target=1.5
   22.37 +javac.test.classpath=\
   22.38 +    ${javac.classpath}:\
   22.39 +    ${build.classes.dir}:\
   22.40 +    ${file.reference.junit-4.4.jar}
   22.41 +javadoc.additionalparam=
   22.42 +javadoc.author=false
   22.43 +javadoc.encoding=
   22.44 +javadoc.noindex=false
   22.45 +javadoc.nonavbar=false
   22.46 +javadoc.notree=false
   22.47 +javadoc.private=false
   22.48 +javadoc.splitindex=true
   22.49 +javadoc.use=true
   22.50 +javadoc.version=false
   22.51 +javadoc.windowtitle=
   22.52 +jnlp.codebase.type=local
   22.53 +jnlp.codebase.url=file:/home/jarda/src/apifest08/currency/dist
   22.54 +jnlp.descriptor=application
   22.55 +jnlp.enabled=false
   22.56 +jnlp.offline-allowed=false
   22.57 +jnlp.signed=false
   22.58 +meta.inf.dir=${src.dir}/META-INF
   22.59 +platform.active=default_platform
   22.60 +run.classpath=\
   22.61 +    ${javac.classpath}:\
   22.62 +    ${build.classes.dir}
   22.63 +# Space-separated list of JVM arguments used when running the project
   22.64 +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
   22.65 +# or test-sys-prop.name=value to set system properties for unit tests):
   22.66 +run.jvmargs=
   22.67 +run.test.classpath=\
   22.68 +    ${javac.test.classpath}:\
   22.69 +    ${build.test.classes.dir}
   22.70 +src.dir=src
   22.71 +test.src.dir=test
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/task3/solution04/nbproject/project.xml	Tue Oct 07 11:05:34 2008 +0200
    23.3 @@ -0,0 +1,16 @@
    23.4 +<?xml version="1.0" encoding="UTF-8"?>
    23.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
    23.6 +    <type>org.netbeans.modules.java.j2seproject</type>
    23.7 +    <configuration>
    23.8 +        <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
    23.9 +            <name>Currency Convertor Solution 04</name>
   23.10 +            <minimum-ant-version>1.6.5</minimum-ant-version>
   23.11 +            <source-roots>
   23.12 +                <root id="src.dir"/>
   23.13 +            </source-roots>
   23.14 +            <test-roots>
   23.15 +                <root id="test.src.dir"/>
   23.16 +            </test-roots>
   23.17 +        </data>
   23.18 +    </configuration>
   23.19 +</project>
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/task3/solution04/src/org/apidesign/apifest08/currency/CompositeConvertorImpl.java	Tue Oct 07 11:05:34 2008 +0200
    24.3 @@ -0,0 +1,314 @@
    24.4 +package org.apidesign.apifest08.currency;
    24.5 +
    24.6 +
    24.7 +import java.math.BigDecimal;
    24.8 +import java.math.RoundingMode;
    24.9 +import java.util.Collections;
   24.10 +import java.util.Currency;
   24.11 +import java.util.HashMap;
   24.12 +import java.util.HashSet;
   24.13 +import java.util.Map;
   24.14 +import java.util.Set;
   24.15 +
   24.16 +
   24.17 +/**
   24.18 + * A composite convertor allows conversions between many currencies by forwarding conversion requests to stored convertors.
   24.19 + * A composite convertor will build all possible conversions that are allowed by the underlying set of convertors.
   24.20 + *
   24.21 + * @author D'Arcy Smith
   24.22 + * @verson 1.0
   24.23 + */
   24.24 +final class CompositeConvertorImpl
   24.25 +    implements Convertor
   24.26 +{
   24.27 +    /**
   24.28 +     * The convertors that are supported.
   24.29 +     */
   24.30 +    private final Convertor[] convertors;
   24.31 +    
   24.32 +    /**
   24.33 +     * Keeps track of what convertors to use to convert between currencies.
   24.34 +     */
   24.35 +    private final Map<Currency, Map<Currency, Convertor>> possibleConversions;
   24.36 +    
   24.37 +    {
   24.38 +        possibleConversions = new HashMap<Currency, Map<Currency, Convertor>>();
   24.39 +    }
   24.40 +
   24.41 +    /**
   24.42 +     * Construct a ComositeConvertorImpl with the specified convertors.
   24.43 +     * This will result in all possible conversions between the supplied currencies being made.
   24.44 +     * 
   24.45 +     * @param cs the convertors to use.
   24.46 +     * @throws IllegalArgumentException if any of the items in cs are null.
   24.47 +     */
   24.48 +    CompositeConvertorImpl(Convertor ... cs)
   24.49 +    {
   24.50 +        int newConvertors;
   24.51 +        
   24.52 +        convertors = cs;
   24.53 +
   24.54 +        // track all of the known conversion
   24.55 +        for(final Convertor convertor : convertors)
   24.56 +        {
   24.57 +            final Set<Currency>      currencies;
   24.58 +            Map<Currency, Convertor> possible;
   24.59 +
   24.60 +            if(convertor == null)
   24.61 +            {
   24.62 +                throw new IllegalArgumentException("cs cannot contain null");
   24.63 +            }
   24.64 +            
   24.65 +            currencies = convertor.getCurrencies();
   24.66 +
   24.67 +            for(final Currency currency : currencies)
   24.68 +            {
   24.69 +                possible = possibleConversions.get(currency);
   24.70 +
   24.71 +                if(possible == null)
   24.72 +                {
   24.73 +                    possible = new HashMap<Currency, Convertor>();
   24.74 +                    possibleConversions.put(currency, possible);
   24.75 +                }
   24.76 +
   24.77 +                for(final Currency c : currencies)
   24.78 +                {
   24.79 +                    possible.put(c, convertor);
   24.80 +                }
   24.81 +            }
   24.82 +        }
   24.83 +
   24.84 +        // make up conversions that can be derived... eg:
   24.85 +        //   we have:
   24.86 +        //      USD <-> CAD
   24.87 +        //      CAD <-> CZK
   24.88 +        //      SSK <-> GBP
   24.89 +        //   we can derive:
   24.90 +        //      USD <-> CZK
   24.91 +        //   we cannot derive:
   24.92 +        //      USD <-> GBP
   24.93 +        //      CAD <-> GBP
   24.94 +        //      CZK <-> GBP
   24.95 +        do
   24.96 +        {
   24.97 +            newConvertors = 0;
   24.98 +
   24.99 +            // todo... need to loop this until all the ones that can be handled are done.
  24.100 +            for(final Currency from : getCurrencies())
  24.101 +            {
  24.102 +                for(final Currency to : getCurrencies())
  24.103 +                {
  24.104 +                    if(!(canConvert(from, to)))
  24.105 +                    {
  24.106 +                        final Set<Currency> fromCurrencies;
  24.107 +                        final Set<Currency> toCurrencies;
  24.108 +                        final Set<Currency> common;
  24.109 +
  24.110 +                        fromCurrencies = possibleConversions.get(from).keySet();
  24.111 +                        toCurrencies   = possibleConversions.get(to).keySet();
  24.112 +                        common         = new HashSet<Currency>();
  24.113 +
  24.114 +                        for(final Currency currency : fromCurrencies)
  24.115 +                        {
  24.116 +                            if(toCurrencies.contains(currency))
  24.117 +                            {
  24.118 +                                common.add(currency);
  24.119 +                            }
  24.120 +                        }
  24.121 +
  24.122 +                        for(final Currency currency : common)
  24.123 +                        {
  24.124 +                            final Convertor convertor;
  24.125 +
  24.126 +                            convertor = createConvertor(from, to, currency);
  24.127 +                            possibleConversions.get(from).put(to, convertor);
  24.128 +                            possibleConversions.get(to).put(from, convertor);
  24.129 +                            newConvertors++;
  24.130 +                        }
  24.131 +                    }
  24.132 +                }
  24.133 +            }
  24.134 +        }
  24.135 +        while(newConvertors > 0);
  24.136 +    }
  24.137 +
  24.138 +    /**
  24.139 +     * Check to see if converting between the two currencies is possible.
  24.140 +     *
  24.141 +     * @param from the currency to convert from.
  24.142 +     * @param to the currency to convert to.
  24.143 +     * @return true if the conversion is possible.
  24.144 +     * @throws IllegalArgumentException if either from or to are null.
  24.145 +     */
  24.146 +    public boolean canConvert(final Currency from, final Currency to)
  24.147 +    {
  24.148 +        final Map<Currency, Convertor> possible;
  24.149 +
  24.150 +        if(from == null)
  24.151 +        {
  24.152 +            throw new IllegalArgumentException("from cannot be null");
  24.153 +        }
  24.154 +        
  24.155 +        if(to == null)
  24.156 +        {
  24.157 +            throw new IllegalArgumentException("to cannot be null");
  24.158 +        }
  24.159 +                
  24.160 +        possible = possibleConversions.get(from);
  24.161 +
  24.162 +        if(possible.containsKey(to))
  24.163 +        {
  24.164 +            return (true);
  24.165 +        }
  24.166 +
  24.167 +        return (false);
  24.168 +    }
  24.169 +
  24.170 +    /**
  24.171 +     * Get the currencies that the convertor supports.  Just because a currency is
  24.172 +     * supported does not mean that canConvert will return true.
  24.173 +     * 
  24.174 +     * @return the supported currencies.
  24.175 +     */
  24.176 +    public Set<Currency> getCurrencies()
  24.177 +    {
  24.178 +        final Set<Currency> currencies;
  24.179 +
  24.180 +        currencies = possibleConversions.keySet();
  24.181 +
  24.182 +        return (Collections.unmodifiableSet(currencies));
  24.183 +    }
  24.184 +    
  24.185 +    /**
  24.186 +     * Get the conversion rate between two currencies.
  24.187 +     * 
  24.188 +     * @param from the currency to convert from.
  24.189 +     * @param to the currency to convert to.
  24.190 +     * @return the conversion rate between the two currencies.
  24.191 +     * @throws IllegalArgumentException if either from or to is null.
  24.192 +     * @throws InvalidConversionException if canConvert would return false.
  24.193 +     */
  24.194 +    public BigDecimal getConversionRate(final Currency from, final Currency to)
  24.195 +        throws InvalidConversionException
  24.196 +    {
  24.197 +        final Map<Currency, Convertor> possible;
  24.198 +        Convertor                      convertor;
  24.199 +
  24.200 +        if(from == null)
  24.201 +        {
  24.202 +            throw new IllegalArgumentException("from cannot be null");
  24.203 +        }
  24.204 +        
  24.205 +        if(to == null)
  24.206 +        {
  24.207 +            throw new IllegalArgumentException("to cannot be null");
  24.208 +        }
  24.209 +        
  24.210 +        if(!(canConvert(from, to)))
  24.211 +        {
  24.212 +            throw new InvalidConversionException("cannot convert", to);
  24.213 +        }
  24.214 +
  24.215 +        possible  = possibleConversions.get(from);
  24.216 +        convertor = possible.get(to);
  24.217 +
  24.218 +        if(convertor == null)
  24.219 +        {
  24.220 +            throw new Error();
  24.221 +        }
  24.222 +
  24.223 +        return (convertor.getConversionRate(from, to));
  24.224 +    }
  24.225 +
  24.226 +    /**
  24.227 +     * Convert an amount from one currency to another.
  24.228 +     * 
  24.229 +     * @param from the currency to convert from.
  24.230 +     * @param to the currency to convert to.
  24.231 +     * @param amount the amount to convert.
  24.232 +     * @return the converted amount.
  24.233 +     * @throws IllegalArgumentException if any of the arguments are null.
  24.234 +     * @throws InvalidConversionException if either from or to are not valid for the convertor.
  24.235 +     */
  24.236 +    public BigDecimal convert(final Currency   from,
  24.237 +                              final Currency   to,
  24.238 +                              final BigDecimal amount)
  24.239 +        throws InvalidConversionException
  24.240 +    {
  24.241 +        final BigDecimal result;
  24.242 +        
  24.243 +        if(amount == null)
  24.244 +        {
  24.245 +            throw new IllegalArgumentException("amount cannot be null");
  24.246 +        }
  24.247 +        
  24.248 +        if(from == null)
  24.249 +        {
  24.250 +            throw new IllegalArgumentException("from cannot be null");
  24.251 +        }
  24.252 +        
  24.253 +        if(to == null)
  24.254 +        {
  24.255 +            throw new IllegalArgumentException("to cannot be null");
  24.256 +        }
  24.257 +
  24.258 +        result = amount.multiply(getConversionRate(from, to));
  24.259 +
  24.260 +        return (result.setScale(2, RoundingMode.HALF_DOWN));
  24.261 +    }
  24.262 +
  24.263 +    /**
  24.264 +     * Create a convertor between two currencies using another currency that is able to convert between both.
  24.265 +     * 
  24.266 +     * @param from the currency to convert from.
  24.267 +     * @param to the currency to convert to.
  24.268 +     * @param intermediary the currency to use as a go-between.
  24.269 +     * @return a Convertor that is able to convert between from an to.
  24.270 +     * @throws IllegalArgumentException if any of the arguments are null.
  24.271 +     */
  24.272 +    private Convertor createConvertor(final Currency from,
  24.273 +                                      final Currency to,
  24.274 +                                      final Currency intermediary) 
  24.275 +    {
  24.276 +        final Convertor fromIntermediary;
  24.277 +        final Convertor toIntermediary;
  24.278 +
  24.279 +        if(from == null)
  24.280 +        {
  24.281 +            throw new IllegalArgumentException("from cannot be null");
  24.282 +        }
  24.283 +        
  24.284 +        if(to == null)
  24.285 +        {
  24.286 +            throw new IllegalArgumentException("to cannot be null");
  24.287 +        }
  24.288 +        
  24.289 +        if(intermediary == null)
  24.290 +        {
  24.291 +            throw new IllegalArgumentException("intermediary cannot be null");
  24.292 +        }
  24.293 +        
  24.294 +        fromIntermediary = possibleConversions.get(from).get(intermediary);
  24.295 +        toIntermediary   = possibleConversions.get(to).get(intermediary);
  24.296 +
  24.297 +        try
  24.298 +        {
  24.299 +            final BigDecimal fromRate;
  24.300 +            final BigDecimal toRate;
  24.301 +            final BigDecimal rate;
  24.302 +            final Convertor  convertor;
  24.303 +            
  24.304 +            fromRate  = fromIntermediary.getConversionRate(from, intermediary);
  24.305 +            toRate    = toIntermediary.getConversionRate(intermediary, to);
  24.306 +            rate      = fromRate.multiply(toRate);
  24.307 +            
  24.308 +            convertor = ConvertorFactory.getConvertor(from, BigDecimal.ONE, to, rate);
  24.309 +            
  24.310 +            return (convertor);
  24.311 +        }
  24.312 +        catch (InvalidConversionException ex)
  24.313 +        {
  24.314 +            throw new Error();
  24.315 +        }
  24.316 +    }
  24.317 +}
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/task3/solution04/src/org/apidesign/apifest08/currency/ConverterImpl.java	Tue Oct 07 11:05:34 2008 +0200
    25.3 @@ -0,0 +1,282 @@
    25.4 +package org.apidesign.apifest08.currency;
    25.5 +
    25.6 +
    25.7 +import java.math.BigDecimal;
    25.8 +import java.math.MathContext;
    25.9 +import java.math.RoundingMode;
   25.10 +import java.util.Collections;
   25.11 +import java.util.Currency;
   25.12 +import java.util.HashSet;
   25.13 +import java.util.Set;
   25.14 +
   25.15 +
   25.16 +/**
   25.17 + * Convert between two currencies.
   25.18 + *
   25.19 + * @author D'Arcy Smith
   25.20 + * @version 1.0
   25.21 + */
   25.22 +final class ConvertorImpl
   25.23 +    implements Convertor
   25.24 +{
   25.25 +    /**
   25.26 +     * The currency to cvonvert from.
   25.27 +     */
   25.28 +    private final Currency currencyA;
   25.29 +
   25.30 +    /**
   25.31 +     * The currency to cvonvert from.
   25.32 +     */
   25.33 +    private final Currency currencyB;
   25.34 +
   25.35 +    /**
   25.36 +     * The echange rate between a and b.
   25.37 +     */
   25.38 +    private final BigDecimal currencyARate;
   25.39 +
   25.40 +    /**
   25.41 +     * The echange rate between b and a.
   25.42 +     */
   25.43 +    private final BigDecimal currencyBRate;
   25.44 +    
   25.45 +    /**
   25.46 +     * Constructs a convertor with the specified currencies.
   25.47 +     * 
   25.48 +     * @param a the currency to convert from.
   25.49 +     * @param aRate the exchage rage between from and to.
   25.50 +     * @param b the currency to convert to.
   25.51 +     * @param bRate the exchage rage between to and from.
   25.52 +     * @throws IllegalArgumentException if either any of the arguments are null or if either rate <= 0.
   25.53 +     */
   25.54 +    public ConvertorImpl(final Currency   a,
   25.55 +                         final BigDecimal aRate,
   25.56 +                         final Currency   b,
   25.57 +                         final BigDecimal bRate)
   25.58 +    {
   25.59 +        if(a == null)
   25.60 +        {
   25.61 +            throw new IllegalArgumentException("a cannot be null");
   25.62 +        }
   25.63 +
   25.64 +        if(b == null)
   25.65 +        {
   25.66 +            throw new IllegalArgumentException("b cannot be null");
   25.67 +        }
   25.68 +
   25.69 +        if(aRate == null)
   25.70 +        {
   25.71 +            throw new IllegalArgumentException("aRate cannot be null");
   25.72 +        }
   25.73 +
   25.74 +        if(bRate == null)
   25.75 +        {
   25.76 +            throw new IllegalArgumentException("bRate cannot be null");
   25.77 +        }
   25.78 +                
   25.79 +        if(aRate.compareTo(BigDecimal.ZERO) <= 0)
   25.80 +        {
   25.81 +            throw new IllegalArgumentException("aRate must be > 0, was: " + aRate);
   25.82 +        }
   25.83 +                
   25.84 +        if(bRate.compareTo(BigDecimal.ZERO) <= 0)
   25.85 +        {
   25.86 +            throw new IllegalArgumentException("bRate must be > 0, was: " + bRate);
   25.87 +        }
   25.88 +        
   25.89 +        currencyA     = a;
   25.90 +        currencyB     = b;
   25.91 +        currencyARate = aRate;
   25.92 +        currencyBRate = bRate;
   25.93 +    }
   25.94 +    
   25.95 +    /**
   25.96 +     * Convert an amount from one currency to another.
   25.97 +     * 
   25.98 +     * @param from the currency to convert from.
   25.99 +     * @param to the currency to convert to.
  25.100 +     * @param amount the amount to convert.
  25.101 +     * @return the converted amount.
  25.102 +     * @throws IllegalArgumentException if any of the arguments are null.
  25.103 +     * @throws InvalidConversionException if either from or to are not equal to the currencies passed to the constructor.
  25.104 +     */
  25.105 +    public BigDecimal convert(final Currency   from,
  25.106 +                              final Currency   to,
  25.107 +                              final BigDecimal amount)
  25.108 +        throws InvalidConversionException
  25.109 +    {
  25.110 +        final BigDecimal result;
  25.111 +        
  25.112 +        if(amount == null)
  25.113 +        {
  25.114 +            throw new IllegalArgumentException("amount cannot be null");
  25.115 +        }
  25.116 +        
  25.117 +        if(from == null)
  25.118 +        {
  25.119 +            throw new IllegalArgumentException("from cannot be null");
  25.120 +        }
  25.121 +        
  25.122 +        if(to == null)
  25.123 +        {
  25.124 +            throw new IllegalArgumentException("to cannot be null");
  25.125 +        }
  25.126 +        
  25.127 +        if(!(from.equals(currencyA)) && (!(from.equals(currencyB))))
  25.128 +        {
  25.129 +            throw new InvalidConversionException("cannot convert from: " + from.getCurrencyCode(), from, currencyA, currencyB);
  25.130 +        }
  25.131 +        
  25.132 +        if(!(to.equals(currencyA)) && (!(to.equals(currencyB))))
  25.133 +        {
  25.134 +            throw new InvalidConversionException("cannot convert to: " + to.getCurrencyCode(), to, currencyA, currencyB);
  25.135 +        }
  25.136 +
  25.137 +        result = amount.multiply(getConversionRate(from, to));
  25.138 +
  25.139 +        return (result.setScale(2, RoundingMode.HALF_DOWN));
  25.140 +    }
  25.141 +
  25.142 +    /**
  25.143 +     * Check to see if converting between the two currencies is possible.
  25.144 +     * 
  25.145 +     * @param from the currency to convert from.
  25.146 +     * @param to the currency to convert to.
  25.147 +     * @return true if the conversion is possible.
  25.148 +     */
  25.149 +    public boolean canConvert(final Currency from, final Currency to)
  25.150 +    {
  25.151 +        return ((from.equals(currencyA) || from.equals(currencyB)) &&
  25.152 +                (to.equals(currencyA)   || to.equals(currencyB)));
  25.153 +    }
  25.154 +
  25.155 +    /**
  25.156 +     * Get the currencies that the convertor supports.
  25.157 +     * 
  25.158 +     * @return the supported currencies.
  25.159 +     */
  25.160 +    public Set<Currency> getCurrencies()
  25.161 +    {
  25.162 +        final Set<Currency> currencies;
  25.163 +        
  25.164 +        currencies = new HashSet<Currency>();
  25.165 +        currencies.add(currencyA);
  25.166 +        currencies.add(currencyB);
  25.167 +
  25.168 +        return (Collections.unmodifiableSet(currencies));
  25.169 +    }
  25.170 +
  25.171 +    /**
  25.172 +     * Get the conversion rate between two currencies.
  25.173 +     * 
  25.174 +     * @param from the currency to convert from.
  25.175 +     * @param to the currency to convert to.
  25.176 +     * @return the conversion rate between the two currencies.
  25.177 +     * @throws InvalidConversionException if canConvert would return false.
  25.178 +     */
  25.179 +    public BigDecimal getConversionRate(final Currency from, 
  25.180 +                                        final Currency to)
  25.181 +        throws InvalidConversionException
  25.182 +    {
  25.183 +        final BigDecimal rate;
  25.184 +
  25.185 +        if(from.equals(to))
  25.186 +        {
  25.187 +            rate = BigDecimal.ONE;
  25.188 +        }
  25.189 +        else 
  25.190 +        {
  25.191 +            final BigDecimal rateX;
  25.192 +            final BigDecimal rateY;
  25.193 +            final BigDecimal temp;
  25.194 +            
  25.195 +            if(from.equals(currencyA))
  25.196 +            {
  25.197 +                rateX = currencyARate;
  25.198 +                rateY = currencyBRate;
  25.199 +            }
  25.200 +            else
  25.201 +            {
  25.202 +                rateX = currencyBRate;
  25.203 +                rateY = currencyARate;
  25.204 +            }
  25.205 +
  25.206 +            temp = BigDecimal.ONE.divide(rateX, MathContext.DECIMAL64);
  25.207 +            rate = temp.multiply(rateY);
  25.208 +        }
  25.209 +        
  25.210 +        return (rate.setScale(20, RoundingMode.HALF_EVEN));
  25.211 +    }
  25.212 +
  25.213 +    /**
  25.214 +     * Check to see if two ConvertorImpls are equal.
  25.215 +     *
  25.216 +     * @param obj the object to check
  25.217 +     * @return if the ConvertorImpls are not the same (cuyrrencies and rates).
  25.218 +     */
  25.219 +    @Override
  25.220 +    public boolean equals(Object obj)
  25.221 +    {
  25.222 +        if (obj == null)
  25.223 +        {
  25.224 +            return false;
  25.225 +        }
  25.226 +        
  25.227 +        if (getClass() != obj.getClass())
  25.228 +        {
  25.229 +            return false;
  25.230 +        }
  25.231 +
  25.232 +        final ConvertorImpl other = (ConvertorImpl) obj;
  25.233 +
  25.234 +        // it would be nice if NetBeans could chck to see if the variable is final and guaranteed not to be null... but that
  25.235 +        // would likely be tricky... but in a NetBeans engineer reads that see if you can do it :-)
  25.236 +        if (this.currencyA != other.currencyA && (this.currencyA == null || !this.currencyA.equals(other.currencyA)))
  25.237 +        {
  25.238 +            return false;
  25.239 +        }
  25.240 +        
  25.241 +        if (this.currencyB != other.currencyB && (this.currencyB == null || !this.currencyB.equals(other.currencyB)))
  25.242 +        {
  25.243 +            return false;
  25.244 +        }
  25.245 +        
  25.246 +        if (this.currencyARate != other.currencyARate && (this.currencyARate == null || !this.currencyARate.equals(other.currencyARate)))
  25.247 +        {
  25.248 +            return false;
  25.249 +        }
  25.250 +        
  25.251 +        if (this.currencyBRate != other.currencyBRate && (this.currencyBRate == null || !this.currencyBRate.equals(other.currencyBRate)))
  25.252 +        {
  25.253 +            return false;
  25.254 +        }
  25.255 +
  25.256 +        return true;
  25.257 +    }
  25.258 +
  25.259 +    /**
  25.260 +     * Get the hashCode of the Convertor.
  25.261 +     *
  25.262 +     * @return the hashCode of the convertor.
  25.263 +     */
  25.264 +    @Override
  25.265 +    public int hashCode()
  25.266 +    {
  25.267 +        int hash = 7;
  25.268 +        hash = 37 * hash + (this.currencyA != null ? this.currencyA.hashCode() : 0);
  25.269 +        hash = 37 * hash + (this.currencyB != null ? this.currencyB.hashCode() : 0);
  25.270 +        hash = 37 * hash + (this.currencyARate != null ? this.currencyARate.hashCode() : 0);
  25.271 +        hash = 37 * hash + (this.currencyBRate != null ? this.currencyBRate.hashCode() : 0);
  25.272 +        return hash;
  25.273 +    }
  25.274 +
  25.275 +    /**
  25.276 +     * Get the currencyCode of both currencies.
  25.277 +     *
  25.278 +     * @return the currency codes of both currencies.
  25.279 +     */
  25.280 +    @Override
  25.281 +    public String toString()
  25.282 +    {
  25.283 +        return (currencyA.getCurrencyCode() + " to " + currencyB.getCurrencyCode());
  25.284 +    }
  25.285 +}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/task3/solution04/src/org/apidesign/apifest08/currency/Convertor.java	Tue Oct 07 11:05:34 2008 +0200
    26.3 @@ -0,0 +1,59 @@
    26.4 +package org.apidesign.apifest08.currency;
    26.5 +
    26.6 +
    26.7 +import java.math.BigDecimal;
    26.8 +import java.util.Currency;
    26.9 +import java.util.Set;
   26.10 +
   26.11 +
   26.12 +/**
   26.13 + * Convert between two currencies.
   26.14 + *
   26.15 + * @author D'Arcy Smith
   26.16 + * @version 1.0
   26.17 + */
   26.18 +public interface Convertor
   26.19 +{
   26.20 +    /**
   26.21 +     * Convert an amount from one currency to another.
   26.22 +     * 
   26.23 +     * @param from the currency to convert from.
   26.24 +     * @param to the currency to convert to.
   26.25 +     * @param amount the amount to convert.
   26.26 +     * @return the converted amount.
   26.27 +     * @throws IllegalArgumentException if any of the arguments are null.
   26.28 +     * @throws InvalidConversionException if either from or to are not valid for the convertor.
   26.29 +     */
   26.30 +    BigDecimal convert(Currency   from, 
   26.31 +                       Currency   to, 
   26.32 +                       BigDecimal amount)
   26.33 +        throws InvalidConversionException;
   26.34 +
   26.35 +    /**
   26.36 +     * Check to see if converting between the two currencies is possible.
   26.37 +     *
   26.38 +     * @param from the currency to convert from.
   26.39 +     * @param to the currency to convert to.
   26.40 +     * @return true if the conversion is possible.
   26.41 +     */
   26.42 +    boolean canConvert(Currency from, Currency to);
   26.43 +
   26.44 +    /**
   26.45 +     * Get the currencies that the convertor supports.  Just because a currency is
   26.46 +     * supported does not mean that canConvert will return true.
   26.47 +     * 
   26.48 +     * @return the supported currencies.
   26.49 +     */
   26.50 +    Set<Currency> getCurrencies();
   26.51 +
   26.52 +    /**
   26.53 +     * Get the conversion rate between two currencies.
   26.54 +     * 
   26.55 +     * @param from the currency to convert from.
   26.56 +     * @param to the currency to convert to.
   26.57 +     * @return the conversion rate between the two currencies.
   26.58 +     * @throws InvalidConversionException if canConvert would return false.
   26.59 +     */
   26.60 +    BigDecimal getConversionRate(final Currency from, final Currency to)
   26.61 +        throws InvalidConversionException;
   26.62 +}
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/task3/solution04/src/org/apidesign/apifest08/currency/ConvertorFactory.java	Tue Oct 07 11:05:34 2008 +0200
    27.3 @@ -0,0 +1,172 @@
    27.4 +package org.apidesign.apifest08.currency;
    27.5 +
    27.6 +import java.math.BigDecimal;
    27.7 +import java.util.Currency;
    27.8 +
    27.9 +
   27.10 +/**
   27.11 + * Create convertors using a flyweight to reduce the number of repetative creations of the same convertor.
   27.12 + * 
   27.13 + * @author D'Arcy Smith
   27.14 + * @version 1.0
   27.15 + */
   27.16 +public final class ConvertorFactory
   27.17 +{
   27.18 +    /*
   27.19 +     * flyweight so that only one vestion of each converter is created at a time.
   27.20 +    private final static Map<String, WeakReference<Convertor>> convertors;
   27.21 +    
   27.22 +    static
   27.23 +    {
   27.24 +        convertors = new WeakHashMap<String, WeakReference<Convertor>>();
   27.25 +    }
   27.26 +    */
   27.27 +    
   27.28 +    /** 
   27.29 +     * Prevent accidental construction.
   27.30 +     */
   27.31 +    private ConvertorFactory()
   27.32 +    {        
   27.33 +    }
   27.34 +    
   27.35 +    /**
   27.36 +     * Get the convertor for the specified currencies.  The currency name format
   27.37 +     * must be acceptable to java.util.Currency.getInstance(String)
   27.38 +     * 
   27.39 +     * @param a the currency to convert from.
   27.40 +     * @param aRate the exchange rate for a to b.
   27.41 +     * @param b the currency to convert to.
   27.42 +     * @param bRate the echante rate for b to a.
   27.43 +     * @return the convertor for the specified currencies.
   27.44 +     * @throws IllegalArgumentException if any of the arguments are null.
   27.45 +     */
   27.46 +    public static Convertor getConvertor(final String     a,
   27.47 +                                         final BigDecimal aRate,
   27.48 +                                         final String     b,
   27.49 +                                         final BigDecimal bRate)
   27.50 +    {
   27.51 +        final Currency  currencyA;
   27.52 +        final Currency  currencyB;
   27.53 +        final Convertor convertor;
   27.54 +        
   27.55 +        currencyA = Currency.getInstance(a);
   27.56 +        currencyB = Currency.getInstance(b);        
   27.57 +        convertor = getConvertor(currencyA, aRate, currencyB, bRate);
   27.58 +        
   27.59 +        return (convertor);
   27.60 +    }
   27.61 +    
   27.62 +    /**
   27.63 +     * Get the convertor for the specified currencies.
   27.64 +     * 
   27.65 +     * @param a the currency to convert from.
   27.66 +     * @param aRate the exchange rate for a to b.
   27.67 +     * @param b the currency to convert to.
   27.68 +     * @param bRate the echante rate for b to a.
   27.69 +     * @return the convertor for the specified currencies.
   27.70 +     * @throws IllegalArgumentException if either any of the arguments are null or if either rate <= 0.
   27.71 +     */
   27.72 +    public static Convertor getConvertor(final Currency   a,
   27.73 +                                         final BigDecimal aRate,
   27.74 +                                         final Currency   b,
   27.75 +                                         final BigDecimal bRate)
   27.76 +    {
   27.77 +        // final String key;        
   27.78 +        Convertor    convertor;
   27.79 +
   27.80 +        if(a == null)
   27.81 +        {
   27.82 +            throw new IllegalArgumentException("a cannot be null");
   27.83 +        }
   27.84 +
   27.85 +        if(b == null)
   27.86 +        {
   27.87 +            throw new IllegalArgumentException("b cannot be null");
   27.88 +        }
   27.89 +        
   27.90 +        if(aRate == null)
   27.91 +        {
   27.92 +            throw new IllegalArgumentException("aRate cannot be null");
   27.93 +        }
   27.94 +        
   27.95 +        if(bRate == null)
   27.96 +        {
   27.97 +            throw new IllegalArgumentException("bRate cannot be null");
   27.98 +        }
   27.99 +
  27.100 +        /*
  27.101 +        key = a.getCurrencyCode() + aRate + b.getCurrencyCode() + bRate;
  27.102 +
  27.103 +        // make sure that we don't try to overwrite one
  27.104 +        synchronized(convertors)
  27.105 +        {
  27.106 +            if(!(convertors.containsKey(key)))
  27.107 +            {        
  27.108 +                convertor = new ConvertorImpl(a, aRate, b, bRate);
  27.109 +                convertors.put(key, new WeakReference(convertor));
  27.110 +            }
  27.111 +
  27.112 +            convertor = convertors.get(key).get();
  27.113 +        }
  27.114 +        */
  27.115 +        
  27.116 +        convertor = new ConvertorImpl(a, aRate, b, bRate);
  27.117 +                
  27.118 +        return (convertor);
  27.119 +    }
  27.120 +    
  27.121 +    public static Convertor mergeConvertors(final Convertor ... cs)
  27.122 +    {
  27.123 +        Convertor convertor;
  27.124 +        
  27.125 +        /*
  27.126 +        final String key;
  27.127 +
  27.128 +        // ISSUE: only takes into account the names... not the rates...
  27.129 +        key = getKey(cs);
  27.130 +
  27.131 +        // make sure that we don't try to overwrite one
  27.132 +        synchronized(convertors)
  27.133 +        {
  27.134 +            if(!(convertors.containsKey(key)))
  27.135 +            {        
  27.136 +                convertor = new CompositeConvertorImpl(cs);
  27.137 +                convertors.put(key, new WeakReference(convertor));
  27.138 +            }
  27.139 +
  27.140 +            convertor = convertors.get(key).get();
  27.141 +        }
  27.142 +        */
  27.143 +        
  27.144 +        convertor = new CompositeConvertorImpl(cs);
  27.145 +        
  27.146 +        return (convertor);
  27.147 +    }
  27.148 +
  27.149 +    /*
  27.150 +    private static String getKey(final Convertor ... cs)
  27.151 +    {
  27.152 +        final Set<Currency> currencies;
  27.153 +        final StringBuilder builder;
  27.154 +        
  27.155 +        currencies = new HashSet<Currency>();
  27.156 +        
  27.157 +        for(final Convertor convertor : cs)
  27.158 +        {
  27.159 +            final Set<Currency> c;
  27.160 +            
  27.161 +            c = convertor.getCurrencies();
  27.162 +            currencies.addAll(c);
  27.163 +        }
  27.164 +        
  27.165 +        builder = new StringBuilder();
  27.166 +
  27.167 +        for(final Currency currency : currencies)
  27.168 +        {
  27.169 +            builder.append(currency.getCurrencyCode());
  27.170 +        }
  27.171 +        
  27.172 +        return (builder.toString());
  27.173 +    }
  27.174 +    */
  27.175 +}
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/task3/solution04/src/org/apidesign/apifest08/currency/InvalidConversionException.java	Tue Oct 07 11:05:34 2008 +0200
    28.3 @@ -0,0 +1,95 @@
    28.4 +package org.apidesign.apifest08.currency;
    28.5 +
    28.6 +      
    28.7 +import java.util.Currency;
    28.8 +
    28.9 +
   28.10 +/**
   28.11 + * Thrown when a currency is invalid for a given Convertor.
   28.12 + * 
   28.13 + * @author D'Arcy Smith
   28.14 + * @version 1.0
   28.15 + */
   28.16 +public class InvalidConversionException
   28.17 +    extends Exception
   28.18 +{
   28.19 +    /**
   28.20 +     * The currency that was tried.
   28.21 +     */
   28.22 +    private final Currency badCurrency;
   28.23 +    
   28.24 +    /**
   28.25 +     * A currency that is valid for the Convertor.
   28.26 +     */
   28.27 +    private final Currency currencyA;
   28.28 +
   28.29 +    /**
   28.30 +     * A currency that is valid for the Convertor.
   28.31 +     */
   28.32 +    private final Currency currencyB;
   28.33 +    
   28.34 +    
   28.35 +    /**
   28.36 +     * Construct a new InvalidConversionException with the specified message.
   28.37 +     * 
   28.38 +     * @param msg the message for getMessage.
   28.39 +     * @param bad the currency that is not valid.
   28.40 +     */
   28.41 +    public InvalidConversionException(final String   msg,
   28.42 +                                      final Currency bad)
   28.43 +    {
   28.44 +        this(msg, bad, null, null);
   28.45 +    }
   28.46 +
   28.47 +    /**
   28.48 +     * Construct a new InvalidConversionException with the specified message.
   28.49 +     * 
   28.50 +     * @param msg the message for getMessage.
   28.51 +     * @param bad the currency that is not valid.
   28.52 +     * @param a a valid currency.
   28.53 +     * @param b a valid currency.
   28.54 +     */
   28.55 +    public InvalidConversionException(final String   msg,
   28.56 +                                      final Currency bad,
   28.57 +                                      final Currency a,
   28.58 +                                      final Currency b)
   28.59 +    {
   28.60 +        super(msg);
   28.61 +
   28.62 +        badCurrency = bad;
   28.63 +        currencyA   = a;
   28.64 +        currencyB   = b;
   28.65 +    }
   28.66 +
   28.67 +    /**
   28.68 +     * Get the currency that is not valid.
   28.69 +     * 
   28.70 +     * @return the badCurrency
   28.71 +     */
   28.72 +    public Currency getBadCurrency()
   28.73 +    {
   28.74 +        return (badCurrency);
   28.75 +    }
   28.76 +
   28.77 +    /**
   28.78 +     * Get a currency that is valid.
   28.79 +     * 
   28.80 +     * @return the currencyA passed to the constructor.
   28.81 +     */
   28.82 +    public Currency getCurrencyA()
   28.83 +    {
   28.84 +        return (currencyA);
   28.85 +    }
   28.86 +
   28.87 +    /**
   28.88 +     * Get a currency that is valid.
   28.89 +     * 
   28.90 +     * @return the currencyB passed to the constructor.
   28.91 +     */
   28.92 +    public Currency getCurrencyB()
   28.93 +    {
   28.94 +        return (currencyB);
   28.95 +    }
   28.96 +
   28.97 +
   28.98 +}
   28.99 \ No newline at end of file
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/task3/solution04/test/org/apidesign/apifest08/test/Task1Test.java	Tue Oct 07 11:05:34 2008 +0200
    29.3 @@ -0,0 +1,223 @@
    29.4 +package org.apidesign.apifest08.test;
    29.5 +
    29.6 +
    29.7 +import java.math.BigDecimal;
    29.8 +import java.util.Currency;
    29.9 +import java.util.Set;
   29.10 +import junit.framework.TestCase;
   29.11 +import org.apidesign.apifest08.currency.Convertor;
   29.12 +import org.apidesign.apifest08.currency.ConvertorFactory;
   29.13 +import org.apidesign.apifest08.currency.InvalidConversionException;
   29.14 +
   29.15 +
   29.16 +/** Finish the Convertor API, and then write bodies of methods inside
   29.17 + * of this class to match the given tasks. To fullfil your task, use the
   29.18 + * API define in the <code>org.apidesign.apifest08.currency</code> package.
   29.19 + * Do not you reflection, or other hacks as your code
   29.20 + * shall run without any runtime permissions.
   29.21 + */
   29.22 +public class Task1Test extends TestCase {
   29.23 +    
   29.24 +    private final static Currency CZK;
   29.25 +    private final static Currency SKK;
   29.26 +    private final static Currency USD;
   29.27 +
   29.28 +    static
   29.29 +    {
   29.30 +        CZK = Currency.getInstance("CZK");
   29.31 +        SKK = Currency.getInstance("SKK");
   29.32 +        USD = Currency.getInstance("USD");
   29.33 +    }
   29.34 +    
   29.35 +    public Task1Test(String testName) {
   29.36 +        super(testName);
   29.37 +    }
   29.38 +
   29.39 +    @Override
   29.40 +    protected void setUp() throws Exception {
   29.41 +    }
   29.42 +
   29.43 +    @Override
   29.44 +    protected void tearDown() throws Exception {
   29.45 +    }
   29.46 +
   29.47 +    /** Create convertor that understands two currencies, CZK and
   29.48 +     *  USD. Make 1 USD == 17 CZK.
   29.49 +     *
   29.50 +     * Creation of the convertor shall not require subclassing of any class
   29.51 +     * or interface on the client side.
   29.52 +     *
   29.53 +     * @return prepared convertor ready for converting USD to CZK and CZK to USD
   29.54 +     */
   29.55 +    public static Convertor createCZKtoUSD()
   29.56 +    {
   29.57 +        return (ConvertorFactory.getConvertor("CZK", BigDecimal.valueOf(17.0),
   29.58 +                                              "USD", BigDecimal.valueOf(1)));
   29.59 +    }
   29.60 +
   29.61 +    /** Create convertor that understands two currencies, CZK and
   29.62 +     *  SKK. Make 100 SKK == 80 CZK.
   29.63 +     *
   29.64 +     * Creation of the convertor shall not require subclassing of any class
   29.65 +     * or interface on the client side.
   29.66 +     * 
   29.67 +     * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
   29.68 +     */
   29.69 +    public static Convertor createSKKtoCZK()
   29.70 +    {
   29.71 +        return (ConvertorFactory.getConvertor(Currency.getInstance("SKK"), BigDecimal.valueOf(100),
   29.72 +                                              Currency.getInstance("CZK"), BigDecimal.valueOf(80)));
   29.73 +    }
   29.74 +    
   29.75 +    /** Use the convertor from <code>createCZKtoUSD</code> method and do few conversions
   29.76 +     * with it.
   29.77 +     */
   29.78 +    public void testCurrencyCZKUSD() throws Exception {
   29.79 +        Convertor  c = createCZKtoUSD();
   29.80 +        BigDecimal result;
   29.81 +        
   29.82 +        // convert $5 to CZK using c:
   29.83 +        // assertEquals("Result is 85 CZK");
   29.84 +        result = c.convert(USD, CZK, BigDecimal.valueOf(5));
   29.85 +        assertEquals(new BigDecimal("85.00"), result);
   29.86 +
   29.87 +        // convert $8 to CZK
   29.88 +        // assertEquals("Result is 136 CZK");
   29.89 +        result = c.convert(USD, CZK, BigDecimal.valueOf(8));
   29.90 +        assertEquals(new BigDecimal("136.00"), result);
   29.91 +
   29.92 +        // convert 1003CZK to USD
   29.93 +        // assertEquals("Result is 59 USD");
   29.94 +        result = c.convert(CZK, USD, BigDecimal.valueOf(1003));
   29.95 +        assertEquals(new BigDecimal("59.00"), result);
   29.96 +    }
   29.97 +
   29.98 +    /** Use the convertor from <code>createSKKtoCZK</code> method and do few conversions
   29.99 +     * with it.
  29.100 +     */
  29.101 +    public void testCurrencySKKCZK() throws Exception {
  29.102 +        Convertor c = createSKKtoCZK();
  29.103 +        BigDecimal result;
  29.104 +        
  29.105 +        // convert 16CZK using c:
  29.106 +        // assertEquals("Result is 20 SKK");
  29.107 +        result = c.convert(CZK, SKK, BigDecimal.valueOf(16));
  29.108 +        assertEquals(new BigDecimal("20.00"), result);
  29.109 +                        
  29.110 +        // convert 500SKK to CZK
  29.111 +        // assertEquals("Result is 400 CZK");
  29.112 +        result = c.convert(SKK, CZK, BigDecimal.valueOf(500));
  29.113 +        assertEquals(new BigDecimal("400.00"), result);
  29.114 +   }
  29.115 +
  29.116 +    /** 
  29.117 +     * Verify that the CZK to USD convertor knows nothing about SKK.
  29.118 +     */
  29.119 +    public void testCannotConvertToSKKwithCZKUSDConvertor() 
  29.120 +        throws Exception 
  29.121 +    {
  29.122 +        Convertor c = createCZKtoUSD();
  29.123 +        
  29.124 +        try
  29.125 +        {
  29.126 +            // convert $5 to SKK, the API shall say this is not possible
  29.127 +            c.convert(USD, SKK, BigDecimal.valueOf(5));
  29.128 +            fail("cannot use the CZKtoUSD converter to convert to SKK");
  29.129 +        }
  29.130 +        catch(InvalidConversionException ex)
  29.131 +        {       
  29.132 +            assertEquals("cannot convert to: SKK", ex.getMessage());
  29.133 +            assertEquals(SKK, ex.getBadCurrency());
  29.134 +            assertEquals(CZK, ex.getCurrencyA());
  29.135 +            assertEquals(USD, ex.getCurrencyB());
  29.136 +        }
  29.137 +
  29.138 +        try
  29.139 +        {
  29.140 +            // convert 500 SKK to CZK, the API shall say this is not possible
  29.141 +            c.convert(SKK, CZK, BigDecimal.valueOf(5));
  29.142 +            fail("cannot use the CZKtoUSD converter to convert from SKK");
  29.143 +        }
  29.144 +        catch(InvalidConversionException ex)
  29.145 +        {            
  29.146 +            assertEquals("cannot convert from: SKK", ex.getMessage());
  29.147 +            assertEquals(SKK, ex.getBadCurrency());
  29.148 +            assertEquals(CZK, ex.getCurrencyA());
  29.149 +            assertEquals(USD, ex.getCurrencyB());
  29.150 +        }
  29.151 +    }
  29.152 +    
  29.153 +    /** 
  29.154 +     * Verify that the CZK to SKK convertor knows nothing about USD.
  29.155 +     */
  29.156 +    public void testCannotConvertToUSDwithSKKCZKConvertor() 
  29.157 +        throws Exception 
  29.158 +    {
  29.159 +        Convertor c = createSKKtoCZK();
  29.160 +        
  29.161 +        try
  29.162 +        {
  29.163 +            // convert $5 to SKK, the API shall say this is not possible
  29.164 +            c.convert(USD, SKK, BigDecimal.valueOf(5));
  29.165 +            fail("cannot use the CZKtoUSD converter to convert to SKK");
  29.166 +        }
  29.167 +        catch(InvalidConversionException ex)
  29.168 +        {       
  29.169 +            assertEquals("cannot convert from: USD", ex.getMessage());
  29.170 +            assertEquals(USD, ex.getBadCurrency());
  29.171 +            assertEquals(SKK, ex.getCurrencyA());
  29.172 +            assertEquals(CZK, ex.getCurrencyB());
  29.173 +        }
  29.174 +
  29.175 +        try
  29.176 +        {
  29.177 +            // convert 500 CZK to USD, the API shall say this is not possible
  29.178 +            c.convert(CZK, USD, BigDecimal.valueOf(500));
  29.179 +            fail("cannot use the CZKtoUSD converter to convert from SKK");
  29.180 +        }
  29.181 +        catch(InvalidConversionException ex)
  29.182 +        {            
  29.183 +            assertEquals("cannot convert to: USD", ex.getMessage());
  29.184 +            assertEquals(USD, ex.getBadCurrency());
  29.185 +            assertEquals(SKK, ex.getCurrencyA());
  29.186 +            assertEquals(CZK, ex.getCurrencyB());
  29.187 +        }
  29.188 +    }
  29.189 +    
  29.190 +    public void testGetCurrencies()
  29.191 +    {
  29.192 +        Convertor           c;
  29.193 +        Set<Currency> currencies;
  29.194 +        
  29.195 +        c          = createSKKtoCZK();
  29.196 +        currencies = c.getCurrencies();        
  29.197 +        assertEquals(2, currencies.size());
  29.198 +        assertTrue(currencies.contains(Currency.getInstance("SKK")));
  29.199 +        assertTrue(currencies.contains(Currency.getInstance("CZK")));
  29.200 +
  29.201 +        c          = createCZKtoUSD();
  29.202 +        currencies = c.getCurrencies();        
  29.203 +        assertEquals(2, currencies.size());
  29.204 +        assertTrue(currencies.contains(Currency.getInstance("USD")));
  29.205 +        assertTrue(currencies.contains(Currency.getInstance("CZK")));
  29.206 +    }
  29.207 +    
  29.208 +    public void testGetConverstionRate()
  29.209 +        throws InvalidConversionException
  29.210 +    {
  29.211 +        Convertor c;
  29.212 +       
  29.213 +        c = createSKKtoCZK();
  29.214 +        assertEquals(1.0,  c.getConversionRate(Currency.getInstance("CZK"), Currency.getInstance("CZK")).doubleValue());
  29.215 +        assertEquals(1.0,  c.getConversionRate(Currency.getInstance("SKK"), Currency.getInstance("SKK")).doubleValue());
  29.216 +        assertEquals(0.80, c.getConversionRate(Currency.getInstance("SKK"), Currency.getInstance("CZK")).doubleValue());
  29.217 +        assertEquals(1.25, c.getConversionRate(Currency.getInstance("CZK"), Currency.getInstance("SKK")).doubleValue());
  29.218 +
  29.219 +        c = createCZKtoUSD();
  29.220 +        assertEquals(1.0,      c.getConversionRate(Currency.getInstance("CZK"), Currency.getInstance("CZK")).doubleValue());
  29.221 +        assertEquals(1.0,      c.getConversionRate(Currency.getInstance("USD"), Currency.getInstance("USD")).doubleValue());
  29.222 +        assertEquals(1.0/17.0, c.getConversionRate(Currency.getInstance("CZK"), Currency.getInstance("USD")).doubleValue(), 0.00000000000000001);
  29.223 +        assertEquals(17.0,     c.getConversionRate(Currency.getInstance("USD"), Currency.getInstance("CZK")).doubleValue(), 0.00000000000000001);
  29.224 +    }
  29.225 +}
  29.226 +
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/task3/solution04/test/org/apidesign/apifest08/test/Task2Test.java	Tue Oct 07 11:05:34 2008 +0200
    30.3 @@ -0,0 +1,179 @@
    30.4 +package org.apidesign.apifest08.test;
    30.5 +
    30.6 +import java.math.BigDecimal;
    30.7 +import java.util.Currency;
    30.8 +import java.util.Set;
    30.9 +import junit.framework.TestCase;
   30.10 +import org.apidesign.apifest08.currency.Convertor;
   30.11 +import org.apidesign.apifest08.currency.ConvertorFactory;
   30.12 +import org.apidesign.apifest08.currency.InvalidConversionException;
   30.13 +
   30.14 +
   30.15 +/** There are many currencies around the world and many banks manipulate
   30.16 + * with more than one or two at the same time. As banks are usually the
   30.17 + * best paying clients, which is true even in case of your Convertor API,
   30.18 + * it is reasonable to listen to their requests.
   30.19 + * <p>
   30.20 + * The quest for today is to enhance your existing convertor API to hold
   30.21 + * information about many currencies and allow conversions between any of them.
   30.22 + * Also, as conversion rates for diferent currencies usually arise from various
   30.23 + * bank departments, there is another important need. There is a need to
   30.24 + * compose two convertors into one by merging all the information about
   30.25 + * currencies they know about.
   30.26 + */
   30.27 +public class Task2Test extends TestCase
   30.28 +{
   30.29 +    private final static Currency CZK;
   30.30 +    private final static Currency SKK;
   30.31 +    private final static Currency USD;
   30.32 +
   30.33 +    static
   30.34 +    {
   30.35 +        CZK = Currency.getInstance("CZK");
   30.36 +        SKK = Currency.getInstance("SKK");
   30.37 +        USD = Currency.getInstance("USD");
   30.38 +    }
   30.39 +
   30.40 +    public Task2Test(String testName)
   30.41 +    {
   30.42 +        super(testName);
   30.43 +    }
   30.44 +
   30.45 +    @Override
   30.46 +    protected void setUp() 
   30.47 +        throws Exception
   30.48 +    {
   30.49 +    }
   30.50 +
   30.51 +    @Override
   30.52 +    protected void tearDown() 
   30.53 +        throws Exception
   30.54 +    {
   30.55 +    }
   30.56 +
   30.57 +    // As in Task1Test, keep in mind, that there are three parts
   30.58 +    // of the whole system:
   30.59 +    // 1. there is someone who knows the current exchange rate
   30.60 +    // 2. there is someone who wants to do the conversion
   30.61 +    // 3. there is the API between 1. and 2. which allows them to communicate
   30.62 +    // 
   30.63 +    // Please backward compatibly enhance your existing API to support following
   30.64 +    // usecases:
   30.65 +    //
   30.66 +    
   30.67 +    /** Create convertor that understands two currencies, CZK and
   30.68 +     *  SKK. Make 100 SKK == 75 CZK. This is method for the group of users that
   30.69 +     *  knows the exchange rate, and needs to use the API to create objects
   30.70 +     *  with the exchange rate. Anyone shall be ready to call this method without
   30.71 +     *  any other method being called previously. The API itself shall know
   30.72 +     *  nothing about any rates, before this method is called.
   30.73 +     */
   30.74 +    public static Convertor createTripleConvertor() {
   30.75 +        // Rates: 1USD = 15CZK
   30.76 +        // Rates: 1USD = 20SKK
   30.77 +        // Rates: 75CZK = 100SKK
   30.78 +        Convertor c = ConvertorFactory.mergeConvertors(
   30.79 +            ConvertorFactory.getConvertor(USD, BigDecimal.ONE, CZK, BigDecimal.valueOf(15.00)),
   30.80 +            ConvertorFactory.getConvertor(USD, BigDecimal.ONE, SKK, BigDecimal.valueOf(20.00))
   30.81 +        );
   30.82 +        
   30.83 +        return c;
   30.84 +    }
   30.85 +
   30.86 +    /** Define convertor that understands three currencies. Use it.
   30.87 +     */
   30.88 +    public void testConvertorForUSDandCZKandSKK() throws Exception {
   30.89 +        Convertor c = createTripleConvertor();
   30.90 +
   30.91 +        // convert $5 to CZK using c:
   30.92 +        // assertEquals("Result is 75 CZK");
   30.93 +        assertEquals(new BigDecimal("75.00"), c.convert(USD, CZK, BigDecimal.valueOf(5.00)));
   30.94 +
   30.95 +        // convert $5 to SKK using c:
   30.96 +        // assertEquals("Result is 100 SKK");
   30.97 +        assertEquals(new BigDecimal("100.00"), c.convert(USD, SKK, BigDecimal.valueOf(5.00)));
   30.98 +
   30.99 +        // convert 200SKK to CZK using c:
  30.100 +        // assertEquals("Result is 150 CZK");
  30.101 +        assertEquals(new BigDecimal("150.00"), c.convert(SKK, CZK, BigDecimal.valueOf(200.00)));
  30.102 +
  30.103 +        // convert 200SKK to USK using c:
  30.104 +        // assertEquals("Result is 10 USD");
  30.105 +        assertEquals(new BigDecimal("10.00"), c.convert(SKK, USD, BigDecimal.valueOf(200.00)));
  30.106 +    }
  30.107 +
  30.108 +    /** Merge all currency rates of convertor 1 with convertor 2.
  30.109 +     * Implement this using your API, preferably this method just delegates
  30.110 +     * into some API method which does the actual work, without requiring
  30.111 +     * API clients to code anything complex.
  30.112 +     */
  30.113 +    public static Convertor merge(Convertor one, Convertor two) {
  30.114 +        return ConvertorFactory.mergeConvertors(one, two);
  30.115 +    }
  30.116 +
  30.117 +    /** Join the convertors from previous task, Task1Test and show that it
  30.118 +     * can be used to do reasonable conversions.
  30.119 +     */
  30.120 +    public void testConvertorComposition() throws Exception {
  30.121 +        Convertor c = merge(
  30.122 +            Task1Test.createCZKtoUSD(),
  30.123 +            Task1Test.createSKKtoCZK()
  30.124 +        );
  30.125 +
  30.126 +        // convert $5 to CZK using c:
  30.127 +        // assertEquals("Result is 85 CZK");
  30.128 +        assertEquals(new BigDecimal("85.00"), c.convert(USD, CZK, BigDecimal.valueOf(5.00)));
  30.129 +
  30.130 +        // convert $8 to CZK using c:
  30.131 +        // assertEquals("Result is 136 CZK");
  30.132 +        assertEquals(new BigDecimal("136.00"), c.convert(USD, CZK, BigDecimal.valueOf(8.00)));
  30.133 +
  30.134 +        // convert 1003CZK to USD using c:
  30.135 +        // assertEquals("Result is 59 USD");
  30.136 +        assertEquals(new BigDecimal("59.00"), c.convert(CZK, USD, BigDecimal.valueOf(1003.00)));
  30.137 +
  30.138 +        // convert 16CZK using c:
  30.139 +        // assertEquals("Result is 20 SKK");
  30.140 +        assertEquals(new BigDecimal("20.00"), c.convert(CZK, SKK, BigDecimal.valueOf(16.00)));
  30.141 +
  30.142 +        // convert 500SKK to CZK using c:
  30.143 +        // assertEquals("Result is 400 CZK");
  30.144 +        assertEquals(new BigDecimal("400.00"), c.convert(SKK, CZK, BigDecimal.valueOf(500.00)));
  30.145 +    }
  30.146 +    
  30.147 +    public void testGetCurrencies()
  30.148 +    {
  30.149 +        Convertor c = merge(
  30.150 +            Task1Test.createCZKtoUSD(),
  30.151 +            Task1Test.createSKKtoCZK()
  30.152 +        );
  30.153 +        Set<Currency> currencies;
  30.154 +        
  30.155 +        currencies = c.getCurrencies();        
  30.156 +        assertEquals(3, currencies.size());
  30.157 +        assertTrue(currencies.contains(Currency.getInstance("SKK")));
  30.158 +        assertTrue(currencies.contains(Currency.getInstance("CZK")));
  30.159 +        assertTrue(currencies.contains(Currency.getInstance("USD")));
  30.160 +    }
  30.161 +    
  30.162 +    public void testGetConverstionRate()
  30.163 +        throws InvalidConversionException
  30.164 +    {
  30.165 +        Convertor c = merge(
  30.166 +            Task1Test.createCZKtoUSD(),
  30.167 +            Task1Test.createSKKtoCZK()
  30.168 +        );
  30.169 +
  30.170 +        assertEquals(1.0,        c.getConversionRate(USD, USD).doubleValue(), 0.0000000000000001);
  30.171 +        assertEquals(17.0,       c.getConversionRate(USD, CZK).doubleValue(), 0.0000000000000001);
  30.172 +        assertEquals(21.25,      c.getConversionRate(USD, SKK).doubleValue(), 0.0000000000000001);
  30.173 +
  30.174 +        assertEquals(1.0 / 17.0, c.getConversionRate(CZK, USD).doubleValue(), 0.0000000000000001);
  30.175 +        assertEquals(1.0,        c.getConversionRate(CZK, CZK).doubleValue(), 0.0000000000000001);
  30.176 +        assertEquals(1.25,       c.getConversionRate(CZK, SKK).doubleValue(), 0.0000000000000001);
  30.177 +
  30.178 +        assertEquals(0.04705882352941176, c.getConversionRate(SKK, USD).doubleValue(), 0.0000000000000001);
  30.179 +        assertEquals(0.8,                 c.getConversionRate(SKK, CZK).doubleValue(), 0.0000000000000001);
  30.180 +        assertEquals(1.0,                 c.getConversionRate(SKK, SKK).doubleValue(), 0.0000000000000001);
  30.181 +    }
  30.182 +}
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/task3/solution06/build.xml	Tue Oct 07 11:05:34 2008 +0200
    31.3 @@ -0,0 +1,69 @@
    31.4 +<?xml version="1.0" encoding="UTF-8"?>
    31.5 +<!-- You may freely edit this file. See commented blocks below for -->
    31.6 +<!-- some examples of how to customize the build. -->
    31.7 +<!-- (If you delete it and reopen the project it will be recreated.) -->
    31.8 +<project name="currency" default="default" basedir=".">
    31.9 +    <description>Builds, tests, and runs the project.</description>
   31.10 +    <import file="nbproject/build-impl.xml"/>
   31.11 +    <!--
   31.12 +
   31.13 +    There exist several targets which are by default empty and which can be 
   31.14 +    used for execution of your tasks. These targets are usually executed 
   31.15 +    before and after some main targets. They are: 
   31.16 +
   31.17 +      -pre-init:                 called before initialization of project properties
   31.18 +      -post-init:                called after initialization of project properties
   31.19 +      -pre-compile:              called before javac compilation
   31.20 +      -post-compile:             called after javac compilation
   31.21 +      -pre-compile-single:       called before javac compilation of single file
   31.22 +      -post-compile-single:      called after javac compilation of single file
   31.23 +      -pre-compile-test:         called before javac compilation of JUnit tests
   31.24 +      -post-compile-test:        called after javac compilation of JUnit tests
   31.25 +      -pre-compile-test-single:  called before javac compilation of single JUnit test
   31.26 +      -post-compile-test-single: called after javac compilation of single JUunit test
   31.27 +      -pre-jar:                  called before JAR building
   31.28 +      -post-jar:                 called after JAR building
   31.29 +      -post-clean:               called after cleaning build products
   31.30 +
   31.31 +    (Targets beginning with '-' are not intended to be called on their own.)
   31.32 +
   31.33 +    Example of inserting an obfuscator after compilation could look like this:
   31.34 +
   31.35 +        <target name="-post-compile">
   31.36 +            <obfuscate>
   31.37 +                <fileset dir="${build.classes.dir}"/>
   31.38 +            </obfuscate>
   31.39 +        </target>
   31.40 +
   31.41 +    For list of available properties check the imported 
   31.42 +    nbproject/build-impl.xml file. 
   31.43 +
   31.44 +
   31.45 +    Another way to customize the build is by overriding existing main targets.
   31.46 +    The targets of interest are: 
   31.47 +
   31.48 +      -init-macrodef-javac:     defines macro for javac compilation
   31.49 +      -init-macrodef-junit:     defines macro for junit execution
   31.50 +      -init-macrodef-debug:     defines macro for class debugging
   31.51 +      -init-macrodef-java:      defines macro for class execution
   31.52 +      -do-jar-with-manifest:    JAR building (if you are using a manifest)
   31.53 +      -do-jar-without-manifest: JAR building (if you are not using a manifest)
   31.54 +      run:                      execution of project 
   31.55 +      -javadoc-build:           Javadoc generation
   31.56 +      test-report:              JUnit report generation
   31.57 +
   31.58 +    An example of overriding the target for project execution could look like this:
   31.59 +
   31.60 +        <target name="run" depends="currency-impl.jar">
   31.61 +            <exec dir="bin" executable="launcher.exe">
   31.62 +                <arg file="${dist.jar}"/>
   31.63 +            </exec>
   31.64 +        </target>
   31.65 +
   31.66 +    Notice that the overridden target depends on the jar target and not only on 
   31.67 +    the compile target as the regular run target does. Again, for a list of available 
   31.68 +    properties which you can use, check the target you are overriding in the
   31.69 +    nbproject/build-impl.xml file. 
   31.70 +
   31.71 +    -->
   31.72 +</project>
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/task3/solution06/nbproject/build-impl.xml	Tue Oct 07 11:05:34 2008 +0200
    32.3 @@ -0,0 +1,642 @@
    32.4 +<?xml version="1.0" encoding="UTF-8"?>
    32.5 +<!--
    32.6 +*** GENERATED FROM project.xml - DO NOT EDIT  ***
    32.7 +***         EDIT ../build.xml INSTEAD         ***
    32.8 +
    32.9 +For the purpose of easier reading the script
   32.10 +is divided into following sections:
   32.11 +
   32.12 +  - initialization
   32.13 +  - compilation
   32.14 +  - jar
   32.15 +  - execution
   32.16 +  - debugging
   32.17 +  - javadoc
   32.18 +  - junit compilation
   32.19 +  - junit execution
   32.20 +  - junit debugging
   32.21 +  - applet
   32.22 +  - cleanup
   32.23 +
   32.24 +        -->
   32.25 +<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="Currency_Convertor_Solution_06-impl">
   32.26 +    <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
   32.27 +    <!-- 
   32.28 +                ======================
   32.29 +                INITIALIZATION SECTION 
   32.30 +                ======================
   32.31 +            -->
   32.32 +    <target name="-pre-init">
   32.33 +        <!-- Empty placeholder for easier customization. -->
   32.34 +        <!-- You can override this target in the ../build.xml file. -->
   32.35 +    </target>
   32.36 +    <target depends="-pre-init" name="-init-private">
   32.37 +        <property file="nbproject/private/config.properties"/>
   32.38 +        <property file="nbproject/private/configs/${config}.properties"/>
   32.39 +        <property file="nbproject/private/private.properties"/>
   32.40 +    </target>
   32.41 +    <target depends="-pre-init,-init-private" name="-init-user">
   32.42 +        <property file="${user.properties.file}"/>
   32.43 +        <!-- The two properties below are usually overridden -->
   32.44 +        <!-- by the active platform. Just a fallback. -->
   32.45 +        <property name="default.javac.source" value="1.4"/>
   32.46 +        <property name="default.javac.target" value="1.4"/>
   32.47 +    </target>
   32.48 +    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
   32.49 +        <property file="nbproject/configs/${config}.properties"/>
   32.50 +        <property file="nbproject/project.properties"/>
   32.51 +    </target>
   32.52 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
   32.53 +        <available file="${manifest.file}" property="manifest.available"/>
   32.54 +        <condition property="manifest.available+main.class">
   32.55 +            <and>
   32.56 +                <isset property="manifest.available"/>
   32.57 +                <isset property="main.class"/>
   32.58 +                <not>
   32.59 +                    <equals arg1="${main.class}" arg2="" trim="true"/>
   32.60 +                </not>
   32.61 +            </and>
   32.62 +        </condition>
   32.63 +        <condition property="manifest.available+main.class+mkdist.available">
   32.64 +            <and>
   32.65 +                <istrue value="${manifest.available+main.class}"/>
   32.66 +                <isset property="libs.CopyLibs.classpath"/>
   32.67 +            </and>
   32.68 +        </condition>
   32.69 +        <condition property="have.tests">
   32.70 +            <or>
   32.71 +                <available file="${test.src.dir}"/>
   32.72 +            </or>
   32.73 +        </condition>
   32.74 +        <condition property="have.sources">
   32.75 +            <or>
   32.76 +                <available file="${src.dir}"/>
   32.77 +            </or>
   32.78 +        </condition>
   32.79 +        <condition property="netbeans.home+have.tests">
   32.80 +            <and>
   32.81 +                <isset property="netbeans.home"/>
   32.82 +                <isset property="have.tests"/>
   32.83 +            </and>
   32.84 +        </condition>
   32.85 +        <condition property="no.javadoc.preview">
   32.86 +            <and>
   32.87 +                <isset property="javadoc.preview"/>
   32.88 +                <isfalse value="${javadoc.preview}"/>
   32.89 +            </and>
   32.90 +        </condition>
   32.91 +        <property name="run.jvmargs" value=""/>
   32.92 +        <property name="javac.compilerargs" value=""/>
   32.93 +        <property name="work.dir" value="${basedir}"/>
   32.94 +        <condition property="no.deps">
   32.95 +            <and>
   32.96 +                <istrue value="${no.dependencies}"/>
   32.97 +            </and>
   32.98 +        </condition>
   32.99 +        <property name="javac.debug" value="true"/>
  32.100 +        <property name="javadoc.preview" value="true"/>
  32.101 +        <property name="application.args" value=""/>
  32.102 +        <property name="source.encoding" value="${file.encoding}"/>
  32.103 +        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
  32.104 +            <and>
  32.105 +                <isset property="javadoc.encoding"/>
  32.106 +                <not>
  32.107 +                    <equals arg1="${javadoc.encoding}" arg2=""/>
  32.108 +                </not>
  32.109 +            </and>
  32.110 +        </condition>
  32.111 +        <property name="javadoc.encoding.used" value="${source.encoding}"/>
  32.112 +        <property name="includes" value="**"/>
  32.113 +        <property name="excludes" value=""/>
  32.114 +        <property name="do.depend" value="false"/>
  32.115 +        <condition property="do.depend.true">
  32.116 +            <istrue value="${do.depend}"/>
  32.117 +        </condition>
  32.118 +        <condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
  32.119 +            <and>
  32.120 +                <isset property="jaxws.endorsed.dir"/>
  32.121 +                <available file="nbproject/jaxws-build.xml"/>
  32.122 +            </and>
  32.123 +        </condition>
  32.124 +    </target>
  32.125 +    <target name="-post-init">
  32.126 +        <!-- Empty placeholder for easier customization. -->
  32.127 +        <!-- You can override this target in the ../build.xml file. -->
  32.128 +    </target>
  32.129 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
  32.130 +        <fail unless="src.dir">Must set src.dir</fail>
  32.131 +        <fail unless="test.src.dir">Must set test.src.dir</fail>
  32.132 +        <fail unless="build.dir">Must set build.dir</fail>
  32.133 +        <fail unless="dist.dir">Must set dist.dir</fail>
  32.134 +        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
  32.135 +        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
  32.136 +        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
  32.137 +        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
  32.138 +        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
  32.139 +        <fail unless="dist.jar">Must set dist.jar</fail>
  32.140 +    </target>
  32.141 +    <target name="-init-macrodef-property">
  32.142 +        <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
  32.143 +            <attribute name="name"/>
  32.144 +            <attribute name="value"/>
  32.145 +            <sequential>
  32.146 +                <property name="@{name}" value="${@{value}}"/>
  32.147 +            </sequential>
  32.148 +        </macrodef>
  32.149 +    </target>
  32.150 +    <target name="-init-macrodef-javac">
  32.151 +        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
  32.152 +            <attribute default="${src.dir}" name="srcdir"/>
  32.153 +            <attribute default="${build.classes.dir}" name="destdir"/>
  32.154 +            <attribute default="${javac.classpath}" name="classpath"/>
  32.155 +            <attribute default="${includes}" name="includes"/>
  32.156 +            <attribute default="${excludes}" name="excludes"/>
  32.157 +            <attribute default="${javac.debug}" name="debug"/>
  32.158 +            <attribute default="" name="sourcepath"/>
  32.159 +            <element name="customize" optional="true"/>
  32.160 +            <sequential>
  32.161 +                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
  32.162 +                    <classpath>
  32.163 +                        <path path="@{classpath}"/>
  32.164 +                    </classpath>
  32.165 +                    <compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
  32.166 +                    <customize/>
  32.167 +                </javac>
  32.168 +            </sequential>
  32.169 +        </macrodef>
  32.170 +        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
  32.171 +            <attribute default="${src.dir}" name="srcdir"/>
  32.172 +            <attribute default="${build.classes.dir}" name="destdir"/>
  32.173 +            <attribute default="${javac.classpath}" name="classpath"/>
  32.174 +            <sequential>
  32.175 +                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
  32.176 +                    <classpath>
  32.177 +                        <path path="@{classpath}"/>
  32.178 +                    </classpath>
  32.179 +                </depend>
  32.180 +            </sequential>
  32.181 +        </macrodef>
  32.182 +        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
  32.183 +            <attribute default="${build.classes.dir}" name="destdir"/>
  32.184 +            <sequential>
  32.185 +                <fail unless="javac.includes">Must set javac.includes</fail>
  32.186 +                <pathconvert pathsep="," property="javac.includes.binary">
  32.187 +                    <path>
  32.188 +                        <filelist dir="@{destdir}" files="${javac.includes}"/>
  32.189 +                    </path>
  32.190 +                    <globmapper from="*.java" to="*.class"/>
  32.191 +                </pathconvert>
  32.192 +                <delete>
  32.193 +                    <files includes="${javac.includes.binary}"/>
  32.194 +                </delete>
  32.195 +            </sequential>
  32.196 +        </macrodef>
  32.197 +    </target>
  32.198 +    <target name="-init-macrodef-junit">
  32.199 +        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
  32.200 +            <attribute default="${includes}" name="includes"/>
  32.201 +            <attribute default="${excludes}" name="excludes"/>
  32.202 +            <attribute default="**" name="testincludes"/>
  32.203 +            <sequential>
  32.204 +                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
  32.205 +                    <batchtest todir="${build.test.results.dir}">
  32.206 +                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
  32.207 +                            <filename name="@{testincludes}"/>
  32.208 +                        </fileset>
  32.209 +                    </batchtest>
  32.210 +                    <classpath>
  32.211 +                        <path path="${run.test.classpath}"/>
  32.212 +                    </classpath>
  32.213 +                    <syspropertyset>
  32.214 +                        <propertyref prefix="test-sys-prop."/>
  32.215 +                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
  32.216 +                    </syspropertyset>
  32.217 +                    <formatter type="brief" usefile="false"/>
  32.218 +                    <formatter type="xml"/>
  32.219 +                    <jvmarg line="${run.jvmargs}"/>
  32.220 +                </junit>
  32.221 +            </sequential>
  32.222 +        </macrodef>
  32.223 +    </target>
  32.224 +    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
  32.225 +        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
  32.226 +            <attribute default="${main.class}" name="name"/>
  32.227 +            <attribute default="${debug.classpath}" name="classpath"/>
  32.228 +            <attribute default="" name="stopclassname"/>
  32.229 +            <sequential>
  32.230 +                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
  32.231 +                    <classpath>
  32.232 +                        <path path="@{classpath}"/>
  32.233 +                    </classpath>
  32.234 +                </nbjpdastart>
  32.235 +            </sequential>
  32.236 +        </macrodef>
  32.237 +        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
  32.238 +            <attribute default="${build.classes.dir}" name="dir"/>
  32.239 +            <sequential>
  32.240 +                <nbjpdareload>
  32.241 +                    <fileset dir="@{dir}" includes="${fix.classes}">
  32.242 +                        <include name="${fix.includes}*.class"/>
  32.243 +                    </fileset>
  32.244 +                </nbjpdareload>
  32.245 +            </sequential>
  32.246 +        </macrodef>
  32.247 +    </target>
  32.248 +    <target name="-init-debug-args">
  32.249 +        <property name="version-output" value="java version &quot;${ant.java.version}"/>
  32.250 +        <condition property="have-jdk-older-than-1.4">
  32.251 +            <or>
  32.252 +                <contains string="${version-output}" substring="java version &quot;1.0"/>
  32.253 +                <contains string="${version-output}" substring="java version &quot;1.1"/>
  32.254 +                <contains string="${version-output}" substring="java version &quot;1.2"/>
  32.255 +                <contains string="${version-output}" substring="java version &quot;1.3"/>
  32.256 +            </or>
  32.257 +        </condition>
  32.258 +        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
  32.259 +            <istrue value="${have-jdk-older-than-1.4}"/>
  32.260 +        </condition>
  32.261 +        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
  32.262 +            <os family="windows"/>
  32.263 +        </condition>
  32.264 +        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
  32.265 +            <isset property="debug.transport"/>
  32.266 +        </condition>
  32.267 +    </target>
  32.268 +    <target depends="-init-debug-args" name="-init-macrodef-debug">
  32.269 +        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
  32.270 +            <attribute default="${main.class}" name="classname"/>
  32.271 +            <attribute default="${debug.classpath}" name="classpath"/>
  32.272 +            <element name="customize" optional="true"/>
  32.273 +            <sequential>
  32.274 +                <java classname="@{classname}" dir="${work.dir}" fork="true">
  32.275 +                    <jvmarg line="${debug-args-line}"/>
  32.276 +                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
  32.277 +                    <jvmarg line="${run.jvmargs}"/>
  32.278 +                    <classpath>
  32.279 +                        <path path="@{classpath}"/>
  32.280 +                    </classpath>
  32.281 +                    <syspropertyset>
  32.282 +                        <propertyref prefix="run-sys-prop."/>
  32.283 +                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
  32.284 +                    </syspropertyset>
  32.285 +                    <customize/>
  32.286 +                </java>
  32.287 +            </sequential>
  32.288 +        </macrodef>
  32.289 +    </target>
  32.290 +    <target name="-init-macrodef-java">
  32.291 +        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
  32.292 +            <attribute default="${main.class}" name="classname"/>
  32.293 +            <element name="customize" optional="true"/>
  32.294 +            <sequential>
  32.295 +                <java classname="@{classname}" dir="${work.dir}" fork="true">
  32.296 +                    <jvmarg line="${run.jvmargs}"/>
  32.297 +                    <classpath>
  32.298 +                        <path path="${run.classpath}"/>
  32.299 +                    </classpath>
  32.300 +                    <syspropertyset>
  32.301 +                        <propertyref prefix="run-sys-prop."/>
  32.302 +                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
  32.303 +                    </syspropertyset>
  32.304 +                    <customize/>
  32.305 +                </java>
  32.306 +            </sequential>
  32.307 +        </macrodef>
  32.308 +    </target>
  32.309 +    <target name="-init-presetdef-jar">
  32.310 +        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
  32.311 +            <jar compress="${jar.compress}" jarfile="${dist.jar}">
  32.312 +                <j2seproject1:fileset dir="${build.classes.dir}"/>
  32.313 +            </jar>
  32.314 +        </presetdef>
  32.315 +    </target>
  32.316 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar" name="init"/>
  32.317 +    <!--
  32.318 +                ===================
  32.319 +                COMPILATION SECTION
  32.320 +                ===================
  32.321 +            -->
  32.322 +    <target depends="init" name="deps-jar" unless="no.deps"/>
  32.323 +    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
  32.324 +    <target depends="init" name="-check-automatic-build">
  32.325 +        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
  32.326 +    </target>
  32.327 +    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
  32.328 +        <antcall target="clean"/>
  32.329 +    </target>
  32.330 +    <target depends="init,deps-jar" name="-pre-pre-compile">
  32.331 +        <mkdir dir="${build.classes.dir}"/>
  32.332 +    </target>
  32.333 +    <target name="-pre-compile">
  32.334 +        <!-- Empty placeholder for easier customization. -->
  32.335 +        <!-- You can override this target in the ../build.xml file. -->
  32.336 +    </target>
  32.337 +    <target if="do.depend.true" name="-compile-depend">
  32.338 +        <j2seproject3:depend/>
  32.339 +    </target>
  32.340 +    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
  32.341 +        <j2seproject3:javac/>
  32.342 +        <copy todir="${build.classes.dir}">
  32.343 +            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  32.344 +        </copy>
  32.345 +    </target>
  32.346 +    <target name="-post-compile">
  32.347 +        <!-- Empty placeholder for easier customization. -->
  32.348 +        <!-- You can override this target in the ../build.xml file. -->
  32.349 +    </target>
  32.350 +    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
  32.351 +    <target name="-pre-compile-single">
  32.352 +        <!-- Empty placeholder for easier customization. -->
  32.353 +        <!-- You can override this target in the ../build.xml file. -->
  32.354 +    </target>
  32.355 +    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
  32.356 +        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
  32.357 +        <j2seproject3:force-recompile/>
  32.358 +        <j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
  32.359 +    </target>
  32.360 +    <target name="-post-compile-single">
  32.361 +        <!-- Empty placeholder for easier customization. -->
  32.362 +        <!-- You can override this target in the ../build.xml file. -->
  32.363 +    </target>
  32.364 +    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
  32.365 +    <!--
  32.366 +                ====================
  32.367 +                JAR BUILDING SECTION
  32.368 +                ====================
  32.369 +            -->
  32.370 +    <target depends="init" name="-pre-pre-jar">
  32.371 +        <dirname file="${dist.jar}" property="dist.jar.dir"/>
  32.372 +        <mkdir dir="${dist.jar.dir}"/>
  32.373 +    </target>
  32.374 +    <target name="-pre-jar">
  32.375 +        <!-- Empty placeholder for easier customization. -->
  32.376 +        <!-- You can override this target in the ../build.xml file. -->
  32.377 +    </target>
  32.378 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
  32.379 +        <j2seproject1:jar/>
  32.380 +    </target>
  32.381 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
  32.382 +        <j2seproject1:jar manifest="${manifest.file}"/>
  32.383 +    </target>
  32.384 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
  32.385 +        <j2seproject1:jar manifest="${manifest.file}">
  32.386 +            <j2seproject1:manifest>
  32.387 +                <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
  32.388 +            </j2seproject1:manifest>
  32.389 +        </j2seproject1:jar>
  32.390 +        <echo>To run this application from the command line without Ant, try:</echo>
  32.391 +        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
  32.392 +        <property location="${dist.jar}" name="dist.jar.resolved"/>
  32.393 +        <pathconvert property="run.classpath.with.dist.jar">
  32.394 +            <path path="${run.classpath}"/>
  32.395 +            <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
  32.396 +        </pathconvert>
  32.397 +        <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
  32.398 +    </target>
  32.399 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
  32.400 +        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
  32.401 +        <pathconvert property="run.classpath.without.build.classes.dir">
  32.402 +            <path path="${run.classpath}"/>
  32.403 +            <map from="${build.classes.dir.resolved}" to=""/>
  32.404 +        </pathconvert>
  32.405 +        <pathconvert pathsep=" " property="jar.classpath">
  32.406 +            <path path="${run.classpath.without.build.classes.dir}"/>
  32.407 +            <chainedmapper>
  32.408 +                <flattenmapper/>
  32.409 +                <globmapper from="*" to="lib/*"/>
  32.410 +            </chainedmapper>
  32.411 +        </pathconvert>
  32.412 +        <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
  32.413 +        <copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
  32.414 +            <fileset dir="${build.classes.dir}"/>
  32.415 +            <manifest>
  32.416 +                <attribute name="Main-Class" value="${main.class}"/>
  32.417 +                <attribute name="Class-Path" value="${jar.classpath}"/>
  32.418 +            </manifest>
  32.419 +        </copylibs>
  32.420 +        <echo>To run this application from the command line without Ant, try:</echo>
  32.421 +        <property location="${dist.jar}" name="dist.jar.resolved"/>
  32.422 +        <echo>java -jar "${dist.jar.resolved}"</echo>
  32.423 +    </target>
  32.424 +    <target name="-post-jar">
  32.425 +        <!-- Empty placeholder for easier customization. -->
  32.426 +        <!-- You can override this target in the ../build.xml file. -->
  32.427 +    </target>
  32.428 +    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
  32.429 +    <!--
  32.430 +                =================
  32.431 +                EXECUTION SECTION
  32.432 +                =================
  32.433 +            -->
  32.434 +    <target depends="init,compile" description="Run a main class." name="run">
  32.435 +        <j2seproject1:java>
  32.436 +            <customize>
  32.437 +                <arg line="${application.args}"/>
  32.438 +            </customize>
  32.439 +        </j2seproject1:java>
  32.440 +    </target>
  32.441 +    <target name="-do-not-recompile">
  32.442 +        <property name="javac.includes.binary" value=""/>
  32.443 +    </target>
  32.444 +    <target depends="init,-do-not-recompile,compile-single" name="run-single">
  32.445 +        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
  32.446 +        <j2seproject1:java classname="${run.class}"/>
  32.447 +    </target>
  32.448 +    <!--
  32.449 +                =================
  32.450 +                DEBUGGING SECTION
  32.451 +                =================
  32.452 +            -->
  32.453 +    <target depends="init" if="netbeans.home" name="-debug-start-debugger">
  32.454 +        <j2seproject1:nbjpdastart name="${debug.class}"/>
  32.455 +    </target>
  32.456 +    <target depends="init,compile" name="-debug-start-debuggee">
  32.457 +        <j2seproject3:debug>
  32.458 +            <customize>
  32.459 +                <arg line="${application.args}"/>
  32.460 +            </customize>
  32.461 +        </j2seproject3:debug>
  32.462 +    </target>
  32.463 +    <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
  32.464 +    <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
  32.465 +        <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
  32.466 +    </target>
  32.467 +    <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
  32.468 +    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
  32.469 +        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
  32.470 +        <j2seproject3:debug classname="${debug.class}"/>
  32.471 +    </target>
  32.472 +    <target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
  32.473 +    <target depends="init" name="-pre-debug-fix">
  32.474 +        <fail unless="fix.includes">Must set fix.includes</fail>
  32.475 +        <property name="javac.includes" value="${fix.includes}.java"/>
  32.476 +    </target>
  32.477 +    <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
  32.478 +        <j2seproject1:nbjpdareload/>
  32.479 +    </target>
  32.480 +    <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
  32.481 +    <!--
  32.482 +                ===============
  32.483 +                JAVADOC SECTION
  32.484 +                ===============
  32.485 +            -->
  32.486 +    <target depends="init" name="-javadoc-build">
  32.487 +        <mkdir dir="${dist.javadoc.dir}"/>
  32.488 +        <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
  32.489 +            <classpath>
  32.490 +                <path path="${javac.classpath}"/>
  32.491 +            </classpath>
  32.492 +            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
  32.493 +                <filename name="**/*.java"/>
  32.494 +            </fileset>
  32.495 +        </javadoc>
  32.496 +    </target>
  32.497 +    <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
  32.498 +        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
  32.499 +    </target>
  32.500 +    <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
  32.501 +    <!--
  32.502 +                =========================
  32.503 +                JUNIT COMPILATION SECTION
  32.504 +                =========================
  32.505 +            -->
  32.506 +    <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
  32.507 +        <mkdir dir="${build.test.classes.dir}"/>
  32.508 +    </target>
  32.509 +    <target name="-pre-compile-test">
  32.510 +        <!-- Empty placeholder for easier customization. -->
  32.511 +        <!-- You can override this target in the ../build.xml file. -->
  32.512 +    </target>
  32.513 +    <target if="do.depend.true" name="-compile-test-depend">
  32.514 +        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
  32.515 +    </target>
  32.516 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
  32.517 +        <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
  32.518 +        <copy todir="${build.test.classes.dir}">
  32.519 +            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  32.520 +        </copy>
  32.521 +    </target>
  32.522 +    <target name="-post-compile-test">
  32.523 +        <!-- Empty placeholder for easier customization. -->
  32.524 +        <!-- You can override this target in the ../build.xml file. -->
  32.525 +    </target>
  32.526 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
  32.527 +    <target name="-pre-compile-test-single">
  32.528 +        <!-- Empty placeholder for easier customization. -->
  32.529 +        <!-- You can override this target in the ../build.xml file. -->
  32.530 +    </target>
  32.531 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
  32.532 +        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
  32.533 +        <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
  32.534 +        <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
  32.535 +        <copy todir="${build.test.classes.dir}">
  32.536 +            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  32.537 +        </copy>
  32.538 +    </target>
  32.539 +    <target name="-post-compile-test-single">
  32.540 +        <!-- Empty placeholder for easier customization. -->
  32.541 +        <!-- You can override this target in the ../build.xml file. -->
  32.542 +    </target>
  32.543 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
  32.544 +    <!--
  32.545 +                =======================
  32.546 +                JUNIT EXECUTION SECTION
  32.547 +                =======================
  32.548 +            -->
  32.549 +    <target depends="init" if="have.tests" name="-pre-test-run">
  32.550 +        <mkdir dir="${build.test.results.dir}"/>
  32.551 +    </target>
  32.552 +    <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
  32.553 +        <j2seproject3:junit testincludes="**/*Test.java"/>
  32.554 +    </target>
  32.555 +    <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
  32.556 +        <fail if="tests.failed">Some tests failed; see details above.</fail>
  32.557 +    </target>
  32.558 +    <target depends="init" if="have.tests" name="test-report"/>
  32.559 +    <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
  32.560 +    <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
  32.561 +    <target depends="init" if="have.tests" name="-pre-test-run-single">
  32.562 +        <mkdir dir="${build.test.results.dir}"/>
  32.563 +    </target>
  32.564 +    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
  32.565 +        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
  32.566 +        <j2seproject3:junit excludes="" includes="${test.includes}"/>
  32.567 +    </target>
  32.568 +    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
  32.569 +        <fail if="tests.failed">Some tests failed; see details above.</fail>
  32.570 +    </target>
  32.571 +    <target depends="init,-do-not-recompile,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
  32.572 +    <!--
  32.573 +                =======================
  32.574 +                JUNIT DEBUGGING SECTION
  32.575 +                =======================
  32.576 +            -->
  32.577 +    <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
  32.578 +        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
  32.579 +        <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
  32.580 +        <delete file="${test.report.file}"/>
  32.581 +        <mkdir dir="${build.test.results.dir}"/>
  32.582 +        <j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
  32.583 +            <customize>
  32.584 +                <syspropertyset>
  32.585 +                    <propertyref prefix="test-sys-prop."/>
  32.586 +                    <mapper from="test-sys-prop.*" to="*" type="glob"/>
  32.587 +                </syspropertyset>
  32.588 +                <arg value="${test.class}"/>
  32.589 +                <arg value="showoutput=true"/>
  32.590 +                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
  32.591 +                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
  32.592 +            </customize>
  32.593 +        </j2seproject3:debug>
  32.594 +    </target>
  32.595 +    <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
  32.596 +        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
  32.597 +    </target>
  32.598 +    <target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
  32.599 +    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
  32.600 +        <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
  32.601 +    </target>
  32.602 +    <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
  32.603 +    <!--
  32.604 +                =========================
  32.605 +                APPLET EXECUTION SECTION
  32.606 +                =========================
  32.607 +            -->
  32.608 +    <target depends="init,compile-single" name="run-applet">
  32.609 +        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
  32.610 +        <j2seproject1:java classname="sun.applet.AppletViewer">
  32.611 +            <customize>
  32.612 +                <arg value="${applet.url}"/>
  32.613 +            </customize>
  32.614 +        </j2seproject1:java>
  32.615 +    </target>
  32.616 +    <!--
  32.617 +                =========================
  32.618 +                APPLET DEBUGGING  SECTION
  32.619 +                =========================
  32.620 +            -->
  32.621 +    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
  32.622 +        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
  32.623 +        <j2seproject3:debug classname="sun.applet.AppletViewer">
  32.624 +            <customize>
  32.625 +                <arg value="${applet.url}"/>
  32.626 +            </customize>
  32.627 +        </j2seproject3:debug>
  32.628 +    </target>
  32.629 +    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
  32.630 +    <!--
  32.631 +                ===============
  32.632 +                CLEANUP SECTION
  32.633 +                ===============
  32.634 +            -->
  32.635 +    <target depends="init" name="deps-clean" unless="no.deps"/>
  32.636 +    <target depends="init" name="-do-clean">
  32.637 +        <delete dir="${build.dir}"/>
  32.638 +        <delete dir="${dist.dir}"/>
  32.639 +    </target>
  32.640 +    <target name="-post-clean">
  32.641 +        <!-- Empty placeholder for easier customization. -->
  32.642 +        <!-- You can override this target in the ../build.xml file. -->
  32.643 +    </target>
  32.644 +    <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
  32.645 +</project>
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/task3/solution06/nbproject/genfiles.properties	Tue Oct 07 11:05:34 2008 +0200
    33.3 @@ -0,0 +1,8 @@
    33.4 +build.xml.data.CRC32=2ab820eb
    33.5 +build.xml.script.CRC32=58a52595
    33.6 +build.xml.stylesheet.CRC32=be360661
    33.7 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
    33.8 +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
    33.9 +nbproject/build-impl.xml.data.CRC32=ff801896
   33.10 +nbproject/build-impl.xml.script.CRC32=a0996c47
   33.11 +nbproject/build-impl.xml.stylesheet.CRC32=e55b27f5
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/task3/solution06/nbproject/project.properties	Tue Oct 07 11:05:34 2008 +0200
    34.3 @@ -0,0 +1,68 @@
    34.4 +application.title=currency
    34.5 +application.vendor=apidesign.org
    34.6 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
    34.7 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
    34.8 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=default
    34.9 +build.classes.dir=${build.dir}/classes
   34.10 +build.classes.excludes=**/*.java,**/*.form
   34.11 +# This directory is removed when the project is cleaned:
   34.12 +build.dir=build
   34.13 +build.generated.dir=${build.dir}/generated
   34.14 +# Only compile against the classpath explicitly listed here:
   34.15 +build.sysclasspath=ignore
   34.16 +build.test.classes.dir=${build.dir}/test/classes
   34.17 +build.test.results.dir=${build.dir}/test/results
   34.18 +debug.classpath=\
   34.19 +    ${run.classpath}
   34.20 +debug.test.classpath=\
   34.21 +    ${run.test.classpath}
   34.22 +# This directory is removed when the project is cleaned:
   34.23 +dist.dir=dist
   34.24 +dist.jar=${dist.dir}/currency.jar
   34.25 +dist.javadoc.dir=${dist.dir}/javadoc
   34.26 +excludes=
   34.27 +file.reference.junit-4.4.jar=../../libs/junit-4.4.jar
   34.28 +file.reference.src-apifest08=..
   34.29 +includes=**
   34.30 +jar.compress=false
   34.31 +javac.classpath=
   34.32 +# Space-separated list of extra javac options
   34.33 +javac.compilerargs=
   34.34 +javac.deprecation=false
   34.35 +javac.source=1.5
   34.36 +javac.target=1.5
   34.37 +javac.test.classpath=\
   34.38 +    ${javac.classpath}:\
   34.39 +    ${build.classes.dir}:\
   34.40 +    ${file.reference.junit-4.4.jar}
   34.41 +javadoc.additionalparam=
   34.42 +javadoc.author=false
   34.43 +javadoc.encoding=
   34.44 +javadoc.noindex=false
   34.45 +javadoc.nonavbar=false
   34.46 +javadoc.notree=false
   34.47 +javadoc.private=false
   34.48 +javadoc.splitindex=true
   34.49 +javadoc.use=true
   34.50 +javadoc.version=false
   34.51 +javadoc.windowtitle=
   34.52 +jnlp.codebase.type=local
   34.53 +jnlp.codebase.url=file:/home/jarda/src/apifest08/currency/dist
   34.54 +jnlp.descriptor=application
   34.55 +jnlp.enabled=false
   34.56 +jnlp.offline-allowed=false
   34.57 +jnlp.signed=false
   34.58 +meta.inf.dir=${src.dir}/META-INF
   34.59 +platform.active=default_platform
   34.60 +run.classpath=\
   34.61 +    ${javac.classpath}:\
   34.62 +    ${build.classes.dir}
   34.63 +# Space-separated list of JVM arguments used when running the project
   34.64 +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
   34.65 +# or test-sys-prop.name=value to set system properties for unit tests):
   34.66 +run.jvmargs=
   34.67 +run.test.classpath=\
   34.68 +    ${javac.test.classpath}:\
   34.69 +    ${build.test.classes.dir}
   34.70 +src.dir=src
   34.71 +test.src.dir=test
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/task3/solution06/nbproject/project.xml	Tue Oct 07 11:05:34 2008 +0200
    35.3 @@ -0,0 +1,16 @@
    35.4 +<?xml version="1.0" encoding="UTF-8"?>
    35.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
    35.6 +    <type>org.netbeans.modules.java.j2seproject</type>
    35.7 +    <configuration>
    35.8 +        <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
    35.9 +            <name>Currency Convertor Solution 06</name>
   35.10 +            <minimum-ant-version>1.6.5</minimum-ant-version>
   35.11 +            <source-roots>
   35.12 +                <root id="src.dir"/>
   35.13 +            </source-roots>
   35.14 +            <test-roots>
   35.15 +                <root id="test.src.dir"/>
   35.16 +            </test-roots>
   35.17 +        </data>
   35.18 +    </configuration>
   35.19 +</project>
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/task3/solution06/src/org/apidesign/apifest08/currency/Amount.java	Tue Oct 07 11:05:34 2008 +0200
    36.3 @@ -0,0 +1,81 @@
    36.4 +package org.apidesign.apifest08.currency;
    36.5 +
    36.6 +import static org.apidesign.apifest08.currency.Assert.notNull;
    36.7 +
    36.8 +import java.math.BigDecimal;
    36.9 +import java.math.RoundingMode;
   36.10 +import java.util.Currency;
   36.11 +
   36.12 +/**
   36.13 + * An amount representation. Amount is represented as composition of a value and 
   36.14 + * a currency.
   36.15 + */
   36.16 +public final class Amount {
   36.17 +	
   36.18 +	private final BigDecimal value;
   36.19 +	private final Currency currency;
   36.20 +	private final int scale;
   36.21 +	private final RoundingMode roundingMode;
   36.22 +	
   36.23 +	public static final RoundingMode DEFAULT_ROUNDING = RoundingMode.HALF_EVEN; 
   36.24 +	
   36.25 +	public Amount(final BigDecimal value, final Currency currency) {
   36.26 +		notNull(value, "value");
   36.27 +		notNull(currency, "currency");
   36.28 +		this.value = value;
   36.29 +		this.currency = currency;
   36.30 +		this.scale = currency.getDefaultFractionDigits();
   36.31 +		this.roundingMode = DEFAULT_ROUNDING;
   36.32 +	}
   36.33 +	
   36.34 +	public Amount(final BigDecimal value, final Currency currency, final RoundingMode roundingMode) {
   36.35 +		notNull(value, "value");
   36.36 +		notNull(currency, "currency");
   36.37 +		notNull(roundingMode, "roundingMode");
   36.38 +		
   36.39 +		this.value = value;
   36.40 +		this.currency = currency;
   36.41 +		this.scale = currency.getDefaultFractionDigits();
   36.42 +		this.roundingMode = roundingMode;
   36.43 +	}
   36.44 +	
   36.45 +	public Amount(final long value, final Currency currency) {
   36.46 +		this(BigDecimal.valueOf(value), currency);
   36.47 +	}
   36.48 +	
   36.49 +	public Amount(final String value, final Currency currency) {
   36.50 +		this(new BigDecimal(value), currency);
   36.51 +	}
   36.52 +	
   36.53 +	/**
   36.54 +	 * @return the value with scale of the associated currency and rounded by 
   36.55 +	 * the rounding mode. 
   36.56 +	 */
   36.57 +	public BigDecimal getValue() {
   36.58 +		return value.setScale(scale, roundingMode);
   36.59 +	}
   36.60 +	
   36.61 +	/**
   36.62 +	 * @return the raw (no explicit scale, no explicit rounding) value 
   36.63 +	 */
   36.64 +	public BigDecimal getRawValue() {
   36.65 +		return value;
   36.66 +	}
   36.67 +	
   36.68 +	public Currency getCurrency() {
   36.69 +		return currency;
   36.70 +	}
   36.71 +
   36.72 +	public int getScale() {
   36.73 +		return scale;
   36.74 +	}
   36.75 +
   36.76 +	public RoundingMode getRoundingMode() {
   36.77 +		return roundingMode;
   36.78 +	}
   36.79 +
   36.80 +	@Override
   36.81 +	public String toString() {
   36.82 +		return value + ",- " + currency.toString();
   36.83 +	}	
   36.84 +}
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/task3/solution06/src/org/apidesign/apifest08/currency/Assert.java	Tue Oct 07 11:05:34 2008 +0200
    37.3 @@ -0,0 +1,11 @@
    37.4 +package org.apidesign.apifest08.currency;
    37.5 +
    37.6 +public final class Assert {
    37.7 +	static void notNull(Object value, String argumentName) {
    37.8 +		if(value == null) {
    37.9 +			throw new IllegalArgumentException("The argument '" + argumentName + "' connot not be null");
   37.10 +		}
   37.11 +	}
   37.12 +}
   37.13 +
   37.14 +
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/task3/solution06/src/org/apidesign/apifest08/currency/ConversionException.java	Tue Oct 07 11:05:34 2008 +0200
    38.3 @@ -0,0 +1,26 @@
    38.4 +package org.apidesign.apifest08.currency;
    38.5 +
    38.6 +/**
    38.7 + * Indicates that a desired conversion cannot be performed.
    38.8 + */
    38.9 +public class ConversionException extends CurrencyException {
   38.10 +	
   38.11 +	private static final long serialVersionUID = 1L;
   38.12 +
   38.13 +	public ConversionException() {
   38.14 +		super();
   38.15 +	}
   38.16 +
   38.17 +	public ConversionException(String message, Throwable cause) {
   38.18 +		super(message, cause);		
   38.19 +	}
   38.20 +
   38.21 +	public ConversionException(String message) {
   38.22 +		super(message);
   38.23 +	}
   38.24 +
   38.25 +	public ConversionException(Throwable cause) {
   38.26 +		super(cause);
   38.27 +	}
   38.28 +	
   38.29 +}
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/task3/solution06/src/org/apidesign/apifest08/currency/Convertor.java	Tue Oct 07 11:05:34 2008 +0200
    39.3 @@ -0,0 +1,124 @@
    39.4 +package org.apidesign.apifest08.currency;
    39.5 +
    39.6 +import static org.apidesign.apifest08.currency.Assert.notNull;
    39.7 +
    39.8 +import java.math.BigDecimal;
    39.9 +import java.math.RoundingMode;
   39.10 +import java.util.ArrayList;
   39.11 +import java.util.Currency;
   39.12 +import java.util.List;
   39.13 +
   39.14 +public final class Convertor {
   39.15 +	
   39.16 +	private List<ConvertorDelegate> convertorDelegates = new ArrayList<ConvertorDelegate>();
   39.17 +	
   39.18 +	
   39.19 +	/**
   39.20 +	 * Create new instance of the converter for the given currencies and its rate.
   39.21 +	 * 
   39.22 +	 * @param rateValue the rate between the first and the second currency
   39.23 +	 * @param currencyFirst the first currency
   39.24 +	 * @param currencySecond the second currency
   39.25 +	 */
   39.26 +	public Convertor(BigDecimal rateValue, Currency currencyFirst, Currency currencySecond) {
   39.27 +		notNull(currencyFirst, "currencyFirst");
   39.28 +		notNull(currencySecond, "currencySecond");		
   39.29 +		notNull(rateValue, "rateValue");	
   39.30 +		convertorDelegates.add(new ConvertorDelegate(rateValue, currencyFirst, currencySecond));
   39.31 +	}
   39.32 +	
   39.33 +	/**
   39.34 +	 * Create new instance of the convertor from the given convertors. 
   39.35 +	 * @param convertors the convertors
   39.36 +	 */
   39.37 +	public Convertor(Convertor... convertors) {
   39.38 +		notNull(convertors, "convertors");
   39.39 +		if(convertors.length == 0) {
   39.40 +			throw new IllegalArgumentException("There must be at least one converter.");
   39.41 +		}
   39.42 +		
   39.43 +		for(Convertor convertor: convertors) {
   39.44 +			if(convertor != null) {
   39.45 +				convertorDelegates.addAll(convertor.convertorDelegates);
   39.46 +			}
   39.47 +		}
   39.48 +	}
   39.49 +    	
   39.50 +	/**
   39.51 +	 * Converts an amount value between the two currencies of this converter.
   39.52 +	 *  
   39.53 +	 * @param amount an amount
   39.54 +	 * @param fromCurrency an amount currency
   39.55 +	 * @param toCurrency to a target currency
   39.56 +	 * @return a converted amount value
   39.57 +	 * 
   39.58 +	 * @throws ConversionException if the conversion fails
   39.59 +	 * @throws UnsupportedConversionException if the conversion between a given currencies is not supported.
   39.60 +	 */
   39.61 +	public Amount convert(BigDecimal amount, Currency fromCurrency, Currency toCurrency) throws ConversionException {
   39.62 +		notNull(amount, "amount");
   39.63 +		notNull(fromCurrency, "fromCurrency");
   39.64 +		notNull(toCurrency, "toCurrency");
   39.65 +		ConvertorDelegate appropriateDelegate = null;
   39.66 +		
   39.67 +		//try find an appropriate delegate for conversion
   39.68 +		for(ConvertorDelegate delegate : convertorDelegates) {
   39.69 +			if(delegate.isConversionSupported(fromCurrency, toCurrency)) {
   39.70 +				appropriateDelegate = delegate;
   39.71 +				break;
   39.72 +			}
   39.73 +		}
   39.74 +		
   39.75 +		if(appropriateDelegate == null) {
   39.76 +			throw new UnsupportedConversionException(fromCurrency, toCurrency);
   39.77 +		}
   39.78 +		
   39.79 +		return appropriateDelegate.convert(amount, fromCurrency, toCurrency);	
   39.80 +	}
   39.81 +	
   39.82 +	/**
   39.83 +	 * Internal delegate implements a logic for conversion between two currencies
   39.84 +	 * and vice versa.
   39.85 +	 * @see #isConversionSupported(Currency, Currency)
   39.86 +	 */
   39.87 +	private static class ConvertorDelegate {
   39.88 +		private final Currency first;
   39.89 +		private final Currency second;
   39.90 +		private final BigDecimal rateValue; // a rate between the first currency and the second currency
   39.91 +		public static final BigDecimal one = new BigDecimal(1);
   39.92 +		
   39.93 +		private ConvertorDelegate(BigDecimal rateValue, Currency currencyFirst, Currency currencySecond) {
   39.94 +			this.rateValue = rateValue;
   39.95 +			this.first = currencyFirst;
   39.96 +			this.second = currencySecond;
   39.97 +		}
   39.98 +		
   39.99 +		private Amount convert(BigDecimal amount, Currency fromCurrency, Currency toCurrency) throws ConversionException {
  39.100 +			BigDecimal rateValue = getRateValue(fromCurrency, toCurrency);
  39.101 +			BigDecimal result = rateValue.multiply(amount);			
  39.102 +			return new Amount(result, toCurrency);	
  39.103 +		}
  39.104 +		
  39.105 +		private BigDecimal getRateValue(Currency fromCurrency, Currency toCurrency) {		
  39.106 +			
  39.107 +			BigDecimal retVal;
  39.108 +			
  39.109 +			if(first == fromCurrency) {
  39.110 +				retVal = rateValue;
  39.111 +			} else {	
  39.112 +				//reverse rate	
  39.113 +				retVal = one.divide(rateValue, 10 ,RoundingMode.HALF_UP);
  39.114 +			}
  39.115 +			
  39.116 +			return retVal;
  39.117 +		}
  39.118 +		
  39.119 +		/**
  39.120 +		 * @return <code>true</code> if the delegate is able to convert from the given currency
  39.121 +		 * to the given currency and vice versa otherwise <code>false</code>.
  39.122 +		 */
  39.123 +		private boolean isConversionSupported(Currency fromCurrency, Currency toCurrency) {
  39.124 +			return ((fromCurrency == first || fromCurrency == second) && (toCurrency == first || toCurrency == second));
  39.125 +		}
  39.126 +	}
  39.127 +}
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/task3/solution06/src/org/apidesign/apifest08/currency/CurrencyException.java	Tue Oct 07 11:05:34 2008 +0200
    40.3 @@ -0,0 +1,25 @@
    40.4 +package org.apidesign.apifest08.currency;
    40.5 +
    40.6 +/**
    40.7 + * Top level runtime exception for 'currency' API.
    40.8 + */
    40.9 +public class CurrencyException extends RuntimeException{
   40.10 +
   40.11 +	private static final long serialVersionUID = 1L;
   40.12 +
   40.13 +	public CurrencyException() {
   40.14 +		super();		
   40.15 +	}
   40.16 +
   40.17 +	public CurrencyException(String message, Throwable cause) {
   40.18 +		super(message, cause);		
   40.19 +	}
   40.20 +
   40.21 +	public CurrencyException(String message) {
   40.22 +		super(message);		
   40.23 +	}
   40.24 +
   40.25 +	public CurrencyException(Throwable cause) {
   40.26 +		super(cause);		
   40.27 +	}
   40.28 +}
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/task3/solution06/src/org/apidesign/apifest08/currency/UnsupportedConversionException.java	Tue Oct 07 11:05:34 2008 +0200
    41.3 @@ -0,0 +1,27 @@
    41.4 +package org.apidesign.apifest08.currency;
    41.5 +
    41.6 +import java.util.Currency;
    41.7 +
    41.8 +public final class UnsupportedConversionException extends ConversionException{
    41.9 +
   41.10 +	private static final long serialVersionUID = 1L; 
   41.11 +	
   41.12 +	private Currency from;
   41.13 +	private Currency to;
   41.14 +
   41.15 +	public UnsupportedConversionException(Currency from, Currency to) {
   41.16 +		super("Conversion from  the currency " + from + " to the currency " + to + " or vice versa in not supported.");
   41.17 +		this.from = from;
   41.18 +		this.to = to;
   41.19 +	}
   41.20 +
   41.21 +	public Currency getFrom() {
   41.22 +		return from;
   41.23 +	}
   41.24 +
   41.25 +	public Currency getTo() {
   41.26 +		return to;
   41.27 +	}
   41.28 +	
   41.29 +	
   41.30 +}
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/task3/solution06/test/org/apidesign/apifest08/test/Currencies.java	Tue Oct 07 11:05:34 2008 +0200
    42.3 @@ -0,0 +1,9 @@
    42.4 +package org.apidesign.apifest08.test;
    42.5 +
    42.6 +import java.util.Currency;
    42.7 +
    42.8 +public class Currencies {
    42.9 +	public static final Currency CZK = Currency.getInstance("CZK");
   42.10 +	public static final Currency SKK = Currency.getInstance("SKK");
   42.11 +	public static final Currency USD = Currency.getInstance("USD");
   42.12 +}
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/task3/solution06/test/org/apidesign/apifest08/test/Task1Test.java	Tue Oct 07 11:05:34 2008 +0200
    43.3 @@ -0,0 +1,136 @@
    43.4 +package org.apidesign.apifest08.test;
    43.5 +
    43.6 +import static org.apidesign.apifest08.test.Currencies.CZK;
    43.7 +import static org.apidesign.apifest08.test.Currencies.SKK;
    43.8 +import static org.apidesign.apifest08.test.Currencies.USD;
    43.9 +
   43.10 +import java.math.BigDecimal;
   43.11 +
   43.12 +import junit.framework.TestCase;
   43.13 +
   43.14 +import org.apidesign.apifest08.currency.Amount;
   43.15 +import org.apidesign.apifest08.currency.ConversionException;
   43.16 +import org.apidesign.apifest08.currency.Convertor;
   43.17 +import org.apidesign.apifest08.currency.UnsupportedConversionException;
   43.18 +
   43.19 +/** Finish the Convertor API, and then write bodies of methods inside
   43.20 + * of this class to match the given tasks. To fullfil your task, use the
   43.21 + * API define in the <code>org.apidesign.apifest08.currency</code> package.
   43.22 + * Do not you reflection, or other hacks as your code
   43.23 + * shall run without any runtime permissions.
   43.24 + */
   43.25 +public class Task1Test extends TestCase {
   43.26 +    public Task1Test(String testName) {
   43.27 +        super(testName);
   43.28 +    }
   43.29 +
   43.30 +    @Override
   43.31 +    protected void setUp() throws Exception {
   43.32 +    }
   43.33 +
   43.34 +    @Override
   43.35 +    protected void tearDown() throws Exception {
   43.36 +    }
   43.37 +
   43.38 +    /** Create convertor that understands two currencies, CZK and
   43.39 +     *  USD. Make 1 USD == 17 CZK.
   43.40 +     *
   43.41 +     * Creation of the convertor shall not require subclassing of any class
   43.42 +     * or interface on the client side.
   43.43 +     *
   43.44 +     * @return prepared convertor ready for converting USD to CZK and CZK to USD
   43.45 +     */
   43.46 +    public static Convertor createCZKtoUSD() {
   43.47 +        return new Convertor(new BigDecimal(17), USD, CZK);
   43.48 +    }
   43.49 +
   43.50 +    /** Create convertor that understands two currencies, CZK and
   43.51 +     *  SKK. Make 100 SKK == 80 CZK.
   43.52 +     *
   43.53 +     * Creation of the convertor shall not require subclassing of any class
   43.54 +     * or interface on the client side.
   43.55 +     * 
   43.56 +     * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
   43.57 +     */
   43.58 +    public static Convertor createSKKtoCZK() {
   43.59 +    	return new Convertor(new BigDecimal("0.8"), SKK, CZK);
   43.60 +    }
   43.61 +    
   43.62 +    /** Use the convertor from <code>createCZKtoUSD</code> method and do few conversions
   43.63 +     * with it.
   43.64 +     */
   43.65 +    public void testCurrencyCZKUSD() throws Exception {
   43.66 +        Convertor c = createCZKtoUSD();
   43.67 +        // convert $5 to CZK using c:
   43.68 +        Amount result =  c.convert(new BigDecimal(5), USD, CZK);
   43.69 +        assertEquals("Result is 85 CZK", 85, result.getValue().intValue());
   43.70 +
   43.71 +        // convert $8 to CZK
   43.72 +        result =  c.convert(new BigDecimal(8), USD, CZK);        
   43.73 +        assertEquals("Result is 136 CZK", 136, result.getValue().intValue());
   43.74 +
   43.75 +        // convert 1003CZK to USD
   43.76 +        result =  c.convert(new BigDecimal(1003), CZK, USD);
   43.77 +        assertEquals("Result is 59 USD", 59, result.getValue().intValue());
   43.78 +    }
   43.79 +
   43.80 +    /** Use the convertor from <code>createSKKtoCZK</code> method and do few conversions
   43.81 +     * with it.
   43.82 +     */
   43.83 +    public void testCurrencySKKCZK() throws Exception {
   43.84 +        Convertor c = createSKKtoCZK();
   43.85 +        // convert 16CZK using c:
   43.86 +        Amount result =  c.convert(new BigDecimal(16), CZK, SKK);
   43.87 +        assertEquals("Result is 20 SKK", 20, result.getValue().intValue());
   43.88 +
   43.89 +        // convert 500SKK to CZK
   43.90 +        result =  c.convert(new BigDecimal(500), SKK, CZK);
   43.91 +        assertEquals("Result is 400 CZK", 400, result.getValue().intValue());
   43.92 +    }
   43.93 +    
   43.94 +    
   43.95 +    /**
   43.96 +     *  Verify that the CZK to USD convertor knows nothing about SKK.
   43.97 +     */
   43.98 +     public void testCannotConvertToSKKwithCZKUSDConvertor() throws Exception {
   43.99 +    	 Convertor c = createCZKtoUSD();
  43.100 +    	 // convert $5 to SKK, the API shall say this is not possible
  43.101 +    	 try {
  43.102 +    		 c.convert(new BigDecimal(5), USD, SKK);
  43.103 +    		 fail("convert $5 to SKK, the API shall say this is not possible");
  43.104 +    	 } catch (ConversionException e) {
  43.105 +    		 //expected
  43.106 +    	 }
  43.107 +    	 
  43.108 +    	 // convert 500 SKK to CZK, the API shall say this is not possible
  43.109 +    	 
  43.110 +    	 try {
  43.111 +    		 c.convert(new BigDecimal("500"), SKK, CZK);
  43.112 +    		 fail("convert 500 SKK to CZK, the API shall say this is not possible");
  43.113 +    	 } catch (ConversionException e) {
  43.114 +    		 //expected
  43.115 +    	 }
  43.116 +     }
  43.117 +    
  43.118 +    /** 
  43.119 +     * Verify that the CZK to SKK convertor knows nothing about USD.
  43.120 +     */
  43.121 +    public void testCannotConvertToSKKwithCZKSKKConvertor() throws Exception {
  43.122 +    	Convertor c = createSKKtoCZK();
  43.123 +    	// convert $5 to SKK, the API shall say this is not possible
  43.124 +    	try {
  43.125 +    		c.convert(new BigDecimal(5), USD, SKK);
  43.126 +    		fail("convert $5 to SKK, the API shall say this is not possible");
  43.127 +    	} catch(ConversionException e) {
  43.128 +    		//expected
  43.129 +    	}
  43.130 +    	
  43.131 +    	try {
  43.132 +    		c.convert(new BigDecimal(500), CZK, USD);	
  43.133 +    		fail("convert 500 CZK to USD, the API shall say this is not possible");
  43.134 +    	} catch(ConversionException e) {
  43.135 +    		//expected
  43.136 +    	}
  43.137 +    } 
  43.138 +}
  43.139 +
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/task3/solution06/test/org/apidesign/apifest08/test/Task2Test.java	Tue Oct 07 11:05:34 2008 +0200
    44.3 @@ -0,0 +1,117 @@
    44.4 +package org.apidesign.apifest08.test;
    44.5 +
    44.6 +import static org.apidesign.apifest08.test.Currencies.CZK;
    44.7 +import static org.apidesign.apifest08.test.Currencies.USD;
    44.8 +import static org.apidesign.apifest08.test.Currencies.SKK;
    44.9 +
   44.10 +import java.math.BigDecimal;
   44.11 +
   44.12 +import junit.framework.TestCase;
   44.13 +import org.apidesign.apifest08.currency.Convertor;
   44.14 +import org.apidesign.apifest08.test.Task1Test;
   44.15 +
   44.16 +/** There are many currencies around the world and many banks manipulate
   44.17 + * with more than one or two at the same time. As banks are usually the
   44.18 + * best paying clients, which is true even in case of your Convertor API,
   44.19 + * it is reasonable to listen to their requests.
   44.20 + * <p>
   44.21 + * The quest for today is to enhance your existing convertor API to hold
   44.22 + * information about many currencies and allow conversions between any of them.
   44.23 + * Also, as conversion rates for diferent currencies usually arise from various
   44.24 + * bank departments, there is another important need. There is a need to
   44.25 + * compose two convertors into one by merging all the information about
   44.26 + * currencies they know about.
   44.27 + */
   44.28 +public class Task2Test extends TestCase {
   44.29 +    public Task2Test(String testName) {
   44.30 +        super(testName);
   44.31 +    }
   44.32 +
   44.33 +    @Override
   44.34 +    protected void setUp() throws Exception {
   44.35 +    }
   44.36 +
   44.37 +    @Override
   44.38 +    protected void tearDown() throws Exception {
   44.39 +    }
   44.40 +
   44.41 +    // As in Task1Test, keep in mind, that there are three parts
   44.42 +    // of the whole system:
   44.43 +    // 1. there is someone who knows the current exchange rate
   44.44 +    // 2. there is someone who wants to do the conversion
   44.45 +    // 3. there is the API between 1. and 2. which allows them to communicate
   44.46 +    // 
   44.47 +    // Please backward compatibly enhance your existing API to support following
   44.48 +    // usecases:
   44.49 +    //
   44.50 +    
   44.51 +    /** Create convertor that understands two currencies, CZK and
   44.52 +     *  SKK. Make 100 SKK == 75 CZK. This is method for the group of users that
   44.53 +     *  knows the exchange rate, and needs to use the API to create objects
   44.54 +     *  with the exchange rate. Anyone shall be ready to call this method without
   44.55 +     *  any other method being called previously. The API itself shall know
   44.56 +     *  nothing about any rates, before this method is called.
   44.57 +     */
   44.58 +    public static Convertor createTripleConvertor() {
   44.59 +        // Rates: 1USD = 15CZK
   44.60 +        // Rates: 1USD = 20SKK
   44.61 +        // Rates: 75CZK = 100SKK
   44.62 +    	Convertor usdCzk = new Convertor(new BigDecimal(15), USD, CZK);
   44.63 +    	Convertor usdSkk = new Convertor(new BigDecimal(20), USD, SKK);
   44.64 +    	Convertor skkCzk = new Convertor(new BigDecimal("0.75"), SKK, CZK);
   44.65 +        return new Convertor(new Convertor[]{usdCzk, usdSkk, skkCzk});
   44.66 +    }
   44.67 +
   44.68 +    /** Define convertor that understands three currencies. Use it.
   44.69 +     */
   44.70 +    public void testConvertorForUSDandCZKandSKK() throws Exception {
   44.71 +        Convertor c = createTripleConvertor();
   44.72 +
   44.73 +        // convert $5 to CZK using c:
   44.74 +        assertEquals("Result is 75 CZK", 75 ,c.convert(new BigDecimal(5), USD, CZK).getValue().intValue());
   44.75 +
   44.76 +        // convert $5 to SKK using c:
   44.77 +        assertEquals("Result is 100 SKK", 100, c.convert(new BigDecimal(5), USD, SKK).getValue().intValue());
   44.78 +
   44.79 +        // convert 200SKK to CZK using c:
   44.80 +        assertEquals("Result is 150 CZK", 150, c.convert(new BigDecimal(200), SKK, CZK).getValue().intValue());
   44.81 +
   44.82 +        // convert 200SKK to USK using c:
   44.83 +        assertEquals("Result is 10 USD", 10, c.convert(new BigDecimal(200), SKK, USD).getValue().intValue());
   44.84 +    }
   44.85 +
   44.86 +    /** Merge all currency rates of convertor 1 with convertor 2.
   44.87 +     * Implement this using your API, preferably this method just delegates
   44.88 +     * into some API method which does the actual work, without requiring
   44.89 +     * API clients to code anything complex.
   44.90 +     */
   44.91 +    public static Convertor merge(Convertor one, Convertor two) {
   44.92 +        return new Convertor(new Convertor[]{one, two});
   44.93 +    }
   44.94 +
   44.95 +    /** Join the convertors from previous task, Task1Test and show that it
   44.96 +     * can be used to do reasonable conversions.
   44.97 +     */
   44.98 +    public void testConvertorComposition() throws Exception {
   44.99 +        Convertor c = merge(
  44.100 +            Task1Test.createCZKtoUSD(),
  44.101 +            Task1Test.createSKKtoCZK()
  44.102 +        );
  44.103 +
  44.104 +        // convert $5 to CZK using c:
  44.105 +        assertEquals("Result is 85 CZK", 85, c.convert(new BigDecimal(5), USD, CZK).getValue().intValue());
  44.106 +
  44.107 +        // convert $8 to CZK using c:
  44.108 +        assertEquals("Result is 136 CZK", 136, c.convert(new BigDecimal(8), USD, CZK).getValue().intValue());
  44.109 +
  44.110 +        // convert 1003CZK to USD using c:
  44.111 +        assertEquals("Result is 59 USD", 59, c.convert(new BigDecimal(1003), CZK, USD).getValue().intValue());
  44.112 +
  44.113 +        // convert 16CZK using c:
  44.114 +        assertEquals("Result is 20 SKK", 20, c.convert(new BigDecimal(16), CZK, SKK).getValue().intValue());
  44.115 +
  44.116 +        // convert 500SKK to CZK using c:
  44.117 +        assertEquals("Result is 400 CZK", 400, c.convert(new BigDecimal(500), SKK, CZK).getValue().intValue());
  44.118 +
  44.119 +    }
  44.120 +}
    45.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.2 +++ b/task3/solution07/build.xml	Tue Oct 07 11:05:34 2008 +0200
    45.3 @@ -0,0 +1,69 @@
    45.4 +<?xml version="1.0" encoding="UTF-8"?>
    45.5 +<!-- You may freely edit this file. See commented blocks below for -->
    45.6 +<!-- some examples of how to customize the build. -->
    45.7 +<!-- (If you delete it and reopen the project it will be recreated.) -->
    45.8 +<project name="currency" default="default" basedir=".">
    45.9 +    <description>Builds, tests, and runs the project.</description>
   45.10 +    <import file="nbproject/build-impl.xml"/>
   45.11 +    <!--
   45.12 +
   45.13 +    There exist several targets which are by default empty and which can be 
   45.14 +    used for execution of your tasks. These targets are usually executed 
   45.15 +    before and after some main targets. They are: 
   45.16 +
   45.17 +      -pre-init:                 called before initialization of project properties
   45.18 +      -post-init:                called after initialization of project properties
   45.19 +      -pre-compile:              called before javac compilation
   45.20 +      -post-compile:             called after javac compilation
   45.21 +      -pre-compile-single:       called before javac compilation of single file
   45.22 +      -post-compile-single:      called after javac compilation of single file
   45.23 +      -pre-compile-test:         called before javac compilation of JUnit tests
   45.24 +      -post-compile-test:        called after javac compilation of JUnit tests
   45.25 +      -pre-compile-test-single:  called before javac compilation of single JUnit test
   45.26 +      -post-compile-test-single: called after javac compilation of single JUunit test
   45.27 +      -pre-jar:                  called before JAR building
   45.28 +      -post-jar:                 called after JAR building
   45.29 +      -post-clean:               called after cleaning build products
   45.30 +
   45.31 +    (Targets beginning with '-' are not intended to be called on their own.)
   45.32 +
   45.33 +    Example of inserting an obfuscator after compilation could look like this:
   45.34 +
   45.35 +        <target name="-post-compile">
   45.36 +            <obfuscate>
   45.37 +                <fileset dir="${build.classes.dir}"/>
   45.38 +            </obfuscate>
   45.39 +        </target>
   45.40 +
   45.41 +    For list of available properties check the imported 
   45.42 +    nbproject/build-impl.xml file. 
   45.43 +
   45.44 +
   45.45 +    Another way to customize the build is by overriding existing main targets.
   45.46 +    The targets of interest are: 
   45.47 +
   45.48 +      -init-macrodef-javac:     defines macro for javac compilation
   45.49 +      -init-macrodef-junit:     defines macro for junit execution
   45.50 +      -init-macrodef-debug:     defines macro for class debugging
   45.51 +      -init-macrodef-java:      defines macro for class execution
   45.52 +      -do-jar-with-manifest:    JAR building (if you are using a manifest)
   45.53 +      -do-jar-without-manifest: JAR building (if you are not using a manifest)
   45.54 +      run:                      execution of project 
   45.55 +      -javadoc-build:           Javadoc generation
   45.56 +      test-report:              JUnit report generation
   45.57 +
   45.58 +    An example of overriding the target for project execution could look like this:
   45.59 +
   45.60 +        <target name="run" depends="currency-impl.jar">
   45.61 +            <exec dir="bin" executable="launcher.exe">
   45.62 +                <arg file="${dist.jar}"/>
   45.63 +            </exec>
   45.64 +        </target>
   45.65 +
   45.66 +    Notice that the overridden target depends on the jar target and not only on 
   45.67 +    the compile target as the regular run target does. Again, for a list of available 
   45.68 +    properties which you can use, check the target you are overriding in the
   45.69 +    nbproject/build-impl.xml file. 
   45.70 +
   45.71 +    -->
   45.72 +</project>
    46.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.2 +++ b/task3/solution07/nbproject/build-impl.xml	Tue Oct 07 11:05:34 2008 +0200
    46.3 @@ -0,0 +1,642 @@
    46.4 +<?xml version="1.0" encoding="UTF-8"?>
    46.5 +<!--
    46.6 +*** GENERATED FROM project.xml - DO NOT EDIT  ***
    46.7 +***         EDIT ../build.xml INSTEAD         ***
    46.8 +
    46.9 +For the purpose of easier reading the script
   46.10 +is divided into following sections:
   46.11 +
   46.12 +  - initialization
   46.13 +  - compilation
   46.14 +  - jar
   46.15 +  - execution
   46.16 +  - debugging
   46.17 +  - javadoc
   46.18 +  - junit compilation
   46.19 +  - junit execution
   46.20 +  - junit debugging
   46.21 +  - applet
   46.22 +  - cleanup
   46.23 +
   46.24 +        -->
   46.25 +<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="Currency_Convertor_Solution_07-impl">
   46.26 +    <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
   46.27 +    <!-- 
   46.28 +                ======================
   46.29 +                INITIALIZATION SECTION 
   46.30 +                ======================
   46.31 +            -->
   46.32 +    <target name="-pre-init">
   46.33 +        <!-- Empty placeholder for easier customization. -->
   46.34 +        <!-- You can override this target in the ../build.xml file. -->
   46.35 +    </target>
   46.36 +    <target depends="-pre-init" name="-init-private">
   46.37 +        <property file="nbproject/private/config.properties"/>
   46.38 +        <property file="nbproject/private/configs/${config}.properties"/>
   46.39 +        <property file="nbproject/private/private.properties"/>
   46.40 +    </target>
   46.41 +    <target depends="-pre-init,-init-private" name="-init-user">
   46.42 +        <property file="${user.properties.file}"/>
   46.43 +        <!-- The two properties below are usually overridden -->
   46.44 +        <!-- by the active platform. Just a fallback. -->
   46.45 +        <property name="default.javac.source" value="1.4"/>
   46.46 +        <property name="default.javac.target" value="1.4"/>
   46.47 +    </target>
   46.48 +    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
   46.49 +        <property file="nbproject/configs/${config}.properties"/>
   46.50 +        <property file="nbproject/project.properties"/>
   46.51 +    </target>
   46.52 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
   46.53 +        <available file="${manifest.file}" property="manifest.available"/>
   46.54 +        <condition property="manifest.available+main.class">
   46.55 +            <and>
   46.56 +                <isset property="manifest.available"/>
   46.57 +                <isset property="main.class"/>
   46.58 +                <not>
   46.59 +                    <equals arg1="${main.class}" arg2="" trim="true"/>
   46.60 +                </not>
   46.61 +            </and>
   46.62 +        </condition>
   46.63 +        <condition property="manifest.available+main.class+mkdist.available">
   46.64 +            <and>
   46.65 +                <istrue value="${manifest.available+main.class}"/>
   46.66 +                <isset property="libs.CopyLibs.classpath"/>
   46.67 +            </and>
   46.68 +        </condition>
   46.69 +        <condition property="have.tests">
   46.70 +            <or>
   46.71 +                <available file="${test.src.dir}"/>
   46.72 +            </or>
   46.73 +        </condition>
   46.74 +        <condition property="have.sources">
   46.75 +            <or>
   46.76 +                <available file="${src.dir}"/>
   46.77 +            </or>
   46.78 +        </condition>
   46.79 +        <condition property="netbeans.home+have.tests">
   46.80 +            <and>
   46.81 +                <isset property="netbeans.home"/>
   46.82 +                <isset property="have.tests"/>
   46.83 +            </and>
   46.84 +        </condition>
   46.85 +        <condition property="no.javadoc.preview">
   46.86 +            <and>
   46.87 +                <isset property="javadoc.preview"/>
   46.88 +                <isfalse value="${javadoc.preview}"/>
   46.89 +            </and>
   46.90 +        </condition>
   46.91 +        <property name="run.jvmargs" value=""/>
   46.92 +        <property name="javac.compilerargs" value=""/>
   46.93 +        <property name="work.dir" value="${basedir}"/>
   46.94 +        <condition property="no.deps">
   46.95 +            <and>
   46.96 +                <istrue value="${no.dependencies}"/>
   46.97 +            </and>
   46.98 +        </condition>
   46.99 +        <property name="javac.debug" value="true"/>
  46.100 +        <property name="javadoc.preview" value="true"/>
  46.101 +        <property name="application.args" value=""/>
  46.102 +        <property name="source.encoding" value="${file.encoding}"/>
  46.103 +        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
  46.104 +            <and>
  46.105 +                <isset property="javadoc.encoding"/>
  46.106 +                <not>
  46.107 +                    <equals arg1="${javadoc.encoding}" arg2=""/>
  46.108 +                </not>
  46.109 +            </and>
  46.110 +        </condition>
  46.111 +        <property name="javadoc.encoding.used" value="${source.encoding}"/>
  46.112 +        <property name="includes" value="**"/>
  46.113 +        <property name="excludes" value=""/>
  46.114 +        <property name="do.depend" value="false"/>
  46.115 +        <condition property="do.depend.true">
  46.116 +            <istrue value="${do.depend}"/>
  46.117 +        </condition>
  46.118 +        <condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
  46.119 +            <and>
  46.120 +                <isset property="jaxws.endorsed.dir"/>
  46.121 +                <available file="nbproject/jaxws-build.xml"/>
  46.122 +            </and>
  46.123 +        </condition>
  46.124 +    </target>
  46.125 +    <target name="-post-init">
  46.126 +        <!-- Empty placeholder for easier customization. -->
  46.127 +        <!-- You can override this target in the ../build.xml file. -->
  46.128 +    </target>
  46.129 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
  46.130 +        <fail unless="src.dir">Must set src.dir</fail>
  46.131 +        <fail unless="test.src.dir">Must set test.src.dir</fail>
  46.132 +        <fail unless="build.dir">Must set build.dir</fail>
  46.133 +        <fail unless="dist.dir">Must set dist.dir</fail>
  46.134 +        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
  46.135 +        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
  46.136 +        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
  46.137 +        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
  46.138 +        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
  46.139 +        <fail unless="dist.jar">Must set dist.jar</fail>
  46.140 +    </target>
  46.141 +    <target name="-init-macrodef-property">
  46.142 +        <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
  46.143 +            <attribute name="name"/>
  46.144 +            <attribute name="value"/>
  46.145 +            <sequential>
  46.146 +                <property name="@{name}" value="${@{value}}"/>
  46.147 +            </sequential>
  46.148 +        </macrodef>
  46.149 +    </target>
  46.150 +    <target name="-init-macrodef-javac">
  46.151 +        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
  46.152 +            <attribute default="${src.dir}" name="srcdir"/>
  46.153 +            <attribute default="${build.classes.dir}" name="destdir"/>
  46.154 +            <attribute default="${javac.classpath}" name="classpath"/>
  46.155 +            <attribute default="${includes}" name="includes"/>
  46.156 +            <attribute default="${excludes}" name="excludes"/>
  46.157 +            <attribute default="${javac.debug}" name="debug"/>
  46.158 +            <attribute default="" name="sourcepath"/>
  46.159 +            <element name="customize" optional="true"/>
  46.160 +            <sequential>
  46.161 +                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
  46.162 +                    <classpath>
  46.163 +                        <path path="@{classpath}"/>
  46.164 +                    </classpath>
  46.165 +                    <compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
  46.166 +                    <customize/>
  46.167 +                </javac>
  46.168 +            </sequential>
  46.169 +        </macrodef>
  46.170 +        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
  46.171 +            <attribute default="${src.dir}" name="srcdir"/>
  46.172 +            <attribute default="${build.classes.dir}" name="destdir"/>
  46.173 +            <attribute default="${javac.classpath}" name="classpath"/>
  46.174 +            <sequential>
  46.175 +                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
  46.176 +                    <classpath>
  46.177 +                        <path path="@{classpath}"/>
  46.178 +                    </classpath>
  46.179 +                </depend>
  46.180 +            </sequential>
  46.181 +        </macrodef>
  46.182 +        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
  46.183 +            <attribute default="${build.classes.dir}" name="destdir"/>
  46.184 +            <sequential>
  46.185 +                <fail unless="javac.includes">Must set javac.includes</fail>
  46.186 +                <pathconvert pathsep="," property="javac.includes.binary">
  46.187 +                    <path>
  46.188 +                        <filelist dir="@{destdir}" files="${javac.includes}"/>
  46.189 +                    </path>
  46.190 +                    <globmapper from="*.java" to="*.class"/>
  46.191 +                </pathconvert>
  46.192 +                <delete>
  46.193 +                    <files includes="${javac.includes.binary}"/>
  46.194 +                </delete>
  46.195 +            </sequential>
  46.196 +        </macrodef>
  46.197 +    </target>
  46.198 +    <target name="-init-macrodef-junit">
  46.199 +        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
  46.200 +            <attribute default="${includes}" name="includes"/>
  46.201 +            <attribute default="${excludes}" name="excludes"/>
  46.202 +            <attribute default="**" name="testincludes"/>
  46.203 +            <sequential>
  46.204 +                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
  46.205 +                    <batchtest todir="${build.test.results.dir}">
  46.206 +                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
  46.207 +                            <filename name="@{testincludes}"/>
  46.208 +                        </fileset>
  46.209 +                    </batchtest>
  46.210 +                    <classpath>
  46.211 +                        <path path="${run.test.classpath}"/>
  46.212 +                    </classpath>
  46.213 +                    <syspropertyset>
  46.214 +                        <propertyref prefix="test-sys-prop."/>
  46.215 +                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
  46.216 +                    </syspropertyset>
  46.217 +                    <formatter type="brief" usefile="false"/>
  46.218 +                    <formatter type="xml"/>
  46.219 +                    <jvmarg line="${run.jvmargs}"/>
  46.220 +                </junit>
  46.221 +            </sequential>
  46.222 +        </macrodef>
  46.223 +    </target>
  46.224 +    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
  46.225 +        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
  46.226 +            <attribute default="${main.class}" name="name"/>
  46.227 +            <attribute default="${debug.classpath}" name="classpath"/>
  46.228 +            <attribute default="" name="stopclassname"/>
  46.229 +            <sequential>
  46.230 +                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
  46.231 +                    <classpath>
  46.232 +                        <path path="@{classpath}"/>
  46.233 +                    </classpath>
  46.234 +                </nbjpdastart>
  46.235 +            </sequential>
  46.236 +        </macrodef>
  46.237 +        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
  46.238 +            <attribute default="${build.classes.dir}" name="dir"/>
  46.239 +            <sequential>
  46.240 +                <nbjpdareload>
  46.241 +                    <fileset dir="@{dir}" includes="${fix.classes}">
  46.242 +                        <include name="${fix.includes}*.class"/>
  46.243 +                    </fileset>
  46.244 +                </nbjpdareload>
  46.245 +            </sequential>
  46.246 +        </macrodef>
  46.247 +    </target>
  46.248 +    <target name="-init-debug-args">
  46.249 +        <property name="version-output" value="java version &quot;${ant.java.version}"/>
  46.250 +        <condition property="have-jdk-older-than-1.4">
  46.251 +            <or>
  46.252 +                <contains string="${version-output}" substring="java version &quot;1.0"/>
  46.253 +                <contains string="${version-output}" substring="java version &quot;1.1"/>
  46.254 +                <contains string="${version-output}" substring="java version &quot;1.2"/>
  46.255 +                <contains string="${version-output}" substring="java version &quot;1.3"/>
  46.256 +            </or>
  46.257 +        </condition>
  46.258 +        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
  46.259 +            <istrue value="${have-jdk-older-than-1.4}"/>
  46.260 +        </condition>
  46.261 +        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
  46.262 +            <os family="windows"/>
  46.263 +        </condition>
  46.264 +        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
  46.265 +            <isset property="debug.transport"/>
  46.266 +        </condition>
  46.267 +    </target>
  46.268 +    <target depends="-init-debug-args" name="-init-macrodef-debug">
  46.269 +        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
  46.270 +            <attribute default="${main.class}" name="classname"/>
  46.271 +            <attribute default="${debug.classpath}" name="classpath"/>
  46.272 +            <element name="customize" optional="true"/>
  46.273 +            <sequential>
  46.274 +                <java classname="@{classname}" dir="${work.dir}" fork="true">
  46.275 +                    <jvmarg line="${debug-args-line}"/>
  46.276 +                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
  46.277 +                    <jvmarg line="${run.jvmargs}"/>
  46.278 +                    <classpath>
  46.279 +                        <path path="@{classpath}"/>
  46.280 +                    </classpath>
  46.281 +                    <syspropertyset>
  46.282 +                        <propertyref prefix="run-sys-prop."/>
  46.283 +                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
  46.284 +                    </syspropertyset>
  46.285 +                    <customize/>
  46.286 +                </java>
  46.287 +            </sequential>
  46.288 +        </macrodef>
  46.289 +    </target>
  46.290 +    <target name="-init-macrodef-java">
  46.291 +        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
  46.292 +            <attribute default="${main.class}" name="classname"/>
  46.293 +            <element name="customize" optional="true"/>
  46.294 +            <sequential>
  46.295 +                <java classname="@{classname}" dir="${work.dir}" fork="true">
  46.296 +                    <jvmarg line="${run.jvmargs}"/>
  46.297 +                    <classpath>
  46.298 +                        <path path="${run.classpath}"/>
  46.299 +                    </classpath>
  46.300 +                    <syspropertyset>
  46.301 +                        <propertyref prefix="run-sys-prop."/>
  46.302 +                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
  46.303 +                    </syspropertyset>
  46.304 +                    <customize/>
  46.305 +                </java>
  46.306 +            </sequential>
  46.307 +        </macrodef>
  46.308 +    </target>
  46.309 +    <target name="-init-presetdef-jar">
  46.310 +        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
  46.311 +            <jar compress="${jar.compress}" jarfile="${dist.jar}">
  46.312 +                <j2seproject1:fileset dir="${build.classes.dir}"/>
  46.313 +            </jar>
  46.314 +        </presetdef>
  46.315 +    </target>
  46.316 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar" name="init"/>
  46.317 +    <!--
  46.318 +                ===================
  46.319 +                COMPILATION SECTION
  46.320 +                ===================
  46.321 +            -->
  46.322 +    <target depends="init" name="deps-jar" unless="no.deps"/>
  46.323 +    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
  46.324 +    <target depends="init" name="-check-automatic-build">
  46.325 +        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
  46.326 +    </target>
  46.327 +    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
  46.328 +        <antcall target="clean"/>
  46.329 +    </target>
  46.330 +    <target depends="init,deps-jar" name="-pre-pre-compile">
  46.331 +        <mkdir dir="${build.classes.dir}"/>
  46.332 +    </target>
  46.333 +    <target name="-pre-compile">
  46.334 +        <!-- Empty placeholder for easier customization. -->
  46.335 +        <!-- You can override this target in the ../build.xml file. -->
  46.336 +    </target>
  46.337 +    <target if="do.depend.true" name="-compile-depend">
  46.338 +        <j2seproject3:depend/>
  46.339 +    </target>
  46.340 +    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
  46.341 +        <j2seproject3:javac/>
  46.342 +        <copy todir="${build.classes.dir}">
  46.343 +            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  46.344 +        </copy>
  46.345 +    </target>
  46.346 +    <target name="-post-compile">
  46.347 +        <!-- Empty placeholder for easier customization. -->
  46.348 +        <!-- You can override this target in the ../build.xml file. -->
  46.349 +    </target>
  46.350 +    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
  46.351 +    <target name="-pre-compile-single">
  46.352 +        <!-- Empty placeholder for easier customization. -->
  46.353 +        <!-- You can override this target in the ../build.xml file. -->
  46.354 +    </target>
  46.355 +    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
  46.356 +        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
  46.357 +        <j2seproject3:force-recompile/>
  46.358 +        <j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
  46.359 +    </target>
  46.360 +    <target name="-post-compile-single">
  46.361 +        <!-- Empty placeholder for easier customization. -->
  46.362 +        <!-- You can override this target in the ../build.xml file. -->
  46.363 +    </target>
  46.364 +    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
  46.365 +    <!--
  46.366 +                ====================
  46.367 +                JAR BUILDING SECTION
  46.368 +                ====================
  46.369 +            -->
  46.370 +    <target depends="init" name="-pre-pre-jar">
  46.371 +        <dirname file="${dist.jar}" property="dist.jar.dir"/>
  46.372 +        <mkdir dir="${dist.jar.dir}"/>
  46.373 +    </target>
  46.374 +    <target name="-pre-jar">
  46.375 +        <!-- Empty placeholder for easier customization. -->
  46.376 +        <!-- You can override this target in the ../build.xml file. -->
  46.377 +    </target>
  46.378 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
  46.379 +        <j2seproject1:jar/>
  46.380 +    </target>
  46.381 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
  46.382 +        <j2seproject1:jar manifest="${manifest.file}"/>
  46.383 +    </target>
  46.384 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
  46.385 +        <j2seproject1:jar manifest="${manifest.file}">
  46.386 +            <j2seproject1:manifest>
  46.387 +                <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
  46.388 +            </j2seproject1:manifest>
  46.389 +        </j2seproject1:jar>
  46.390 +        <echo>To run this application from the command line without Ant, try:</echo>
  46.391 +        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
  46.392 +        <property location="${dist.jar}" name="dist.jar.resolved"/>
  46.393 +        <pathconvert property="run.classpath.with.dist.jar">
  46.394 +            <path path="${run.classpath}"/>
  46.395 +            <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
  46.396 +        </pathconvert>
  46.397 +        <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
  46.398 +    </target>
  46.399 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
  46.400 +        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
  46.401 +        <pathconvert property="run.classpath.without.build.classes.dir">
  46.402 +            <path path="${run.classpath}"/>
  46.403 +            <map from="${build.classes.dir.resolved}" to=""/>
  46.404 +        </pathconvert>
  46.405 +        <pathconvert pathsep=" " property="jar.classpath">
  46.406 +            <path path="${run.classpath.without.build.classes.dir}"/>
  46.407 +            <chainedmapper>
  46.408 +                <flattenmapper/>
  46.409 +                <globmapper from="*" to="lib/*"/>
  46.410 +            </chainedmapper>
  46.411 +        </pathconvert>
  46.412 +        <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
  46.413 +        <copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
  46.414 +            <fileset dir="${build.classes.dir}"/>
  46.415 +            <manifest>
  46.416 +                <attribute name="Main-Class" value="${main.class}"/>
  46.417 +                <attribute name="Class-Path" value="${jar.classpath}"/>
  46.418 +            </manifest>
  46.419 +        </copylibs>
  46.420 +        <echo>To run this application from the command line without Ant, try:</echo>
  46.421 +        <property location="${dist.jar}" name="dist.jar.resolved"/>
  46.422 +        <echo>java -jar "${dist.jar.resolved}"</echo>
  46.423 +    </target>
  46.424 +    <target name="-post-jar">
  46.425 +        <!-- Empty placeholder for easier customization. -->
  46.426 +        <!-- You can override this target in the ../build.xml file. -->
  46.427 +    </target>
  46.428 +    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
  46.429 +    <!--
  46.430 +                =================
  46.431 +                EXECUTION SECTION
  46.432 +                =================
  46.433 +            -->
  46.434 +    <target depends="init,compile" description="Run a main class." name="run">
  46.435 +        <j2seproject1:java>
  46.436 +            <customize>
  46.437 +                <arg line="${application.args}"/>
  46.438 +            </customize>
  46.439 +        </j2seproject1:java>
  46.440 +    </target>
  46.441 +    <target name="-do-not-recompile">
  46.442 +        <property name="javac.includes.binary" value=""/>
  46.443 +    </target>
  46.444 +    <target depends="init,-do-not-recompile,compile-single" name="run-single">
  46.445 +        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
  46.446 +        <j2seproject1:java classname="${run.class}"/>
  46.447 +    </target>
  46.448 +    <!--
  46.449 +                =================
  46.450 +                DEBUGGING SECTION
  46.451 +                =================
  46.452 +            -->
  46.453 +    <target depends="init" if="netbeans.home" name="-debug-start-debugger">
  46.454 +        <j2seproject1:nbjpdastart name="${debug.class}"/>
  46.455 +    </target>
  46.456 +    <target depends="init,compile" name="-debug-start-debuggee">
  46.457 +        <j2seproject3:debug>
  46.458 +            <customize>
  46.459 +                <arg line="${application.args}"/>
  46.460 +            </customize>
  46.461 +        </j2seproject3:debug>
  46.462 +    </target>
  46.463 +    <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
  46.464 +    <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
  46.465 +        <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
  46.466 +    </target>
  46.467 +    <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
  46.468 +    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
  46.469 +        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
  46.470 +        <j2seproject3:debug classname="${debug.class}"/>
  46.471 +    </target>
  46.472 +    <target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
  46.473 +    <target depends="init" name="-pre-debug-fix">
  46.474 +        <fail unless="fix.includes">Must set fix.includes</fail>
  46.475 +        <property name="javac.includes" value="${fix.includes}.java"/>
  46.476 +    </target>
  46.477 +    <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
  46.478 +        <j2seproject1:nbjpdareload/>
  46.479 +    </target>
  46.480 +    <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
  46.481 +    <!--
  46.482 +                ===============
  46.483 +                JAVADOC SECTION
  46.484 +                ===============
  46.485 +            -->
  46.486 +    <target depends="init" name="-javadoc-build">
  46.487 +        <mkdir dir="${dist.javadoc.dir}"/>
  46.488 +        <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
  46.489 +            <classpath>
  46.490 +                <path path="${javac.classpath}"/>
  46.491 +            </classpath>
  46.492 +            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
  46.493 +                <filename name="**/*.java"/>
  46.494 +            </fileset>
  46.495 +        </javadoc>
  46.496 +    </target>
  46.497 +    <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
  46.498 +        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
  46.499 +    </target>
  46.500 +    <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
  46.501 +    <!--
  46.502 +                =========================
  46.503 +                JUNIT COMPILATION SECTION
  46.504 +                =========================
  46.505 +            -->
  46.506 +    <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
  46.507 +        <mkdir dir="${build.test.classes.dir}"/>
  46.508 +    </target>
  46.509 +    <target name="-pre-compile-test">
  46.510 +        <!-- Empty placeholder for easier customization. -->
  46.511 +        <!-- You can override this target in the ../build.xml file. -->
  46.512 +    </target>
  46.513 +    <target if="do.depend.true" name="-compile-test-depend">
  46.514 +        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
  46.515 +    </target>
  46.516 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
  46.517 +        <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
  46.518 +        <copy todir="${build.test.classes.dir}">
  46.519 +            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  46.520 +        </copy>
  46.521 +    </target>
  46.522 +    <target name="-post-compile-test">
  46.523 +        <!-- Empty placeholder for easier customization. -->
  46.524 +        <!-- You can override this target in the ../build.xml file. -->
  46.525 +    </target>
  46.526 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
  46.527 +    <target name="-pre-compile-test-single">
  46.528 +        <!-- Empty placeholder for easier customization. -->
  46.529 +        <!-- You can override this target in the ../build.xml file. -->
  46.530 +    </target>
  46.531 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
  46.532 +        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
  46.533 +        <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
  46.534 +        <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
  46.535 +        <copy todir="${build.test.classes.dir}">
  46.536 +            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  46.537 +        </copy>
  46.538 +    </target>
  46.539 +    <target name="-post-compile-test-single">
  46.540 +        <!-- Empty placeholder for easier customization. -->
  46.541 +        <!-- You can override this target in the ../build.xml file. -->
  46.542 +    </target>
  46.543 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
  46.544 +    <!--
  46.545 +                =======================
  46.546 +                JUNIT EXECUTION SECTION
  46.547 +                =======================
  46.548 +            -->
  46.549 +    <target depends="init" if="have.tests" name="-pre-test-run">
  46.550 +        <mkdir dir="${build.test.results.dir}"/>
  46.551 +    </target>
  46.552 +    <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
  46.553 +        <j2seproject3:junit testincludes="**/*Test.java"/>
  46.554 +    </target>
  46.555 +    <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
  46.556 +        <fail if="tests.failed">Some tests failed; see details above.</fail>
  46.557 +    </target>
  46.558 +    <target depends="init" if="have.tests" name="test-report"/>
  46.559 +    <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
  46.560 +    <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
  46.561 +    <target depends="init" if="have.tests" name="-pre-test-run-single">
  46.562 +        <mkdir dir="${build.test.results.dir}"/>
  46.563 +    </target>
  46.564 +    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
  46.565 +        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
  46.566 +        <j2seproject3:junit excludes="" includes="${test.includes}"/>
  46.567 +    </target>
  46.568 +    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
  46.569 +        <fail if="tests.failed">Some tests failed; see details above.</fail>
  46.570 +    </target>
  46.571 +    <target depends="init,-do-not-recompile,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
  46.572 +    <!--
  46.573 +                =======================
  46.574 +                JUNIT DEBUGGING SECTION
  46.575 +                =======================
  46.576 +            -->
  46.577 +    <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
  46.578 +        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
  46.579 +        <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
  46.580 +        <delete file="${test.report.file}"/>
  46.581 +        <mkdir dir="${build.test.results.dir}"/>
  46.582 +        <j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
  46.583 +            <customize>
  46.584 +                <syspropertyset>
  46.585 +                    <propertyref prefix="test-sys-prop."/>
  46.586 +                    <mapper from="test-sys-prop.*" to="*" type="glob"/>
  46.587 +                </syspropertyset>
  46.588 +                <arg value="${test.class}"/>
  46.589 +                <arg value="showoutput=true"/>
  46.590 +                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
  46.591 +                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
  46.592 +            </customize>
  46.593 +        </j2seproject3:debug>
  46.594 +    </target>
  46.595 +    <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
  46.596 +        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
  46.597 +    </target>
  46.598 +    <target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
  46.599 +    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
  46.600 +        <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
  46.601 +    </target>
  46.602 +    <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
  46.603 +    <!--
  46.604 +                =========================
  46.605 +                APPLET EXECUTION SECTION
  46.606 +                =========================
  46.607 +            -->
  46.608 +    <target depends="init,compile-single" name="run-applet">
  46.609 +        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
  46.610 +        <j2seproject1:java classname="sun.applet.AppletViewer">
  46.611 +            <customize>
  46.612 +                <arg value="${applet.url}"/>
  46.613 +            </customize>
  46.614 +        </j2seproject1:java>
  46.615 +    </target>
  46.616 +    <!--
  46.617 +                =========================
  46.618 +                APPLET DEBUGGING  SECTION
  46.619 +                =========================
  46.620 +            -->
  46.621 +    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
  46.622 +        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
  46.623 +        <j2seproject3:debug classname="sun.applet.AppletViewer">
  46.624 +            <customize>
  46.625 +                <arg value="${applet.url}"/>
  46.626 +            </customize>
  46.627 +        </j2seproject3:debug>
  46.628 +    </target>
  46.629 +    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
  46.630 +    <!--
  46.631 +                ===============
  46.632 +                CLEANUP SECTION
  46.633 +                ===============
  46.634 +            -->
  46.635 +    <target depends="init" name="deps-clean" unless="no.deps"/>
  46.636 +    <target depends="init" name="-do-clean">
  46.637 +        <delete dir="${build.dir}"/>
  46.638 +        <delete dir="${dist.dir}"/>
  46.639 +    </target>
  46.640 +    <target name="-post-clean">
  46.641 +        <!-- Empty placeholder for easier customization. -->
  46.642 +        <!-- You can override this target in the ../build.xml file. -->
  46.643 +    </target>
  46.644 +    <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
  46.645 +</project>
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/task3/solution07/nbproject/genfiles.properties	Tue Oct 07 11:05:34 2008 +0200
    47.3 @@ -0,0 +1,8 @@
    47.4 +build.xml.data.CRC32=2ab820eb
    47.5 +build.xml.script.CRC32=58a52595
    47.6 +build.xml.stylesheet.CRC32=be360661
    47.7 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
    47.8 +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
    47.9 +nbproject/build-impl.xml.data.CRC32=979fc7ba
   47.10 +nbproject/build-impl.xml.script.CRC32=92452d37
   47.11 +nbproject/build-impl.xml.stylesheet.CRC32=e55b27f5
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/task3/solution07/nbproject/project.properties	Tue Oct 07 11:05:34 2008 +0200
    48.3 @@ -0,0 +1,68 @@
    48.4 +application.title=currency
    48.5 +application.vendor=apidesign.org
    48.6 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
    48.7 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
    48.8 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=default
    48.9 +build.classes.dir=${build.dir}/classes
   48.10 +build.classes.excludes=**/*.java,**/*.form
   48.11 +# This directory is removed when the project is cleaned:
   48.12 +build.dir=build
   48.13 +build.generated.dir=${build.dir}/generated
   48.14 +# Only compile against the classpath explicitly listed here:
   48.15 +build.sysclasspath=ignore
   48.16 +build.test.classes.dir=${build.dir}/test/classes
   48.17 +build.test.results.dir=${build.dir}/test/results
   48.18 +debug.classpath=\
   48.19 +    ${run.classpath}
   48.20 +debug.test.classpath=\
   48.21 +    ${run.test.classpath}
   48.22 +# This directory is removed when the project is cleaned:
   48.23 +dist.dir=dist
   48.24 +dist.jar=${dist.dir}/currency.jar
   48.25 +dist.javadoc.dir=${dist.dir}/javadoc
   48.26 +excludes=
   48.27 +file.reference.junit-4.4.jar=../../libs/junit-4.4.jar
   48.28 +file.reference.src-apifest08=..
   48.29 +includes=**
   48.30 +jar.compress=false
   48.31 +javac.classpath=
   48.32 +# Space-separated list of extra javac options
   48.33 +javac.compilerargs=
   48.34 +javac.deprecation=false
   48.35 +javac.source=1.5
   48.36 +javac.target=1.5
   48.37 +javac.test.classpath=\
   48.38 +    ${javac.classpath}:\
   48.39 +    ${build.classes.dir}:\
   48.40 +    ${file.reference.junit-4.4.jar}
   48.41 +javadoc.additionalparam=
   48.42 +javadoc.author=false
   48.43 +javadoc.encoding=
   48.44 +javadoc.noindex=false
   48.45 +javadoc.nonavbar=false
   48.46 +javadoc.notree=false
   48.47 +javadoc.private=false
   48.48 +javadoc.splitindex=true
   48.49 +javadoc.use=true
   48.50 +javadoc.version=false
   48.51 +javadoc.windowtitle=
   48.52 +jnlp.codebase.type=local
   48.53 +jnlp.codebase.url=file:/home/jarda/src/apifest08/currency/dist
   48.54 +jnlp.descriptor=application
   48.55 +jnlp.enabled=false
   48.56 +jnlp.offline-allowed=false
   48.57 +jnlp.signed=false
   48.58 +meta.inf.dir=${src.dir}/META-INF
   48.59 +platform.active=default_platform
   48.60 +run.classpath=\
   48.61 +    ${javac.classpath}:\
   48.62 +    ${build.classes.dir}
   48.63 +# Space-separated list of JVM arguments used when running the project
   48.64 +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
   48.65 +# or test-sys-prop.name=value to set system properties for unit tests):
   48.66 +run.jvmargs=
   48.67 +run.test.classpath=\
   48.68 +    ${javac.test.classpath}:\
   48.69 +    ${build.test.classes.dir}
   48.70 +src.dir=src
   48.71 +test.src.dir=test
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/task3/solution07/nbproject/project.xml	Tue Oct 07 11:05:34 2008 +0200
    49.3 @@ -0,0 +1,16 @@
    49.4 +<?xml version="1.0" encoding="UTF-8"?>
    49.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
    49.6 +    <type>org.netbeans.modules.java.j2seproject</type>
    49.7 +    <configuration>
    49.8 +        <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
    49.9 +            <name>Currency Convertor Solution 07</name>
   49.10 +            <minimum-ant-version>1.6.5</minimum-ant-version>
   49.11 +            <source-roots>
   49.12 +                <root id="src.dir"/>
   49.13 +            </source-roots>
   49.14 +            <test-roots>
   49.15 +                <root id="test.src.dir"/>
   49.16 +            </test-roots>
   49.17 +        </data>
   49.18 +    </configuration>
   49.19 +</project>
    50.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    50.2 +++ b/task3/solution07/src/org/apidesign/apifest08/currency/ConversionRate.java	Tue Oct 07 11:05:34 2008 +0200
    50.3 @@ -0,0 +1,91 @@
    50.4 +package org.apidesign.apifest08.currency;
    50.5 +
    50.6 +import java.math.BigDecimal;
    50.7 +import java.math.RoundingMode;
    50.8 +
    50.9 +/**
   50.10 + * A rate of conversion from one currency to another.
   50.11 + * @author jdvorak
   50.12 + */
   50.13 +public class ConversionRate {
   50.14 +
   50.15 +    private final MonetaryAmount srcUnitAmount;
   50.16 +    private final MonetaryAmount tgtUnitAmount;
   50.17 +    private final int tgtScale;
   50.18 +    private final RoundingMode roundingMode;
   50.19 +
   50.20 +    /**
   50.21 +     * A new conversion rate that gives tgtUnitAmount per every srcUnitAmount.
   50.22 +     * @param srcUnitAmount the amount of source currency
   50.23 +     * @param tgtUnitAmount the corresponding amount of target currency
   50.24 +     * @param tgtScale the scale of the target amounts
   50.25 +     * @param roundingMode the rounding mode to use when producing the target amounts
   50.26 +     */
   50.27 +    public ConversionRate( final MonetaryAmount srcUnitAmount, final MonetaryAmount tgtUnitAmount, final int targetScale, final RoundingMode roundingMode ) {
   50.28 +        this.srcUnitAmount = srcUnitAmount;
   50.29 +        this.tgtUnitAmount = tgtUnitAmount;
   50.30 +        this.tgtScale = targetScale;
   50.31 +        this.roundingMode = roundingMode;
   50.32 +    }
   50.33 +
   50.34 +    /**
   50.35 +     * A new conversion rate that gives tgtUnitAmount per every srcUnitAmount, default number of fraction digits and the given rounding mode.
   50.36 +     * @param srcUnitAmount the amount of source currency
   50.37 +     * @param tgtUnitAmount the corresponding amount of target currency
   50.38 +     * @param roundingMode the rounding mode to use
   50.39 +     */
   50.40 +    public ConversionRate( final MonetaryAmount srcUnitAmount, final MonetaryAmount tgtUnitAmount, final RoundingMode roundingMode ) {
   50.41 +        this( srcUnitAmount, tgtUnitAmount, tgtUnitAmount.getCurrency().getDefaultFractionDigits(), roundingMode );
   50.42 +    }
   50.43 +
   50.44 +    /**
   50.45 +     * A new conversion rate that gives tgtUnitAmount per every srcUnitAmount, default number of fraction digits and {@link RoundingMode#HALF_EVEN}.
   50.46 +     * @param srcUnitAmount the amount of source currency
   50.47 +     * @param tgtUnitAmount the corresponding amount of target currency
   50.48 +     */
   50.49 +    public ConversionRate( final MonetaryAmount srcUnitAmount, final MonetaryAmount tgtUnitAmount ) {
   50.50 +        this( srcUnitAmount, tgtUnitAmount, RoundingMode.HALF_EVEN );
   50.51 +    }
   50.52 +
   50.53 +    public RoundingMode getRoundingMode() {
   50.54 +        return roundingMode;
   50.55 +    }
   50.56 +
   50.57 +    public MonetaryAmount getSrcUnitAmount() {
   50.58 +        return srcUnitAmount;
   50.59 +    }
   50.60 +
   50.61 +    public int getTgtScale() {
   50.62 +        return tgtScale;
   50.63 +    }
   50.64 +
   50.65 +    public MonetaryAmount getTgtUnitAmount() {
   50.66 +        return tgtUnitAmount;
   50.67 +    }
   50.68 +    
   50.69 +    /**
   50.70 +     * Multiplies the given amount with the given rate.
   50.71 +     * @param srcAmount
   50.72 +     * @return
   50.73 +     */
   50.74 +    public BigDecimal convert( final BigDecimal srcAmount ) {
   50.75 +        return srcAmount
   50.76 +            .multiply( tgtUnitAmount.getAmount() )
   50.77 +            .divide( srcUnitAmount.getAmount(), tgtScale, roundingMode );
   50.78 +    }
   50.79 +    
   50.80 +    /**
   50.81 +     * Creates a monetary amount that corresponds to the given source amount multiplied by the rate.
   50.82 +     * @param srcAmount the source amount
   50.83 +     * @return the monetary amount in the target currency
   50.84 +     * @throws IllegalArgumentException if the currency of srcAmount is not equal to the source currency of this rate
   50.85 +     */
   50.86 +    public MonetaryAmount convert( final MonetaryAmount srcAmount ) {
   50.87 +        if ( srcUnitAmount.getCurrency().equals( srcAmount.getCurrency() ) ) {
   50.88 +            return new MonetaryAmount( convert( srcAmount.getAmount() ), tgtUnitAmount.getCurrency() );
   50.89 +        } else {
   50.90 +            throw new IllegalArgumentException( "This rate converts from " + srcUnitAmount.getCurrency() + ", but a conversion from " + srcAmount.getCurrency() + " is attempted" );
   50.91 +        }
   50.92 +    }
   50.93 +    
   50.94 +}
    51.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    51.2 +++ b/task3/solution07/src/org/apidesign/apifest08/currency/Convertor.java	Tue Oct 07 11:05:34 2008 +0200
    51.3 @@ -0,0 +1,109 @@
    51.4 +package org.apidesign.apifest08.currency;
    51.5 +
    51.6 +import java.util.Currency;
    51.7 +
    51.8 +/** This is the skeleton class for your API. You need to make it public, so
    51.9 + * it is accessible to your client code (currently in Task1Test.java) file.
   51.10 + * <p>
   51.11 + * Feel free to create additional classes or rename this one, just keep all
   51.12 + * the API and its implementation in this package. Do not spread it outside
   51.13 + * to other packages.
   51.14 + */
   51.15 +public interface Convertor {
   51.16 +    
   51.17 +    /**
   51.18 +     * Converts by taking a request and producing a response.
   51.19 +     * If a convertor finds it cannot perform the requested conversion,
   51.20 +     * it should return a non-null {@link ConversionResult} that has null {@link ConversionResult#getNetAmount()}.
   51.21 +     * A convertor must not convert to a different currency than the one specified in the request.
   51.22 +     * <p>
   51.23 +     * When the need comes to extend the semantics, one subclasses the ConversionRequest and/or ConversionResult classes.
   51.24 +     * <p>
   51.25 +     * This method can be called as many times as you like.
   51.26 +     * A {@link Convertor} shall be considered immutable wrt calls to {@link #convert(org.apidesign.apifest08.currency.Convertor.ConversionRequest).
   51.27 +     * This method of a single {@link Convertor} can be called from many threads concurrently.
   51.28 +     * @param req the conversion request; mustn't be null
   51.29 +     * @return the result of carrying out the conversion request; never null
   51.30 +     * @throws IllegalRequestSubtypeException when the particular implementation cannot handle a specific ConversionRequest type
   51.31 +     */
   51.32 +    public ConversionResult convert( final ConversionRequest req ) throws IllegalRequestSubtypeException;
   51.33 +
   51.34 +    /**
   51.35 +     * The request for converting a monetary amout into another currency.
   51.36 +     * Immutable.
   51.37 +     */
   51.38 +    public class ConversionRequest {
   51.39 +        
   51.40 +        private final MonetaryAmount srcAmount;
   51.41 +        private final Currency tgtCurrency;
   51.42 +
   51.43 +        /**
   51.44 +         * A request to convert srcAmount into tgtCurrency.
   51.45 +         * @param srcAmount the source amount; must not be null
   51.46 +         * @param tgtCurrency the currency we want it in afterwards; must not be null
   51.47 +         */
   51.48 +        public ConversionRequest( final MonetaryAmount srcAmount, final Currency tgtCurrency ) {
   51.49 +            this.srcAmount = srcAmount;
   51.50 +            this.tgtCurrency = tgtCurrency;
   51.51 +            if ( srcAmount == null ) {
   51.52 +                throw new NullPointerException( "The source amount" );
   51.53 +            }
   51.54 +            if ( tgtCurrency == null ) {
   51.55 +                throw new NullPointerException( "The target currency" );
   51.56 +            }
   51.57 +            if ( srcAmount.getCurrency().equals( tgtCurrency ) ) {
   51.58 +                throw new IllegalArgumentException( "Cannot request conversion from " + srcAmount.getCurrency() + " to " + tgtCurrency );
   51.59 +            }
   51.60 +        }
   51.61 +
   51.62 +        /**
   51.63 +         * The source amount.
   51.64 +         */
   51.65 +        public MonetaryAmount getSrcAmount() {
   51.66 +            return srcAmount;
   51.67 +        }
   51.68 +
   51.69 +        /**
   51.70 +         * The target currency.
   51.71 +         */
   51.72 +        public Currency getTgtCurrency() {
   51.73 +            return tgtCurrency;
   51.74 +        }
   51.75 +        
   51.76 +    }
   51.77 +    
   51.78 +    /**
   51.79 +     * The result of converting a monetary amount into another currency.
   51.80 +     * For now it records just the net amount one recieves from the conversion.
   51.81 +     * Immutable.
   51.82 +     * <p>
   51.83 +     * <b>Extension note:</b> 
   51.84 +     * Other items can be added further down the road, as the need for them arises.
   51.85 +     * These items might provide info on other aspects of the conversion,
   51.86 +     * such as the fee or a reason why the conversion might not be admissible.
   51.87 +     */
   51.88 +    public class ConversionResult {
   51.89 +        
   51.90 +        private final MonetaryAmount netAmount;
   51.91 +        
   51.92 +        /**
   51.93 +         * A new conversion result.
   51.94 +         * @param netAmount the amount one recieves from the conversion; 
   51.95 +         * null means the conversion was not admissible
   51.96 +         */
   51.97 +        public ConversionResult( final MonetaryAmount netAmount ) {
   51.98 +            this.netAmount = netAmount;
   51.99 +        }
  51.100 +        
  51.101 +        /**
  51.102 +         * The amount one recieves from the conversion.
  51.103 +         * If null, the conversion is not admissible.
  51.104 +         * @return the amount
  51.105 +         */
  51.106 +        public MonetaryAmount getNetAmount() {
  51.107 +            return netAmount;
  51.108 +        }
  51.109 +        
  51.110 +    }
  51.111 +    
  51.112 +}
    52.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    52.2 +++ b/task3/solution07/src/org/apidesign/apifest08/currency/DelegatingConvertor.java	Tue Oct 07 11:05:34 2008 +0200
    52.3 @@ -0,0 +1,28 @@
    52.4 +/*
    52.5 + * To change this template, choose Tools | Templates
    52.6 + * and open the template in the editor.
    52.7 + */
    52.8 +
    52.9 +package org.apidesign.apifest08.currency;
   52.10 +
   52.11 +/**
   52.12 + *
   52.13 + * @author jdvorak
   52.14 + */
   52.15 +public class DelegatingConvertor implements Convertor {
   52.16 +    
   52.17 +    private final Convertor underlyingConvertor;
   52.18 +
   52.19 +    public DelegatingConvertor( final Convertor underlyingConvertor ) {
   52.20 +        this.underlyingConvertor = underlyingConvertor;
   52.21 +    }
   52.22 +
   52.23 +    protected Convertor getUnderlyingConvertor() {
   52.24 +        return underlyingConvertor;
   52.25 +    }
   52.26 +    
   52.27 +    public ConversionResult convert( final ConversionRequest req ) {
   52.28 +        return underlyingConvertor.convert( req );
   52.29 +    }
   52.30 +    
   52.31 +}
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/task3/solution07/src/org/apidesign/apifest08/currency/IllegalRequestSubtypeException.java	Tue Oct 07 11:05:34 2008 +0200
    53.3 @@ -0,0 +1,30 @@
    53.4 +/*
    53.5 + * To change this template, choose Tools | Templates
    53.6 + * and open the template in the editor.
    53.7 + */
    53.8 +
    53.9 +package org.apidesign.apifest08.currency;
   53.10 +
   53.11 +/**
   53.12 + * Rised when a {@link Convertor} implementation cannot handle a particular subtype of {@link Convertor.ConversionRequest}.
   53.13 + * @author jdvorak
   53.14 + */
   53.15 +public class IllegalRequestSubtypeException extends IllegalArgumentException {
   53.16 +
   53.17 +    public IllegalRequestSubtypeException() {
   53.18 +        super();
   53.19 +    }
   53.20 +    
   53.21 +    public IllegalRequestSubtypeException( final String msg ) {
   53.22 +        super( msg );
   53.23 +    }
   53.24 +    
   53.25 +    public IllegalRequestSubtypeException( final Throwable cause ) {
   53.26 +        super( cause );
   53.27 +    }
   53.28 +    
   53.29 +    public IllegalRequestSubtypeException( final String msg, final Throwable cause ) {
   53.30 +        super( msg, cause );
   53.31 +    }
   53.32 +    
   53.33 +}
    54.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.2 +++ b/task3/solution07/src/org/apidesign/apifest08/currency/MonetaryAmount.java	Tue Oct 07 11:05:34 2008 +0200
    54.3 @@ -0,0 +1,89 @@
    54.4 +package org.apidesign.apifest08.currency;
    54.5 +
    54.6 +import java.math.BigDecimal;
    54.7 +import java.util.Currency;
    54.8 +
    54.9 +/**
   54.10 + * An amount of a currency.
   54.11 + * Immutable.
   54.12 + * @author jdvorak
   54.13 + */
   54.14 +public class MonetaryAmount {
   54.15 +
   54.16 +    private final BigDecimal amount;
   54.17 +    private final Currency currency;
   54.18 +    
   54.19 +    /**
   54.20 +     * A new amount.
   54.21 +     * @param amount the quantity of the currency; must not be null
   54.22 +     * @param currency the currency; must not be null
   54.23 +     */
   54.24 +    public MonetaryAmount( final BigDecimal amount, final Currency currency ) {
   54.25 +        this.amount = amount;
   54.26 +        this.currency = currency;
   54.27 +        if ( amount == null ) {
   54.28 +            throw new NullPointerException( "The amount" );
   54.29 +        }
   54.30 +        if ( currency == null ) {
   54.31 +            throw new NullPointerException( "The currency" );
   54.32 +        }
   54.33 +    }
   54.34 +    
   54.35 +    /**
   54.36 +     * A new amount.
   54.37 +     * @param amount the quantity of the currency; must not be null
   54.38 +     * @param currency the currency; must not be null
   54.39 +     */
   54.40 +    public MonetaryAmount( final double amount, final Currency currency ) {
   54.41 +        this( new BigDecimal( amount ), currency );
   54.42 +    }
   54.43 +    
   54.44 +    /**
   54.45 +     * The amount.
   54.46 +     * @return the amount
   54.47 +     */
   54.48 +    public BigDecimal getAmount() {
   54.49 +        return amount;
   54.50 +    }
   54.51 +    
   54.52 +    /**
   54.53 +     * The currency.
   54.54 +     * @return the currency
   54.55 +     */
   54.56 +    public Currency getCurrency() {
   54.57 +        return currency;
   54.58 +    }
   54.59 +
   54.60 +    /**
   54.61 +     * The string representation of the monetary amount.
   54.62 +     * @return the amount, a non-breakable space, the currency
   54.63 +     */
   54.64 +    @Override
   54.65 +    public String toString() {
   54.66 +        return amount.toPlainString() + "\u00a0" + currency.toString();
   54.67 +    }
   54.68 +    
   54.69 +    /**
   54.70 +     * Two monetary amounts are equal to each other iff they have equal amounts of equal currencies.
   54.71 +     * @param other the other object
   54.72 +     * @return equality
   54.73 +     */
   54.74 +    @Override
   54.75 +    public boolean equals( final Object other ) {
   54.76 +        if ( other instanceof MonetaryAmount ) {
   54.77 +            final MonetaryAmount otherMonetaryAmount = (MonetaryAmount) other;
   54.78 +            return getAmount().equals( otherMonetaryAmount.getAmount() ) && getCurrency().equals( otherMonetaryAmount.getCurrency() );
   54.79 +        }
   54.80 +        return false;
   54.81 +    }
   54.82 +    
   54.83 +    /**
   54.84 +     * The hash code combines the hash codes of the amount and of the currency.
   54.85 +     * @return hash code
   54.86 +     */
   54.87 +    @Override
   54.88 +    public int hashCode() {
   54.89 +        return amount.hashCode() * 37 + currency.hashCode();
   54.90 +    }
   54.91 +    
   54.92 +}
    55.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    55.2 +++ b/task3/solution07/src/org/apidesign/apifest08/currency/TableConvertor.java	Tue Oct 07 11:05:34 2008 +0200
    55.3 @@ -0,0 +1,71 @@
    55.4 +package org.apidesign.apifest08.currency;
    55.5 +
    55.6 +import java.util.Currency;
    55.7 +import java.util.HashMap;
    55.8 +import java.util.Map;
    55.9 +
   55.10 +/**
   55.11 + * A {@link Convertor} that works from a pre-set conversion table.
   55.12 + * First use {@link #putIntoTable(org.apidesign.apifest08.currency.ConversionRate)} to set the conversion table.
   55.13 + * Then invoke the {@link #convert(org.apidesign.apifest08.currency.Convertor.ConversionRequest)} method as many times as you wish.
   55.14 + * @author jdvorak
   55.15 + */
   55.16 +public class TableConvertor implements Convertor {
   55.17 +
   55.18 +    private final Map<Currency, Map<Currency, ConversionRate>> conversionTable = new HashMap<Currency, Map<Currency, ConversionRate>>();
   55.19 +    
   55.20 +    public TableConvertor() {
   55.21 +    }
   55.22 +
   55.23 +    /**
   55.24 +     * Puts a rate into the table.
   55.25 +     * @param rate
   55.26 +     */
   55.27 +    public void putIntoTable( final ConversionRate rate ) {
   55.28 +        final Currency srcCurrency = rate.getSrcUnitAmount().getCurrency();
   55.29 +        final Currency tgtCurrency = rate.getTgtUnitAmount().getCurrency();
   55.30 +        synchronized ( conversionTable ) {
   55.31 +            Map<Currency, ConversionRate> targetTable = conversionTable.get( srcCurrency );
   55.32 +            if ( targetTable == null ) {
   55.33 +                targetTable = new HashMap<Currency, ConversionRate>();
   55.34 +                conversionTable.put( srcCurrency, targetTable );
   55.35 +            }
   55.36 +            targetTable.put( tgtCurrency, rate );
   55.37 +        }
   55.38 +    }
   55.39 +    
   55.40 +    /**
   55.41 +     * Carries out the conversion.
   55.42 +     * If the table does not contain a conversion from the source currency to the target one,
   55.43 +     * a {@link ConversionResult} is returned that has null netAmount.
   55.44 +     * This implementation works with any {@link ConversionRequest}, it won't throw {@link IllegalRequestSubtypeException}.
   55.45 +     * @param req the conversion request
   55.46 +     * @return the conversion result
   55.47 +     */
   55.48 +    public ConversionResult convert( final ConversionRequest req ) {
   55.49 +        final Currency srcCurrency = req.getSrcAmount().getCurrency();
   55.50 +        final Currency tgtCurrency = req.getTgtCurrency();
   55.51 +        final ConversionRate rate = findConversionRate( srcCurrency, tgtCurrency );
   55.52 +        if ( rate != null ) {
   55.53 +            final MonetaryAmount tgtAmount = rate.convert( req.getSrcAmount() );
   55.54 +            return new ConversionResult( tgtAmount );
   55.55 +        } else {
   55.56 +            return new ConversionResult( null );    // did not find the pair of currencies in the table
   55.57 +        }
   55.58 +    }
   55.59 +
   55.60 +    /**
   55.61 +     * Looks up the conversion between the given currencies in the table.
   55.62 +     * @param srcCurrency the source currency
   55.63 +     * @param tgtCurrency the target currency
   55.64 +     * @return the conversion rate; null means no conversion between the currencies was found in the table
   55.65 +     */
   55.66 +    protected ConversionRate findConversionRate( final Currency srcCurrency, final Currency tgtCurrency ) {
   55.67 +        synchronized ( conversionTable ) {
   55.68 +            final Map<Currency, ConversionRate> targetTable = conversionTable.get(srcCurrency);
   55.69 +            final ConversionRate rate = (targetTable != null) ? targetTable.get(tgtCurrency) : null;
   55.70 +            return rate;
   55.71 +        }
   55.72 +    }
   55.73 +
   55.74 +}
    56.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    56.2 +++ b/task3/solution07/test/org/apidesign/apifest08/test/ContractImposingDelegatingConvertor.java	Tue Oct 07 11:05:34 2008 +0200
    56.3 @@ -0,0 +1,53 @@
    56.4 +/*
    56.5 + * To change this template, choose Tools | Templates
    56.6 + * and open the template in the editor.
    56.7 + */
    56.8 +
    56.9 +package org.apidesign.apifest08.test;
   56.10 +
   56.11 +import java.math.BigDecimal;
   56.12 +import java.util.Currency;
   56.13 +import junit.framework.Assert;
   56.14 +import org.apidesign.apifest08.currency.Convertor;
   56.15 +import org.apidesign.apifest08.currency.DelegatingConvertor;
   56.16 +import org.apidesign.apifest08.currency.MonetaryAmount;
   56.17 +
   56.18 +/**
   56.19 + * A delegating convertor that checks preconditions and postconditions.
   56.20 + * Useful for testing.
   56.21 + * @author jdvorak
   56.22 + */
   56.23 +public class ContractImposingDelegatingConvertor extends DelegatingConvertor {
   56.24 +
   56.25 +    public ContractImposingDelegatingConvertor( final Convertor underlyingConvertor ) {
   56.26 +        super( underlyingConvertor );
   56.27 +    }
   56.28 +
   56.29 +    @Override
   56.30 +    public ConversionResult convert( final ConversionRequest req ) {
   56.31 +        Assert.assertNotNull( "The request", req );
   56.32 +        final ConversionResult result = super.convert( req );
   56.33 +        Assert.assertNotNull( "Result of the convert() call", result );
   56.34 +        final MonetaryAmount netAmount = result.getNetAmount();
   56.35 +        if ( netAmount != null ) {
   56.36 +            Assert.assertEquals( "Converted to a different currency than specified in the request", req.getTgtCurrency(), netAmount.getCurrency() );
   56.37 +        }
   56.38 +        return result;
   56.39 +    }
   56.40 +
   56.41 +    /**
   56.42 +     * Do some tests on our own.
   56.43 +     * @return this
   56.44 +     */
   56.45 +    public Convertor test() {
   56.46 +        try {
   56.47 +            final Currency aCurrency = Currency.getInstance( "EUR" );
   56.48 +            new ConversionRequest( new MonetaryAmount( BigDecimal.ONE, aCurrency ), aCurrency );
   56.49 +            Assert.fail( "Should have thrown an IllegalArgumentException" );
   56.50 +        } catch ( final IllegalArgumentException e ) {
   56.51 +            Assert.assertEquals( "Cannot request conversion from EUR to EUR", e.getMessage() );
   56.52 +        }
   56.53 +        return this;
   56.54 +    }
   56.55 +
   56.56 +}
    57.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    57.2 +++ b/task3/solution07/test/org/apidesign/apifest08/test/Task1Test.java	Tue Oct 07 11:05:34 2008 +0200
    57.3 @@ -0,0 +1,177 @@
    57.4 +package org.apidesign.apifest08.test;
    57.5 +
    57.6 +import java.util.Currency;
    57.7 +import junit.framework.TestCase;
    57.8 +import org.apidesign.apifest08.currency.ConversionRate;
    57.9 +import org.apidesign.apifest08.currency.Convertor;
   57.10 +import org.apidesign.apifest08.currency.MonetaryAmount;
   57.11 +import org.apidesign.apifest08.currency.TableConvertor;
   57.12 +
   57.13 +/** Finish the Convertor API, and then write bodies of methods inside
   57.14 + * of this class to match the given tasks. To fullfil your task, use the
   57.15 + * API define in the <code>org.apidesign.apifest08.currency</code> package.
   57.16 + * Do not you reflection, or other hacks as your code
   57.17 + * shall run without any runtime permissions.
   57.18 + */
   57.19 +public class Task1Test extends TestCase {
   57.20 +    public Task1Test(String testName) {
   57.21 +        super(testName);
   57.22 +    }
   57.23 +
   57.24 +    @Override
   57.25 +    protected void setUp() throws Exception {
   57.26 +    }
   57.27 +
   57.28 +    @Override
   57.29 +    protected void tearDown() throws Exception {
   57.30 +    }
   57.31 +
   57.32 +    //
   57.33 +    // Imagine that there are three parts of the whole system:
   57.34 +    // 1. there is someone who knows the current exchange rate
   57.35 +    // 2. there is someone who wants to do the conversion
   57.36 +    // 3. there is the API between 1. and 2. which allows them to communicate
   57.37 +    // Please design such API
   57.38 +    //
   57.39 +
   57.40 +    protected static final Currency CZK = Currency.getInstance( "CZK" );
   57.41 +    protected static final Currency SKK = Currency.getInstance( "SKK" );
   57.42 +    protected static final Currency USD = Currency.getInstance( "USD" );
   57.43 +    
   57.44 +    /** Create convertor that understands two currencies, CZK and
   57.45 +     *  USD. Make 1 USD == 17 CZK.
   57.46 +     *  USD. Make 1 USD == 17 CZK. This is a method provided for #1 group -
   57.47 +     *  e.g. those that know the exchange rate. They somehow need to create
   57.48 +     *  the objects from the API and tell them the exchange rate. The API itself
   57.49 +     *  knows nothing about any rates, before the createCZKtoUSD method is called.
   57.50 +     *
   57.51 +     * Creation of the convertor shall not require subclassing of any class
   57.52 +     * or interface on the client side.
   57.53 +     *
   57.54 +     * @return prepared convertor ready for converting USD to CZK and CZK to USD
   57.55 +     */
   57.56 +    public static Convertor createCZKtoUSD() {
   57.57 +        final TableConvertor convertor = new TableConvertor();
   57.58 +        final MonetaryAmount amountInCZK = new MonetaryAmount( 17, CZK );
   57.59 +        final MonetaryAmount amountInUSD = new MonetaryAmount( 1, USD );
   57.60 +        convertor.putIntoTable( new ConversionRate( amountInCZK, amountInUSD ) );
   57.61 +        convertor.putIntoTable( new ConversionRate( amountInUSD, amountInCZK ) );
   57.62 +        return new ContractImposingDelegatingConvertor( convertor ).test();
   57.63 +    }
   57.64 +
   57.65 +    /** Create convertor that understands two currencies, CZK and
   57.66 +     *  SKK. Make 100 SKK == 80 CZK. Again this is method for the #1 group -
   57.67 +     *  it knows the exchange rate, and needs to use the API to create objects
   57.68 +     *  with the exchange rate. Anyone shall be ready to call this method without
   57.69 +     *  any other method being called previously. The API itself shall know
   57.70 +     *  nothing about any rates, before this method is called.
   57.71 +     *
   57.72 +     * Creation of the convertor shall not require subclassing of any class
   57.73 +     * or interface on the client side.
   57.74 +     * 
   57.75 +     * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
   57.76 +     */
   57.77 +    public static Convertor createSKKtoCZK() {
   57.78 +        final TableConvertor convertor = new TableConvertor();
   57.79 +        final MonetaryAmount amountInSKK = new MonetaryAmount( 100, SKK );
   57.80 +        final MonetaryAmount amountInCZK = new MonetaryAmount( 80, CZK );
   57.81 +        convertor.putIntoTable( new ConversionRate( amountInSKK, amountInCZK ) );
   57.82 +        convertor.putIntoTable( new ConversionRate( amountInCZK, amountInSKK ) );
   57.83 +        return new ContractImposingDelegatingConvertor( convertor ).test();
   57.84 +    }
   57.85 +
   57.86 +    //
   57.87 +    // now the methods for group #2 follow:
   57.88 +    // this group knows nothing about exchange rates, but knows how to use
   57.89 +    // the API to do conversions. It somehow (by calling one of the factory
   57.90 +    // methods) gets objects from the API and uses them to do the conversions.
   57.91 +    //
   57.92 +
   57.93 +    /** Use the convertor from <code>createCZKtoUSD</code> method and do few conversions
   57.94 +     * with it.
   57.95 +     */
   57.96 +    public void testCurrencyCZKUSD() throws Exception {
   57.97 +        final Convertor c = createCZKtoUSD();
   57.98 +        
   57.99 +        // convert $5 to CZK using c:
  57.100 +        final Convertor.ConversionResult r1 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), CZK ) );
  57.101 +        final MonetaryAmount a1 = r1.getNetAmount();
  57.102 +        // assertEquals("Result is 85 CZK");
  57.103 +        assertNotNull( a1 );
  57.104 +        assertEquals( 85.0, a1.getAmount().doubleValue() );
  57.105 +        assertEquals( CZK, a1.getCurrency() );
  57.106 +
  57.107 +        // convert $8 to CZK
  57.108 +        final Convertor.ConversionResult r2 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 8, USD ), CZK ) );
  57.109 +        final MonetaryAmount a2 = r2.getNetAmount();
  57.110 +        // assertEquals("Result is 136 CZK");
  57.111 +        assertNotNull( a2 );
  57.112 +        assertEquals( 136.0, a2.getAmount().doubleValue() );
  57.113 +        assertEquals( CZK, a2.getCurrency() );
  57.114 +
  57.115 +        // convert 1003CZK to USD
  57.116 +        final Convertor.ConversionResult r3 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 1003, CZK ), USD ) );
  57.117 +        final MonetaryAmount a3 = r3.getNetAmount();
  57.118 +        // assertEquals("Result is 59 USD");
  57.119 +        assertNotNull( a3 );
  57.120 +        assertEquals( 59.0, a3.getAmount().doubleValue() );
  57.121 +        assertEquals( USD, a3.getCurrency() );
  57.122 +    }
  57.123 +
  57.124 +    /** Use the convertor from <code>createSKKtoCZK</code> method and do few conversions
  57.125 +     * with it.
  57.126 +     */
  57.127 +    public void testCurrencySKKCZK() throws Exception {
  57.128 +        final Convertor c = createSKKtoCZK();
  57.129 +        
  57.130 +        // convert 16CZK using c:
  57.131 +        final Convertor.ConversionResult r1 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 16, CZK ), SKK ) );
  57.132 +        final MonetaryAmount a1 = r1.getNetAmount();
  57.133 +        // assertEquals("Result is 20 SKK");
  57.134 +        assertNotNull( a1 );
  57.135 +        assertEquals( 20.0, a1.getAmount().doubleValue() );
  57.136 +        assertEquals( SKK, a1.getCurrency() );
  57.137 +        
  57.138 +        // convert 500SKK to CZK
  57.139 +        final Convertor.ConversionResult r2 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 500, SKK ), CZK ) );
  57.140 +        final MonetaryAmount a2 = r2.getNetAmount();
  57.141 +        // assertEquals("Result is 400 CZK");
  57.142 +        assertNotNull( a2 );
  57.143 +        assertEquals( 400.0, a2.getAmount().doubleValue() );
  57.144 +        assertEquals( CZK, a2.getCurrency() );
  57.145 +    }
  57.146 +
  57.147 +    /** Verify that the CZK to USD convertor knows nothing about SKK.
  57.148 +    */
  57.149 +    public void testCannotConvertToSKKwithCZKUSDConvertor() throws Exception {
  57.150 +        final Convertor c = createCZKtoUSD();
  57.151 +        
  57.152 +        // convert $5 to SKK, the API shall say this is not possible
  57.153 +        final Convertor.ConversionResult r1 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), SKK ) );
  57.154 +        final MonetaryAmount a1 = r1.getNetAmount();
  57.155 +        assertNull( a1 );
  57.156 +
  57.157 +        // convert 500 SKK to CZK, the API shall say this is not possible
  57.158 +        final Convertor.ConversionResult r2 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, SKK ), CZK ) );
  57.159 +        final MonetaryAmount a2 = r2.getNetAmount();
  57.160 +        assertNull( a2 );
  57.161 +    }
  57.162 +
  57.163 +    /** Verify that the CZK to SKK convertor knows nothing about USD.
  57.164 +    */
  57.165 +    public void testCannotConvertToUSDwithCZKSKKConvertor() throws Exception {
  57.166 +        final Convertor c = createSKKtoCZK();
  57.167 +        
  57.168 +        // convert $5 to SKK, the API shall say this is not possible
  57.169 +        final Convertor.ConversionResult r1 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), SKK ) );
  57.170 +        final MonetaryAmount a1 = r1.getNetAmount();
  57.171 +        assertNull( a1 );
  57.172 +        
  57.173 +        // convert 500 CZK to USD, the API shall say this is not possible
  57.174 +        final Convertor.ConversionResult r2 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, CZK ), USD ) );
  57.175 +        final MonetaryAmount a2 = r2.getNetAmount();
  57.176 +        assertNull( a2 );
  57.177 +    }
  57.178 +
  57.179 +}
  57.180 +
    58.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    58.2 +++ b/task3/solution07/test/org/apidesign/apifest08/test/Task2Test.java	Tue Oct 07 11:05:34 2008 +0200
    58.3 @@ -0,0 +1,192 @@
    58.4 +package org.apidesign.apifest08.test;
    58.5 +
    58.6 +import java.util.Currency;
    58.7 +import junit.framework.TestCase;
    58.8 +import org.apidesign.apifest08.currency.ConversionRate;
    58.9 +import org.apidesign.apifest08.currency.Convertor;
   58.10 +import org.apidesign.apifest08.currency.IllegalRequestSubtypeException;
   58.11 +import org.apidesign.apifest08.currency.MonetaryAmount;
   58.12 +import org.apidesign.apifest08.currency.TableConvertor;
   58.13 +
   58.14 +/** There are many currencies around the world and many banks manipulate
   58.15 + * with more than one or two at the same time. As banks are usually the
   58.16 + * best paying clients, which is true even in case of your Convertor API,
   58.17 + * it is reasonable to listen to their requests.
   58.18 + * <p>
   58.19 + * The quest for today is to enhance your existing convertor API to hold
   58.20 + * information about many currencies and allow conversions between any of them.
   58.21 + * Also, as conversion rates for diferent currencies usually arise from various
   58.22 + * bank departments, there is another important need. There is a need to
   58.23 + * compose two convertors into one by merging all the information about
   58.24 + * currencies they know about.
   58.25 + */
   58.26 +public class Task2Test extends TestCase {
   58.27 +    public Task2Test(String testName) {
   58.28 +        super(testName);
   58.29 +    }
   58.30 +
   58.31 +    @Override
   58.32 +    protected void setUp() throws Exception {
   58.33 +    }
   58.34 +
   58.35 +    @Override
   58.36 +    protected void tearDown() throws Exception {
   58.37 +    }
   58.38 +
   58.39 +    protected static final Currency CZK = Currency.getInstance( "CZK" );
   58.40 +    protected static final Currency SKK = Currency.getInstance( "SKK" );
   58.41 +    protected static final Currency USD = Currency.getInstance( "USD" );
   58.42 +
   58.43 +    // As in Task1Test, keep in mind, that there are three parts
   58.44 +    // of the whole system:
   58.45 +    // 1. there is someone who knows the current exchange rate
   58.46 +    // 2. there is someone who wants to do the conversion
   58.47 +    // 3. there is the API between 1. and 2. which allows them to communicate
   58.48 +    // 
   58.49 +    // Please backward compatibly enhance your existing API to support following
   58.50 +    // usecases:
   58.51 +    //
   58.52 +    
   58.53 +    /** Create convertor that understands two currencies, CZK and
   58.54 +     *  SKK. Make 100 SKK == 75 CZK. This is method for the group of users that
   58.55 +     *  knows the exchange rate, and needs to use the API to create objects
   58.56 +     *  with the exchange rate. Anyone shall be ready to call this method without
   58.57 +     *  any other method being called previously. The API itself shall know
   58.58 +     *  nothing about any rates, before this method is called.
   58.59 +     */
   58.60 +    public static Convertor createTripleConvertor() {
   58.61 +        // Rates: 1USD = 15CZK
   58.62 +        // Rates: 1USD = 20SKK
   58.63 +        // Rates: 75CZK = 100SKK
   58.64 +        final TableConvertor convertor = new TableConvertor();
   58.65 +        final MonetaryAmount amountInUSD = new MonetaryAmount( 1, USD );
   58.66 +        final MonetaryAmount amountInCZK = new MonetaryAmount( 15, CZK );
   58.67 +        final MonetaryAmount amountInSKK = new MonetaryAmount( 20, SKK );
   58.68 +        convertor.putIntoTable( new ConversionRate( amountInCZK, amountInUSD ) );
   58.69 +        convertor.putIntoTable( new ConversionRate( amountInUSD, amountInCZK ) );
   58.70 +        convertor.putIntoTable( new ConversionRate( amountInSKK, amountInUSD ) );
   58.71 +        convertor.putIntoTable( new ConversionRate( amountInUSD, amountInSKK ) );
   58.72 +        convertor.putIntoTable( new ConversionRate( amountInSKK, amountInCZK ) );
   58.73 +        convertor.putIntoTable( new ConversionRate( amountInCZK, amountInSKK ) );
   58.74 +        return new ContractImposingDelegatingConvertor( convertor ).test();
   58.75 +    }
   58.76 +
   58.77 +    /** Define convertor that understands three currencies. Use it.
   58.78 +     */
   58.79 +    public void testConvertorForUSDandCZKandSKK() throws Exception {
   58.80 +        final Convertor c = createTripleConvertor();
   58.81 +
   58.82 +        // convert $5 to CZK using c:
   58.83 +        final Convertor.ConversionResult r1 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), CZK ) );
   58.84 +        final MonetaryAmount a1 = r1.getNetAmount();
   58.85 +        // assertEquals("Result is 75 CZK");
   58.86 +        assertNotNull( a1 );
   58.87 +        assertEquals( 75.0, a1.getAmount().doubleValue() );
   58.88 +        assertEquals( CZK, a1.getCurrency() );
   58.89 +
   58.90 +        // convert $5 to SKK using c:
   58.91 +        final Convertor.ConversionResult r2 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), SKK ) );
   58.92 +        final MonetaryAmount a2 = r2.getNetAmount();
   58.93 +        // assertEquals("Result is 100 SKK");
   58.94 +        assertNotNull( a2 );
   58.95 +        assertEquals( 100.0, a2.getAmount().doubleValue() );
   58.96 +        assertEquals( SKK, a2.getCurrency() );
   58.97 +
   58.98 +        // convert 200SKK to CZK using c:
   58.99 +        final Convertor.ConversionResult r3 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 200, SKK ), CZK ) );
  58.100 +        final MonetaryAmount a3 = r3.getNetAmount();
  58.101 +        // assertEquals("Result is 150 CZK");
  58.102 +        assertNotNull( a3 );
  58.103 +        assertEquals( 150.0, a3.getAmount().doubleValue() );
  58.104 +        assertEquals( CZK, a3.getCurrency() );
  58.105 +
  58.106 +        // convert 200SKK to USK using c:
  58.107 +        final Convertor.ConversionResult r4 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 200, SKK ), USD ) );
  58.108 +        final MonetaryAmount a4 = r4.getNetAmount();
  58.109 +        // assertEquals("Result is 10 USD");
  58.110 +        assertNotNull( a4 );
  58.111 +        assertEquals( 10.0, a4.getAmount().doubleValue() );
  58.112 +        assertEquals( USD, a4.getCurrency() );
  58.113 +    }
  58.114 +
  58.115 +    /** Merge all currency rates of convertor 1 with convertor 2.
  58.116 +     * Implement this using your API, preferably this method just delegates
  58.117 +     * into some API method which does the actual work, without requiring
  58.118 +     * API clients to code anything complex.
  58.119 +     */
  58.120 +    public static Convertor merge( final Convertor one, final Convertor two ) {
  58.121 +        return new Convertor() {
  58.122 +
  58.123 +            public ConversionResult convert( ConversionRequest req ) throws IllegalRequestSubtypeException {
  58.124 +                final ConversionResult res1 = one.convert( req );
  58.125 +                final ConversionResult res2 = two.convert( req );
  58.126 +                if ( res1.getNetAmount() != null ) {
  58.127 +                    if ( res2.getNetAmount() != null ) {
  58.128 +                        // TODO check if they arrive at the same thing
  58.129 +                        return res1;
  58.130 +                    } else {
  58.131 +                        return res1;
  58.132 +                    }
  58.133 +                } else {
  58.134 +                    if ( res2.getNetAmount() != null ) {
  58.135 +                        return res2;
  58.136 +                    } else {
  58.137 +                        // neither converts
  58.138 +                        return new ConversionResult( null );
  58.139 +                    }                    
  58.140 +                }
  58.141 +            }
  58.142 +            
  58.143 +        };
  58.144 +    }
  58.145 +
  58.146 +    /** Join the convertors from previous task, Task1Test and show that it
  58.147 +     * can be used to do reasonable conversions.
  58.148 +     */
  58.149 +    public void testConvertorComposition() throws Exception {
  58.150 +        final Convertor c = merge(
  58.151 +            Task1Test.createCZKtoUSD(),
  58.152 +            Task1Test.createSKKtoCZK()
  58.153 +        );
  58.154 +
  58.155 +        // convert $5 to CZK using c:
  58.156 +        final Convertor.ConversionResult r1 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), CZK ) );
  58.157 +        final MonetaryAmount a1 = r1.getNetAmount();
  58.158 +        // assertEquals("Result is 85 CZK");
  58.159 +        assertNotNull( a1 );
  58.160 +        assertEquals( 85.0, a1.getAmount().doubleValue() );
  58.161 +        assertEquals( CZK, a1.getCurrency() );
  58.162 +
  58.163 +        // convert $8 to CZK
  58.164 +        final Convertor.ConversionResult r2 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 8, USD ), CZK ) );
  58.165 +        final MonetaryAmount a2 = r2.getNetAmount();
  58.166 +        // assertEquals("Result is 136 CZK");
  58.167 +        assertNotNull( a2 );
  58.168 +        assertEquals( 136.0, a2.getAmount().doubleValue() );
  58.169 +        assertEquals( CZK, a2.getCurrency() );
  58.170 +
  58.171 +        // convert 1003CZK to USD
  58.172 +        final Convertor.ConversionResult r3 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 1003, CZK ), USD ) );
  58.173 +        final MonetaryAmount a3 = r3.getNetAmount();
  58.174 +        // assertEquals("Result is 59 USD");
  58.175 +        assertNotNull( a3 );
  58.176 +        assertEquals( 59.0, a3.getAmount().doubleValue() );
  58.177 +        assertEquals( USD, a3.getCurrency() );
  58.178 +
  58.179 +        // convert 16CZK using c:
  58.180 +        final Convertor.ConversionResult r4 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 16, CZK ), SKK ) );
  58.181 +        final MonetaryAmount a4 = r4.getNetAmount();
  58.182 +        // assertEquals("Result is 20 SKK");
  58.183 +        assertNotNull( a4 );
  58.184 +        assertEquals( 20.0, a4.getAmount().doubleValue() );
  58.185 +        assertEquals( SKK, a4.getCurrency() );
  58.186 +
  58.187 +        // convert 500SKK to CZK using c:
  58.188 +        final Convertor.ConversionResult r5 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 500, SKK ), CZK ) );
  58.189 +        final MonetaryAmount a5 = r5.getNetAmount();
  58.190 +        // assertEquals("Result is 400 CZK");
  58.191 +        assertNotNull( a5 );
  58.192 +        assertEquals( 400.0, a5.getAmount().doubleValue() );
  58.193 +        assertEquals( CZK, a5.getCurrency() );
  58.194 +    }
  58.195 +}
    59.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    59.2 +++ b/task3/solution11/build.xml	Tue Oct 07 11:05:34 2008 +0200
    59.3 @@ -0,0 +1,69 @@
    59.4 +<?xml version="1.0" encoding="UTF-8"?>
    59.5 +<!-- You may freely edit this file. See commented blocks below for -->
    59.6 +<!-- some examples of how to customize the build. -->
    59.7 +<!-- (If you delete it and reopen the project it will be recreated.) -->
    59.8 +<project name="currency" default="default" basedir=".">
    59.9 +    <description>Builds, tests, and runs the project.</description>
   59.10 +    <import file="nbproject/build-impl.xml"/>
   59.11 +    <!--
   59.12 +
   59.13 +    There exist several targets which are by default empty and which can be 
   59.14 +    used for execution of your tasks. These targets are usually executed 
   59.15 +    before and after some main targets. They are: 
   59.16 +
   59.17 +      -pre-init:                 called before initialization of project properties
   59.18 +      -post-init:                called after initialization of project properties
   59.19 +      -pre-compile:              called before javac compilation
   59.20 +      -post-compile:             called after javac compilation
   59.21 +      -pre-compile-single:       called before javac compilation of single file
   59.22 +      -post-compile-single:      called after javac compilation of single file
   59.23 +      -pre-compile-test:         called before javac compilation of JUnit tests
   59.24 +      -post-compile-test:        called after javac compilation of JUnit tests
   59.25 +      -pre-compile-test-single:  called before javac compilation of single JUnit test
   59.26 +      -post-compile-test-single: called after javac compilation of single JUunit test
   59.27 +      -pre-jar:                  called before JAR building
   59.28 +      -post-jar:                 called after JAR building
   59.29 +      -post-clean:               called after cleaning build products
   59.30 +
   59.31 +    (Targets beginning with '-' are not intended to be called on their own.)
   59.32 +
   59.33 +    Example of inserting an obfuscator after compilation could look like this:
   59.34 +
   59.35 +        <target name="-post-compile">
   59.36 +            <obfuscate>
   59.37 +                <fileset dir="${build.classes.dir}"/>
   59.38 +            </obfuscate>
   59.39 +        </target>
   59.40 +
   59.41 +    For list of available properties check the imported 
   59.42 +    nbproject/build-impl.xml file. 
   59.43 +
   59.44 +
   59.45 +    Another way to customize the build is by overriding existing main targets.
   59.46 +    The targets of interest are: 
   59.47 +
   59.48 +      -init-macrodef-javac:     defines macro for javac compilation
   59.49 +      -init-macrodef-junit:     defines macro for junit execution
   59.50 +      -init-macrodef-debug:     defines macro for class debugging
   59.51 +      -init-macrodef-java:      defines macro for class execution
   59.52 +      -do-jar-with-manifest:    JAR building (if you are using a manifest)
   59.53 +      -do-jar-without-manifest: JAR building (if you are not using a manifest)
   59.54 +      run:                      execution of project 
   59.55 +      -javadoc-build:           Javadoc generation
   59.56 +      test-report:              JUnit report generation
   59.57 +
   59.58 +    An example of overriding the target for project execution could look like this:
   59.59 +
   59.60 +        <target name="run" depends="currency-impl.jar">
   59.61 +            <exec dir="bin" executable="launcher.exe">
   59.62 +                <arg file="${dist.jar}"/>
   59.63 +            </exec>
   59.64 +        </target>
   59.65 +
   59.66 +    Notice that the overridden target depends on the jar target and not only on 
   59.67 +    the compile target as the regular run target does. Again, for a list of available 
   59.68 +    properties which you can use, check the target you are overriding in the
   59.69 +    nbproject/build-impl.xml file. 
   59.70 +
   59.71 +    -->
   59.72 +</project>
    60.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    60.2 +++ b/task3/solution11/nbproject/build-impl.xml	Tue Oct 07 11:05:34 2008 +0200
    60.3 @@ -0,0 +1,629 @@
    60.4 +<?xml version="1.0" encoding="UTF-8"?>
    60.5 +<!--
    60.6 +*** GENERATED FROM project.xml - DO NOT EDIT  ***
    60.7 +***         EDIT ../build.xml INSTEAD         ***
    60.8 +
    60.9 +For the purpose of easier reading the script
   60.10 +is divided into following sections:
   60.11 +
   60.12 +  - initialization
   60.13 +  - compilation
   60.14 +  - jar
   60.15 +  - execution
   60.16 +  - debugging
   60.17 +  - javadoc
   60.18 +  - junit compilation
   60.19 +  - junit execution
   60.20 +  - junit debugging
   60.21 +  - applet
   60.22 +  - cleanup
   60.23 +
   60.24 +        -->
   60.25 +<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="Currency_Convertor_Solution_11-impl">
   60.26 +    <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
   60.27 +    <!-- 
   60.28 +                ======================
   60.29 +                INITIALIZATION SECTION 
   60.30 +                ======================
   60.31 +            -->
   60.32 +    <target name="-pre-init">
   60.33 +        <!-- Empty placeholder for easier customization. -->
   60.34 +        <!-- You can override this target in the ../build.xml file. -->
   60.35 +    </target>
   60.36 +    <target depends="-pre-init" name="-init-private">
   60.37 +        <property file="nbproject/private/config.properties"/>
   60.38 +        <property file="nbproject/private/configs/${config}.properties"/>
   60.39 +        <property file="nbproject/private/private.properties"/>
   60.40 +    </target>
   60.41 +    <target depends="-pre-init,-init-private" name="-init-user">
   60.42 +        <property file="${user.properties.file}"/>
   60.43 +        <!-- The two properties below are usually overridden -->
   60.44 +        <!-- by the active platform. Just a fallback. -->
   60.45 +        <property name="default.javac.source" value="1.4"/>
   60.46 +        <property name="default.javac.target" value="1.4"/>
   60.47 +    </target>
   60.48 +    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
   60.49 +        <property file="nbproject/configs/${config}.properties"/>
   60.50 +        <property file="nbproject/project.properties"/>
   60.51 +    </target>
   60.52 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
   60.53 +        <available file="${manifest.file}" property="manifest.available"/>
   60.54 +        <condition property="manifest.available+main.class">
   60.55 +            <and>
   60.56 +                <isset property="manifest.available"/>
   60.57 +                <isset property="main.class"/>
   60.58 +                <not>
   60.59 +                    <equals arg1="${main.class}" arg2="" trim="true"/>
   60.60 +                </not>
   60.61 +            </and>
   60.62 +        </condition>
   60.63 +        <condition property="manifest.available+main.class+mkdist.available">
   60.64 +            <and>
   60.65 +                <istrue value="${manifest.available+main.class}"/>
   60.66 +                <isset property="libs.CopyLibs.classpath"/>
   60.67 +            </and>
   60.68 +        </condition>
   60.69 +        <condition property="have.tests">
   60.70 +            <or>
   60.71 +                <available file="${test.src.dir}"/>
   60.72 +            </or>
   60.73 +        </condition>
   60.74 +        <condition property="have.sources">
   60.75 +            <or>
   60.76 +                <available file="${src.dir}"/>
   60.77 +            </or>
   60.78 +        </condition>
   60.79 +        <condition property="netbeans.home+have.tests">
   60.80 +            <and>
   60.81 +                <isset property="netbeans.home"/>
   60.82 +                <isset property="have.tests"/>
   60.83 +            </and>
   60.84 +        </condition>
   60.85 +        <condition property="no.javadoc.preview">
   60.86 +            <and>
   60.87 +                <isset property="javadoc.preview"/>
   60.88 +                <isfalse value="${javadoc.preview}"/>
   60.89 +            </and>
   60.90 +        </condition>
   60.91 +        <property name="run.jvmargs" value=""/>
   60.92 +        <property name="javac.compilerargs" value=""/>
   60.93 +        <property name="work.dir" value="${basedir}"/>
   60.94 +        <condition property="no.deps">
   60.95 +            <and>
   60.96 +                <istrue value="${no.dependencies}"/>
   60.97 +            </and>
   60.98 +        </condition>
   60.99 +        <property name="javac.debug" value="true"/>
  60.100 +        <property name="javadoc.preview" value="true"/>
  60.101 +        <property name="application.args" value=""/>
  60.102 +        <property name="source.encoding" value="${file.encoding}"/>
  60.103 +        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
  60.104 +            <and>
  60.105 +                <isset property="javadoc.encoding"/>
  60.106 +                <not>
  60.107 +                    <equals arg1="${javadoc.encoding}" arg2=""/>
  60.108 +                </not>
  60.109 +            </and>
  60.110 +        </condition>
  60.111 +        <property name="javadoc.encoding.used" value="${source.encoding}"/>
  60.112 +        <property name="includes" value="**"/>
  60.113 +        <property name="excludes" value=""/>
  60.114 +        <property name="do.depend" value="false"/>
  60.115 +        <condition property="do.depend.true">
  60.116 +            <istrue value="${do.depend}"/>
  60.117 +        </condition>
  60.118 +        <condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
  60.119 +            <and>
  60.120 +                <isset property="jaxws.endorsed.dir"/>
  60.121 +                <available file="nbproject/jaxws-build.xml"/>
  60.122 +            </and>
  60.123 +        </condition>
  60.124 +    </target>
  60.125 +    <target name="-post-init">
  60.126 +        <!-- Empty placeholder for easier customization. -->
  60.127 +        <!-- You can override this target in the ../build.xml file. -->
  60.128 +    </target>
  60.129 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
  60.130 +        <fail unless="src.dir">Must set src.dir</fail>
  60.131 +        <fail unless="test.src.dir">Must set test.src.dir</fail>
  60.132 +        <fail unless="build.dir">Must set build.dir</fail>
  60.133 +        <fail unless="dist.dir">Must set dist.dir</fail>
  60.134 +        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
  60.135 +        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
  60.136 +        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
  60.137 +        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
  60.138 +        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
  60.139 +        <fail unless="dist.jar">Must set dist.jar</fail>
  60.140 +    </target>
  60.141 +    <target name="-init-macrodef-property">
  60.142 +        <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
  60.143 +            <attribute name="name"/>
  60.144 +            <attribute name="value"/>
  60.145 +            <sequential>
  60.146 +                <property name="@{name}" value="${@{value}}"/>
  60.147 +            </sequential>
  60.148 +        </macrodef>
  60.149 +    </target>
  60.150 +    <target name="-init-macrodef-javac">
  60.151 +        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
  60.152 +            <attribute default="${src.dir}" name="srcdir"/>
  60.153 +            <attribute default="${build.classes.dir}" name="destdir"/>
  60.154 +            <attribute default="${javac.classpath}" name="classpath"/>
  60.155 +            <attribute default="${includes}" name="includes"/>
  60.156 +            <attribute default="${excludes}" name="excludes"/>
  60.157 +            <attribute default="${javac.debug}" name="debug"/>
  60.158 +            <attribute default="" name="sourcepath"/>
  60.159 +            <element name="customize" optional="true"/>
  60.160 +            <sequential>
  60.161 +                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
  60.162 +                    <classpath>
  60.163 +                        <path path="@{classpath}"/>
  60.164 +                    </classpath>
  60.165 +                    <compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
  60.166 +                    <customize/>
  60.167 +                </javac>
  60.168 +            </sequential>
  60.169 +        </macrodef>
  60.170 +        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
  60.171 +            <attribute default="${src.dir}" name="srcdir"/>
  60.172 +            <attribute default="${build.classes.dir}" name="destdir"/>
  60.173 +            <attribute default="${javac.classpath}" name="classpath"/>
  60.174 +            <sequential>
  60.175 +                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
  60.176 +                    <classpath>
  60.177 +                        <path path="@{classpath}"/>
  60.178 +                    </classpath>
  60.179 +                </depend>
  60.180 +            </sequential>
  60.181 +        </macrodef>
  60.182 +        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
  60.183 +            <attribute default="${build.classes.dir}" name="destdir"/>
  60.184 +            <sequential>
  60.185 +                <fail unless="javac.includes">Must set javac.includes</fail>
  60.186 +                <pathconvert pathsep="," property="javac.includes.binary">
  60.187 +                    <path>
  60.188 +                        <filelist dir="@{destdir}" files="${javac.includes}"/>
  60.189 +                    </path>
  60.190 +                    <globmapper from="*.java" to="*.class"/>
  60.191 +                </pathconvert>
  60.192 +                <delete>
  60.193 +                    <files includes="${javac.includes.binary}"/>
  60.194 +                </delete>
  60.195 +            </sequential>
  60.196 +        </macrodef>
  60.197 +    </target>
  60.198 +    <target name="-init-macrodef-junit">
  60.199 +        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
  60.200 +            <attribute default="${includes}" name="includes"/>
  60.201 +            <attribute default="${excludes}" name="excludes"/>
  60.202 +            <attribute default="**" name="testincludes"/>
  60.203 +            <sequential>
  60.204 +                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
  60.205 +                    <batchtest todir="${build.test.results.dir}">
  60.206 +                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
  60.207 +                            <filename name="@{testincludes}"/>
  60.208 +                        </fileset>
  60.209 +                    </batchtest>
  60.210 +                    <classpath>
  60.211 +                        <path path="${run.test.classpath}"/>
  60.212 +                    </classpath>
  60.213 +                    <syspropertyset>
  60.214 +                        <propertyref prefix="test-sys-prop."/>
  60.215 +                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
  60.216 +                    </syspropertyset>
  60.217 +                    <formatter type="brief" usefile="false"/>
  60.218 +                    <formatter type="xml"/>
  60.219 +                    <jvmarg line="${run.jvmargs}"/>
  60.220 +                </junit>
  60.221 +            </sequential>
  60.222 +        </macrodef>
  60.223 +    </target>
  60.224 +    <target name="-init-macrodef-nbjpda">
  60.225 +        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
  60.226 +            <attribute default="${main.class}" name="name"/>
  60.227 +            <attribute default="${debug.classpath}" name="classpath"/>
  60.228 +            <attribute default="" name="stopclassname"/>
  60.229 +            <sequential>
  60.230 +                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="dt_socket">
  60.231 +                    <classpath>
  60.232 +                        <path path="@{classpath}"/>
  60.233 +                    </classpath>
  60.234 +                </nbjpdastart>
  60.235 +            </sequential>
  60.236 +        </macrodef>
  60.237 +        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
  60.238 +            <attribute default="${build.classes.dir}" name="dir"/>
  60.239 +            <sequential>
  60.240 +                <nbjpdareload>
  60.241 +                    <fileset dir="@{dir}" includes="${fix.classes}">
  60.242 +                        <include name="${fix.includes}*.class"/>
  60.243 +                    </fileset>
  60.244 +                </nbjpdareload>
  60.245 +            </sequential>
  60.246 +        </macrodef>
  60.247 +    </target>
  60.248 +    <target name="-init-debug-args">
  60.249 +        <property name="version-output" value="java version &quot;${ant.java.version}"/>
  60.250 +        <condition property="have-jdk-older-than-1.4">
  60.251 +            <or>
  60.252 +                <contains string="${version-output}" substring="java version &quot;1.0"/>
  60.253 +                <contains string="${version-output}" substring="java version &quot;1.1"/>
  60.254 +                <contains string="${version-output}" substring="java version &quot;1.2"/>
  60.255 +                <contains string="${version-output}" substring="java version &quot;1.3"/>
  60.256 +            </or>
  60.257 +        </condition>
  60.258 +        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
  60.259 +            <istrue value="${have-jdk-older-than-1.4}"/>
  60.260 +        </condition>
  60.261 +    </target>
  60.262 +    <target depends="-init-debug-args" name="-init-macrodef-debug">
  60.263 +        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
  60.264 +            <attribute default="${main.class}" name="classname"/>
  60.265 +            <attribute default="${debug.classpath}" name="classpath"/>
  60.266 +            <element name="customize" optional="true"/>
  60.267 +            <sequential>
  60.268 +                <java classname="@{classname}" dir="${work.dir}" fork="true">
  60.269 +                    <jvmarg line="${debug-args-line}"/>
  60.270 +                    <jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/>
  60.271 +                    <jvmarg line="${run.jvmargs}"/>
  60.272 +                    <classpath>
  60.273 +                        <path path="@{classpath}"/>
  60.274 +                    </classpath>
  60.275 +                    <syspropertyset>
  60.276 +                        <propertyref prefix="run-sys-prop."/>
  60.277 +                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
  60.278 +                    </syspropertyset>
  60.279 +                    <customize/>
  60.280 +                </java>
  60.281 +            </sequential>
  60.282 +        </macrodef>
  60.283 +    </target>
  60.284 +    <target name="-init-macrodef-java">
  60.285 +        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
  60.286 +            <attribute default="${main.class}" name="classname"/>
  60.287 +            <element name="customize" optional="true"/>
  60.288 +            <sequential>
  60.289 +                <java classname="@{classname}" dir="${work.dir}" fork="true">
  60.290 +                    <jvmarg line="${run.jvmargs}"/>
  60.291 +                    <classpath>
  60.292 +                        <path path="${run.classpath}"/>
  60.293 +                    </classpath>
  60.294 +                    <syspropertyset>
  60.295 +                        <propertyref prefix="run-sys-prop."/>
  60.296 +                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
  60.297 +                    </syspropertyset>
  60.298 +                    <customize/>
  60.299 +                </java>
  60.300 +            </sequential>
  60.301 +        </macrodef>
  60.302 +    </target>
  60.303 +    <target name="-init-presetdef-jar">
  60.304 +        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
  60.305 +            <jar compress="${jar.compress}" jarfile="${dist.jar}">
  60.306 +                <j2seproject1:fileset dir="${build.classes.dir}"/>
  60.307 +            </jar>
  60.308 +        </presetdef>
  60.309 +    </target>
  60.310 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar" name="init"/>
  60.311 +    <!--
  60.312 +                ===================
  60.313 +                COMPILATION SECTION
  60.314 +                ===================
  60.315 +            -->
  60.316 +    <target depends="init" name="deps-jar" unless="no.deps"/>
  60.317 +    <target depends="init,deps-jar" name="-pre-pre-compile">
  60.318 +        <mkdir dir="${build.classes.dir}"/>
  60.319 +    </target>
  60.320 +    <target name="-pre-compile">
  60.321 +        <!-- Empty placeholder for easier customization. -->
  60.322 +        <!-- You can override this target in the ../build.xml file. -->
  60.323 +    </target>
  60.324 +    <target if="do.depend.true" name="-compile-depend">
  60.325 +        <j2seproject3:depend/>
  60.326 +    </target>
  60.327 +    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
  60.328 +        <j2seproject3:javac/>
  60.329 +        <copy todir="${build.classes.dir}">
  60.330 +            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  60.331 +        </copy>
  60.332 +    </target>
  60.333 +    <target name="-post-compile">
  60.334 +        <!-- Empty placeholder for easier customization. -->
  60.335 +        <!-- You can override this target in the ../build.xml file. -->
  60.336 +    </target>
  60.337 +    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
  60.338 +    <target name="-pre-compile-single">
  60.339 +        <!-- Empty placeholder for easier customization. -->
  60.340 +        <!-- You can override this target in the ../build.xml file. -->
  60.341 +    </target>
  60.342 +    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
  60.343 +        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
  60.344 +        <j2seproject3:force-recompile/>
  60.345 +        <j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
  60.346 +    </target>
  60.347 +    <target name="-post-compile-single">
  60.348 +        <!-- Empty placeholder for easier customization. -->
  60.349 +        <!-- You can override this target in the ../build.xml file. -->
  60.350 +    </target>
  60.351 +    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
  60.352 +    <!--
  60.353 +                ====================
  60.354 +                JAR BUILDING SECTION
  60.355 +                ====================
  60.356 +            -->
  60.357 +    <target depends="init" name="-pre-pre-jar">
  60.358 +        <dirname file="${dist.jar}" property="dist.jar.dir"/>
  60.359 +        <mkdir dir="${dist.jar.dir}"/>
  60.360 +    </target>
  60.361 +    <target name="-pre-jar">
  60.362 +        <!-- Empty placeholder for easier customization. -->
  60.363 +        <!-- You can override this target in the ../build.xml file. -->
  60.364 +    </target>
  60.365 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
  60.366 +        <j2seproject1:jar/>
  60.367 +    </target>
  60.368 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
  60.369 +        <j2seproject1:jar manifest="${manifest.file}"/>
  60.370 +    </target>
  60.371 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
  60.372 +        <j2seproject1:jar manifest="${manifest.file}">
  60.373 +            <j2seproject1:manifest>
  60.374 +                <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
  60.375 +            </j2seproject1:manifest>
  60.376 +        </j2seproject1:jar>
  60.377 +        <echo>To run this application from the command line without Ant, try:</echo>
  60.378 +        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
  60.379 +        <property location="${dist.jar}" name="dist.jar.resolved"/>
  60.380 +        <pathconvert property="run.classpath.with.dist.jar">
  60.381 +            <path path="${run.classpath}"/>
  60.382 +            <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
  60.383 +        </pathconvert>
  60.384 +        <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
  60.385 +    </target>
  60.386 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
  60.387 +        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
  60.388 +        <pathconvert property="run.classpath.without.build.classes.dir">
  60.389 +            <path path="${run.classpath}"/>
  60.390 +            <map from="${build.classes.dir.resolved}" to=""/>
  60.391 +        </pathconvert>
  60.392 +        <pathconvert pathsep=" " property="jar.classpath">
  60.393 +            <path path="${run.classpath.without.build.classes.dir}"/>
  60.394 +            <chainedmapper>
  60.395 +                <flattenmapper/>
  60.396 +                <globmapper from="*" to="lib/*"/>
  60.397 +            </chainedmapper>
  60.398 +        </pathconvert>
  60.399 +        <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
  60.400 +        <copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
  60.401 +            <fileset dir="${build.classes.dir}"/>
  60.402 +            <manifest>
  60.403 +                <attribute name="Main-Class" value="${main.class}"/>
  60.404 +                <attribute name="Class-Path" value="${jar.classpath}"/>
  60.405 +            </manifest>
  60.406 +        </copylibs>
  60.407 +        <echo>To run this application from the command line without Ant, try:</echo>
  60.408 +        <property location="${dist.jar}" name="dist.jar.resolved"/>
  60.409 +        <echo>java -jar "${dist.jar.resolved}"</echo>
  60.410 +    </target>
  60.411 +    <target name="-post-jar">
  60.412 +        <!-- Empty placeholder for easier customization. -->
  60.413 +        <!-- You can override this target in the ../build.xml file. -->
  60.414 +    </target>
  60.415 +    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
  60.416 +    <!--
  60.417 +                =================
  60.418 +                EXECUTION SECTION
  60.419 +                =================
  60.420 +            -->
  60.421 +    <target depends="init,compile" description="Run a main class." name="run">
  60.422 +        <j2seproject1:java>
  60.423 +            <customize>
  60.424 +                <arg line="${application.args}"/>
  60.425 +            </customize>
  60.426 +        </j2seproject1:java>
  60.427 +    </target>
  60.428 +    <target name="-do-not-recompile">
  60.429 +        <property name="javac.includes.binary" value=""/>
  60.430 +    </target>
  60.431 +    <target depends="init,-do-not-recompile,compile-single" name="run-single">
  60.432 +        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
  60.433 +        <j2seproject1:java classname="${run.class}"/>
  60.434 +    </target>
  60.435 +    <!--
  60.436 +                =================
  60.437 +                DEBUGGING SECTION
  60.438 +                =================
  60.439 +            -->
  60.440 +    <target depends="init" if="netbeans.home" name="-debug-start-debugger">
  60.441 +        <j2seproject1:nbjpdastart name="${debug.class}"/>
  60.442 +    </target>
  60.443 +    <target depends="init,compile" name="-debug-start-debuggee">
  60.444 +        <j2seproject3:debug>
  60.445 +            <customize>
  60.446 +                <arg line="${application.args}"/>
  60.447 +            </customize>
  60.448 +        </j2seproject3:debug>
  60.449 +    </target>
  60.450 +    <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
  60.451 +    <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
  60.452 +        <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
  60.453 +    </target>
  60.454 +    <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
  60.455 +    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
  60.456 +        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
  60.457 +        <j2seproject3:debug classname="${debug.class}"/>
  60.458 +    </target>
  60.459 +    <target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
  60.460 +    <target depends="init" name="-pre-debug-fix">
  60.461 +        <fail unless="fix.includes">Must set fix.includes</fail>
  60.462 +        <property name="javac.includes" value="${fix.includes}.java"/>
  60.463 +    </target>
  60.464 +    <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
  60.465 +        <j2seproject1:nbjpdareload/>
  60.466 +    </target>
  60.467 +    <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
  60.468 +    <!--
  60.469 +                ===============
  60.470 +                JAVADOC SECTION
  60.471 +                ===============
  60.472 +            -->
  60.473 +    <target depends="init" name="-javadoc-build">
  60.474 +        <mkdir dir="${dist.javadoc.dir}"/>
  60.475 +        <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
  60.476 +            <classpath>
  60.477 +                <path path="${javac.classpath}"/>
  60.478 +            </classpath>
  60.479 +            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
  60.480 +                <filename name="**/*.java"/>
  60.481 +            </fileset>
  60.482 +        </javadoc>
  60.483 +    </target>
  60.484 +    <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
  60.485 +        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
  60.486 +    </target>
  60.487 +    <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
  60.488 +    <!--
  60.489 +                =========================
  60.490 +                JUNIT COMPILATION SECTION
  60.491 +                =========================
  60.492 +            -->
  60.493 +    <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
  60.494 +        <mkdir dir="${build.test.classes.dir}"/>
  60.495 +    </target>
  60.496 +    <target name="-pre-compile-test">
  60.497 +        <!-- Empty placeholder for easier customization. -->
  60.498 +        <!-- You can override this target in the ../build.xml file. -->
  60.499 +    </target>
  60.500 +    <target if="do.depend.true" name="-compile-test-depend">
  60.501 +        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
  60.502 +    </target>
  60.503 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
  60.504 +        <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
  60.505 +        <copy todir="${build.test.classes.dir}">
  60.506 +            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  60.507 +        </copy>
  60.508 +    </target>
  60.509 +    <target name="-post-compile-test">
  60.510 +        <!-- Empty placeholder for easier customization. -->
  60.511 +        <!-- You can override this target in the ../build.xml file. -->
  60.512 +    </target>
  60.513 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
  60.514 +    <target name="-pre-compile-test-single">
  60.515 +        <!-- Empty placeholder for easier customization. -->
  60.516 +        <!-- You can override this target in the ../build.xml file. -->
  60.517 +    </target>
  60.518 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
  60.519 +        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
  60.520 +        <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
  60.521 +        <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
  60.522 +        <copy todir="${build.test.classes.dir}">
  60.523 +            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  60.524 +        </copy>
  60.525 +    </target>
  60.526 +    <target name="-post-compile-test-single">
  60.527 +        <!-- Empty placeholder for easier customization. -->
  60.528 +        <!-- You can override this target in the ../build.xml file. -->
  60.529 +    </target>
  60.530 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
  60.531 +    <!--
  60.532 +                =======================
  60.533 +                JUNIT EXECUTION SECTION
  60.534 +                =======================
  60.535 +            -->
  60.536 +    <target depends="init" if="have.tests" name="-pre-test-run">
  60.537 +        <mkdir dir="${build.test.results.dir}"/>
  60.538 +    </target>
  60.539 +    <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
  60.540 +        <j2seproject3:junit testincludes="**/*Test.java"/>
  60.541 +    </target>
  60.542 +    <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
  60.543 +        <fail if="tests.failed">Some tests failed; see details above.</fail>
  60.544 +    </target>
  60.545 +    <target depends="init" if="have.tests" name="test-report"/>
  60.546 +    <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
  60.547 +    <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
  60.548 +    <target depends="init" if="have.tests" name="-pre-test-run-single">
  60.549 +        <mkdir dir="${build.test.results.dir}"/>
  60.550 +    </target>
  60.551 +    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
  60.552 +        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
  60.553 +        <j2seproject3:junit excludes="" includes="${test.includes}"/>
  60.554 +    </target>
  60.555 +    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
  60.556 +        <fail if="tests.failed">Some tests failed; see details above.</fail>
  60.557 +    </target>
  60.558 +    <target depends="init,-do-not-recompile,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
  60.559 +    <!--
  60.560 +                =======================
  60.561 +                JUNIT DEBUGGING SECTION
  60.562 +                =======================
  60.563 +            -->
  60.564 +    <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
  60.565 +        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
  60.566 +        <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
  60.567 +        <delete file="${test.report.file}"/>
  60.568 +        <mkdir dir="${build.test.results.dir}"/>
  60.569 +        <j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
  60.570 +            <customize>
  60.571 +                <syspropertyset>
  60.572 +                    <propertyref prefix="test-sys-prop."/>
  60.573 +                    <mapper from="test-sys-prop.*" to="*" type="glob"/>
  60.574 +                </syspropertyset>
  60.575 +                <arg value="${test.class}"/>
  60.576 +                <arg value="showoutput=true"/>
  60.577 +                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
  60.578 +                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
  60.579 +            </customize>
  60.580 +        </j2seproject3:debug>
  60.581 +    </target>
  60.582 +    <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
  60.583 +        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
  60.584 +    </target>
  60.585 +    <target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
  60.586 +    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
  60.587 +        <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
  60.588 +    </target>
  60.589 +    <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
  60.590 +    <!--
  60.591 +                =========================
  60.592 +                APPLET EXECUTION SECTION
  60.593 +                =========================
  60.594 +            -->
  60.595 +    <target depends="init,compile-single" name="run-applet">
  60.596 +        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
  60.597 +        <j2seproject1:java classname="sun.applet.AppletViewer">
  60.598 +            <customize>
  60.599 +                <arg value="${applet.url}"/>
  60.600 +            </customize>
  60.601 +        </j2seproject1:java>
  60.602 +    </target>
  60.603 +    <!--
  60.604 +                =========================
  60.605 +                APPLET DEBUGGING  SECTION
  60.606 +                =========================
  60.607 +            -->
  60.608 +    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
  60.609 +        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
  60.610 +        <j2seproject3:debug classname="sun.applet.AppletViewer">
  60.611 +            <customize>
  60.612 +                <arg value="${applet.url}"/>
  60.613 +            </customize>
  60.614 +        </j2seproject3:debug>
  60.615 +    </target>
  60.616 +    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
  60.617 +    <!--
  60.618 +                ===============
  60.619 +                CLEANUP SECTION
  60.620 +                ===============
  60.621 +            -->
  60.622 +    <target depends="init" name="deps-clean" unless="no.deps"/>
  60.623 +    <target depends="init" name="-do-clean">
  60.624 +        <delete dir="${build.dir}"/>
  60.625 +        <delete dir="${dist.dir}"/>
  60.626 +    </target>
  60.627 +    <target name="-post-clean">
  60.628 +        <!-- Empty placeholder for easier customization. -->
  60.629 +        <!-- You can override this target in the ../build.xml file. -->
  60.630 +    </target>
  60.631 +    <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
  60.632 +</project>
    61.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    61.2 +++ b/task3/solution11/nbproject/genfiles.properties	Tue Oct 07 11:05:34 2008 +0200
    61.3 @@ -0,0 +1,8 @@
    61.4 +build.xml.data.CRC32=2ab820eb
    61.5 +build.xml.script.CRC32=58a52595
    61.6 +build.xml.stylesheet.CRC32=be360661
    61.7 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
    61.8 +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
    61.9 +nbproject/build-impl.xml.data.CRC32=0e1e702f
   61.10 +nbproject/build-impl.xml.script.CRC32=c899f2cf
   61.11 +nbproject/build-impl.xml.stylesheet.CRC32=487672f9
    62.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    62.2 +++ b/task3/solution11/nbproject/project.properties	Tue Oct 07 11:05:34 2008 +0200
    62.3 @@ -0,0 +1,68 @@
    62.4 +application.title=currency
    62.5 +application.vendor=apidesign.org
    62.6 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
    62.7 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
    62.8 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=default
    62.9 +build.classes.dir=${build.dir}/classes
   62.10 +build.classes.excludes=**/*.java,**/*.form
   62.11 +# This directory is removed when the project is cleaned:
   62.12 +build.dir=build
   62.13 +build.generated.dir=${build.dir}/generated
   62.14 +# Only compile against the classpath explicitly listed here:
   62.15 +build.sysclasspath=ignore
   62.16 +build.test.classes.dir=${build.dir}/test/classes
   62.17 +build.test.results.dir=${build.dir}/test/results
   62.18 +debug.classpath=\
   62.19 +    ${run.classpath}
   62.20 +debug.test.classpath=\
   62.21 +    ${run.test.classpath}
   62.22 +# This directory is removed when the project is cleaned:
   62.23 +dist.dir=dist
   62.24 +dist.jar=${dist.dir}/currency.jar
   62.25 +dist.javadoc.dir=${dist.dir}/javadoc
   62.26 +excludes=
   62.27 +file.reference.junit-4.4.jar=../../libs/junit-4.4.jar
   62.28 +file.reference.src-apifest08=..
   62.29 +includes=**
   62.30 +jar.compress=false
   62.31 +javac.classpath=
   62.32 +# Space-separated list of extra javac options
   62.33 +javac.compilerargs=-Xlint:unchecked
   62.34 +javac.deprecation=false
   62.35 +javac.source=1.5
   62.36 +javac.target=1.5
   62.37 +javac.test.classpath=\
   62.38 +    ${javac.classpath}:\
   62.39 +    ${build.classes.dir}:\
   62.40 +    ${file.reference.junit-4.4.jar}
   62.41 +javadoc.additionalparam=
   62.42 +javadoc.author=false
   62.43 +javadoc.encoding=
   62.44 +javadoc.noindex=false
   62.45 +javadoc.nonavbar=false
   62.46 +javadoc.notree=false
   62.47 +javadoc.private=false
   62.48 +javadoc.splitindex=true
   62.49 +javadoc.use=true
   62.50 +javadoc.version=false
   62.51 +javadoc.windowtitle=
   62.52 +jnlp.codebase.type=local
   62.53 +jnlp.codebase.url=file:/home/jarda/src/apifest08/currency/dist
   62.54 +jnlp.descriptor=application
   62.55 +jnlp.enabled=false
   62.56 +jnlp.offline-allowed=false
   62.57 +jnlp.signed=false
   62.58 +meta.inf.dir=${src.dir}/META-INF
   62.59 +platform.active=default_platform
   62.60 +run.classpath=\
   62.61 +    ${javac.classpath}:\
   62.62 +    ${build.classes.dir}
   62.63 +# Space-separated list of JVM arguments used when running the project
   62.64 +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
   62.65 +# or test-sys-prop.name=value to set system properties for unit tests):
   62.66 +run.jvmargs=
   62.67 +run.test.classpath=\
   62.68 +    ${javac.test.classpath}:\
   62.69 +    ${build.test.classes.dir}
   62.70 +src.dir=src
   62.71 +test.src.dir=test
    63.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    63.2 +++ b/task3/solution11/nbproject/project.xml	Tue Oct 07 11:05:34 2008 +0200
    63.3 @@ -0,0 +1,16 @@
    63.4 +<?xml version="1.0" encoding="UTF-8"?>
    63.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
    63.6 +    <type>org.netbeans.modules.java.j2seproject</type>
    63.7 +    <configuration>
    63.8 +        <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
    63.9 +            <name>Currency Convertor Solution 11</name>
   63.10 +            <minimum-ant-version>1.6.5</minimum-ant-version>
   63.11 +            <source-roots>
   63.12 +                <root id="src.dir"/>
   63.13 +            </source-roots>
   63.14 +            <test-roots>
   63.15 +                <root id="test.src.dir"/>
   63.16 +            </test-roots>
   63.17 +        </data>
   63.18 +    </configuration>
   63.19 +</project>
    64.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    64.2 +++ b/task3/solution11/src/org/apidesign/apifest08/currency/Computer.java	Tue Oct 07 11:05:34 2008 +0200
    64.3 @@ -0,0 +1,65 @@
    64.4 +package org.apidesign.apifest08.currency;
    64.5 +
    64.6 +/**
    64.7 + * Interface declaring method for computing conversion.
    64.8 + * 
    64.9 + * Because of a vague definition of currency amount's type,
   64.10 + * the interface has a generic type.
   64.11 + * 
   64.12 + * @author ked
   64.13 + * @see http://wiki.apidesign.org/wiki/APIDesignPatterns:ResponseReply
   64.14 + */
   64.15 +interface Computer<AmountType> {
   64.16 +
   64.17 +    ComputerResponse<AmountType> compute(ComputerRequest<AmountType> request);
   64.18 +
   64.19 +    /**
   64.20 +     * 
   64.21 +     * @param <AmountType>
   64.22 +     */
   64.23 +    final class ComputerRequest<AmountType> {
   64.24 +
   64.25 +        private AmountType input;
   64.26 +        private AmountType inputCurrencyRatio;
   64.27 +        private AmountType outputCurrencyRatio;
   64.28 +
   64.29 +        AmountType getInput() {
   64.30 +            return input;
   64.31 +        }
   64.32 +
   64.33 +        void setInput(AmountType input) {
   64.34 +            this.input = input;
   64.35 +        }
   64.36 +
   64.37 +        AmountType getInputCurrencyRatio() {
   64.38 +            return inputCurrencyRatio;
   64.39 +        }
   64.40 +
   64.41 +        void setInputCurrencyRatio(AmountType inputCurrencyRatio) {
   64.42 +            this.inputCurrencyRatio = inputCurrencyRatio;
   64.43 +        }
   64.44 +
   64.45 +        AmountType getOutputCurrencyRatio() {
   64.46 +            return outputCurrencyRatio;
   64.47 +        }
   64.48 +
   64.49 +        void setOutputCurrencyRatio(AmountType outputCurrencyRatio) {
   64.50 +            this.outputCurrencyRatio = outputCurrencyRatio;
   64.51 +        }
   64.52 +    }
   64.53 +
   64.54 +    final class ComputerResponse<AmountType> {
   64.55 +
   64.56 +        private AmountType result;
   64.57 +
   64.58 +        AmountType getResult() {
   64.59 +            return result;
   64.60 +        }
   64.61 +
   64.62 +        void setResult(AmountType result) {
   64.63 +            this.result = result;
   64.64 +        }
   64.65 +    }
   64.66 +    
   64.67 +    
   64.68 +}
   64.69 \ No newline at end of file
    65.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    65.2 +++ b/task3/solution11/src/org/apidesign/apifest08/currency/Convertor.java	Tue Oct 07 11:05:34 2008 +0200
    65.3 @@ -0,0 +1,228 @@
    65.4 +package org.apidesign.apifest08.currency;
    65.5 +
    65.6 +import java.util.ArrayList;
    65.7 +import java.util.Collection;
    65.8 +import java.util.HashSet;
    65.9 +import java.util.List;
   65.10 +import java.util.Set;
   65.11 +import org.apidesign.apifest08.currency.Computer.ComputerRequest;
   65.12 +import org.apidesign.apifest08.currency.Computer.ComputerResponse;
   65.13 +
   65.14 +/**
   65.15 + * Convertor.
   65.16 + * 
   65.17 + * In Task 1's version provides conversion between currency values
   65.18 + * with amount stored in integer or double, that are identified
   65.19 + * with string value. Exchange rates are immutable.
   65.20 + * 
   65.21 + * In Task2's version provides support for multiple exchange rates
   65.22 + * between different currencies & merging exchange rates from
   65.23 + * existing convertors into new convertor's instance.
   65.24 + * No time for javadoc these features, sorry.
   65.25 + * 
   65.26 + * @author ked
   65.27 + */
   65.28 +public final class Convertor<AmountType, IdentifierType> {
   65.29 +
   65.30 +    Computer<AmountType> computer;
   65.31 +    List<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates = new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
   65.32 +
   65.33 +    Convertor(
   65.34 +            Computer<AmountType> computer,
   65.35 +            Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
   65.36 +        this.computer = computer;
   65.37 +
   65.38 +        for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
   65.39 +            if (findExchangeRate(
   65.40 +                    this.exchangeRates,
   65.41 +                    exchangeRate.getCurrencyA().getIdentifier(),
   65.42 +                    exchangeRate.getCurrencyB().getIdentifier()) != null) {
   65.43 +                throw new IllegalArgumentException("Duplicate exchange rate!");
   65.44 +            }
   65.45 +            this.exchangeRates.add(exchangeRate);
   65.46 +        }
   65.47 +    }
   65.48 +
   65.49 +    private ExchangeRateValue<AmountType, IdentifierType> findExchangeRate(
   65.50 +            Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates,
   65.51 +            IdentifierType currencyA,
   65.52 +            IdentifierType currencyB) {
   65.53 +        for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
   65.54 +            if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) ||
   65.55 +                    (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) {
   65.56 +                return exchangeRate;
   65.57 +            }
   65.58 +        }
   65.59 +        return null;
   65.60 +    }
   65.61 +
   65.62 +    /**
   65.63 +     * Convert an amount of the one currency to an amount of the another one currency
   65.64 +     * with respect to previously specified exchange rates.
   65.65 +     * 
   65.66 +     * @param targetCurrency an identifier of the requested currency
   65.67 +     * @param currencyValue an amount of the another one currency
   65.68 +     * @return an amount of the requested currency
   65.69 +     */
   65.70 +    public CurrencyValue<AmountType, IdentifierType> convert(
   65.71 +            IdentifierType targetCurrency,
   65.72 +            CurrencyValue<AmountType, IdentifierType> currencyValue) {
   65.73 +        ExchangeRateValue<AmountType, IdentifierType> exchangeRate =
   65.74 +                findExchangeRate(exchangeRates, currencyValue.getIdentifier(), targetCurrency);
   65.75 +        if (exchangeRate == null) {
   65.76 +            throw new IllegalArgumentException("Inappropriate currencies to convert!");
   65.77 +        }
   65.78 +
   65.79 +        ComputerRequest<AmountType> computerRequest = new ComputerRequest<AmountType>();
   65.80 +        computerRequest.setInput(currencyValue.getAmount());
   65.81 +
   65.82 +        IdentifierType targetCurrencyRef; // just for backward compatibility :-(
   65.83 +        if (exchangeRate.getCurrencyA().getIdentifier().equals(targetCurrency)) {
   65.84 +            computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
   65.85 +            computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
   65.86 +            targetCurrencyRef = exchangeRate.getCurrencyA().getIdentifier();
   65.87 +        } else {
   65.88 +            computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
   65.89 +            computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
   65.90 +            targetCurrencyRef = exchangeRate.getCurrencyB().getIdentifier();
   65.91 +        }
   65.92 +
   65.93 +        ComputerResponse<AmountType> computerResponse = computer.compute(computerRequest);
   65.94 +        return CurrencyValue.getCurrencyValue(
   65.95 +                computerResponse.getResult(),
   65.96 +                targetCurrencyRef);
   65.97 +    }
   65.98 +
   65.99 +    // ---
  65.100 +    // MERGING
  65.101 +    // ---
  65.102 +    static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
  65.103 +            Computer<AmountType> computer,
  65.104 +            Collection<Convertor<AmountType, IdentifierType>> convertors) {
  65.105 +        Set<ExchangeRateValue<AmountType, IdentifierType>> exchangeRatesSet = new HashSet<ExchangeRateValue<AmountType, IdentifierType>>();
  65.106 +        for (Convertor<AmountType, IdentifierType> convertor : convertors) {
  65.107 +            exchangeRatesSet.addAll(convertor.exchangeRates);
  65.108 +        }
  65.109 +        return getConvertor(computer, exchangeRatesSet);
  65.110 +    }
  65.111 +
  65.112 +    static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
  65.113 +            Computer<AmountType> computer,
  65.114 +            Convertor<AmountType, IdentifierType> convertorA,
  65.115 +            Convertor<AmountType, IdentifierType> convertorB) {
  65.116 +        Collection<Convertor<AmountType, IdentifierType>> convertors =
  65.117 +                new ArrayList<Convertor<AmountType, IdentifierType>>();
  65.118 +        convertors.add(convertorA);
  65.119 +        convertors.add(convertorB);
  65.120 +        return mergeConvertors(computer, convertors);
  65.121 +    }
  65.122 +
  65.123 +    public static Convertor<Double, String> mergeConvertorsDoubleString(
  65.124 +            Collection<Convertor<Double, String>> convertors) {
  65.125 +        return mergeConvertors(DoubleComputer, convertors);
  65.126 +    }
  65.127 +
  65.128 +    public static Convertor<Double, String> mergeConvertorsDoubleString(
  65.129 +            Convertor<Double, String> convertorA,
  65.130 +            Convertor<Double, String> convertorB) {
  65.131 +        return mergeConvertors(DoubleComputer, convertorA, convertorB);
  65.132 +    }
  65.133 +
  65.134 +    public static Convertor<Integer, String> mergeConvertorsIntegerString(
  65.135 +            Collection<Convertor<Integer, String>> convertors) {
  65.136 +        return mergeConvertors(IntegerComputer, convertors);
  65.137 +    }
  65.138 +
  65.139 +    public static Convertor<Integer, String> mergeConvertorsIntegerString(
  65.140 +            Convertor<Integer, String> convertorA,
  65.141 +            Convertor<Integer, String> convertorB) {
  65.142 +        return mergeConvertors(IntegerComputer, convertorA, convertorB);
  65.143 +    }
  65.144 +
  65.145 +    // ---
  65.146 +    // CREATION
  65.147 +    // ---
  65.148 +    static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
  65.149 +            Computer<AmountType> computer, Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
  65.150 +        return new Convertor<AmountType, IdentifierType>(computer, exchangeRates);
  65.151 +    }
  65.152 +
  65.153 +    static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
  65.154 +            Computer<AmountType> computer, ExchangeRateValue<AmountType, IdentifierType> exchangeRate) {
  65.155 +        Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates =
  65.156 +                new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
  65.157 +        exchangeRates.add(exchangeRate);
  65.158 +        return getConvertor(computer, exchangeRates);
  65.159 +    }
  65.160 +    
  65.161 +    public static Convertor<Double, String> getConvertorDoubleString(
  65.162 +            Collection<ExchangeRateValue<Double, String>> exchangeRates) {
  65.163 +        return getConvertor(DoubleComputer, exchangeRates);
  65.164 +    }
  65.165 +
  65.166 +    public static Convertor<Double, String> getConvertorDoubleString(
  65.167 +            ExchangeRateValue<Double, String> exchangeRate) {
  65.168 +        return getConvertor(DoubleComputer, exchangeRate);
  65.169 +    }
  65.170 +
  65.171 +    public static Convertor<Integer, String> getConvertorIntegerString(
  65.172 +            Collection<ExchangeRateValue<Integer, String>> exchangeRates) {
  65.173 +        return getConvertor(IntegerComputer, exchangeRates);
  65.174 +    }
  65.175 +
  65.176 +    public static Convertor<Integer, String> getConvertorIntegerString(
  65.177 +            ExchangeRateValue<Integer, String> exchangeRate) {
  65.178 +        return getConvertor(IntegerComputer, exchangeRate);
  65.179 +    }
  65.180 +
  65.181 +    // ---
  65.182 +    // BACKWARD COMPATIBILITY - CREATION
  65.183 +    // ---
  65.184 +    /**
  65.185 +     * Creates convertor for Double|String values with specified exchange rate
  65.186 +     * between two currencies.
  65.187 +     * 
  65.188 +     * @param firstCurrencyExchangeRate first currency
  65.189 +     * @param secondCurrencyExchangeRate second currency
  65.190 +     * @return convertor
  65.191 +     */
  65.192 +    public static Convertor<Double, String> getConvertorDoubleString(
  65.193 +            CurrencyValue<Double, String> firstCurrencyExchangeRate,
  65.194 +            CurrencyValue<Double, String> secondCurrencyExchangeRate) {
  65.195 +        return getConvertorDoubleString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
  65.196 +    }
  65.197 +
  65.198 +    /**
  65.199 +     * Creates convertor for Integer|String values with specified exchange rate
  65.200 +     * between two currencies.
  65.201 +     * 
  65.202 +     * @param firstCurrencyExchangeRate first currency
  65.203 +     * @param secondCurrencyExchangeRate second currency
  65.204 +     * @return convertor
  65.205 +     */
  65.206 +    public static Convertor<Integer, String> getConvertorIntegerString(
  65.207 +            CurrencyValue<Integer, String> firstCurrencyExchangeRate,
  65.208 +            CurrencyValue<Integer, String> secondCurrencyExchangeRate) {
  65.209 +        return getConvertorIntegerString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
  65.210 +    }
  65.211 +    
  65.212 +    // ---
  65.213 +    // COMPUTERS
  65.214 +    // ---
  65.215 +    static final Computer<Double> DoubleComputer = new Computer<Double>() {
  65.216 +
  65.217 +        public ComputerResponse<Double> compute(ComputerRequest<Double> request) {
  65.218 +            ComputerResponse<Double> response = new ComputerResponse<Double>();
  65.219 +            response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());
  65.220 +            return response;
  65.221 +        }
  65.222 +    };
  65.223 +    static final Computer<Integer> IntegerComputer = new Computer<Integer>() {
  65.224 +
  65.225 +        public ComputerResponse<Integer> compute(ComputerRequest<Integer> request) {
  65.226 +            ComputerResponse<Integer> response = new ComputerResponse<Integer>();
  65.227 +            response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());
  65.228 +            return response;
  65.229 +        }
  65.230 +    };
  65.231 +}
    66.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    66.2 +++ b/task3/solution11/src/org/apidesign/apifest08/currency/CurrencyValue.java	Tue Oct 07 11:05:34 2008 +0200
    66.3 @@ -0,0 +1,72 @@
    66.4 +package org.apidesign.apifest08.currency;
    66.5 +
    66.6 +import java.io.Serializable;
    66.7 +
    66.8 +/**
    66.9 + * Value class, holding an amount of the currency & an identifier of the currency.
   66.10 + * Designed to be an immutable.
   66.11 + * 
   66.12 + * Because of a vague definition of types of the both fields,
   66.13 + * the class has generic types, used as types of the fields.
   66.14 + * These types should be immutable classes, too.
   66.15 + * 
   66.16 + * @author ked
   66.17 + */
   66.18 +public final class CurrencyValue<AmountType, IdentifierType> implements Serializable {
   66.19 +
   66.20 +    private final AmountType amount;
   66.21 +    private final IdentifierType identifier;
   66.22 +
   66.23 +    private CurrencyValue(AmountType amount, IdentifierType identifier) {
   66.24 +        this.amount = amount;
   66.25 +        this.identifier = identifier;
   66.26 +    }
   66.27 +
   66.28 +    public AmountType getAmount() {
   66.29 +        return amount;
   66.30 +    }
   66.31 +
   66.32 +    public IdentifierType getIdentifier() {
   66.33 +        return identifier;
   66.34 +    }
   66.35 +
   66.36 +    @Override
   66.37 +    public boolean equals(Object obj) {
   66.38 +        if (obj == null) {
   66.39 +            return false;
   66.40 +        }
   66.41 +        if (getClass() != obj.getClass()) {
   66.42 +            return false;
   66.43 +        }
   66.44 +        final CurrencyValue other = (CurrencyValue) obj;
   66.45 +        if (this.amount != other.amount && (this.amount == null || !this.amount.equals(other.amount))) {
   66.46 +            return false;
   66.47 +        }
   66.48 +        if (this.identifier != other.identifier && (this.identifier == null || !this.identifier.equals(other.identifier))) {
   66.49 +            return false;
   66.50 +        }
   66.51 +        return true;
   66.52 +    }
   66.53 +
   66.54 +    @Override
   66.55 +    public int hashCode() {
   66.56 +        int hash = 7;
   66.57 +        hash = 97 * hash + (this.amount != null ? this.amount.hashCode() : 0);
   66.58 +        hash = 97 * hash + (this.identifier != null ? this.identifier.hashCode() : 0);
   66.59 +        return hash;
   66.60 +    }
   66.61 +
   66.62 +    /**
   66.63 +     * Creates new instance.
   66.64 +     * Generic types of the new instance are derived from types of the parameters.
   66.65 +     * 
   66.66 +     * @param <AmountType> type of the currency amount
   66.67 +     * @param <IdentifierType> type of the currency identifier
   66.68 +     * @param amount currency amount
   66.69 +     * @param identifier currency identifier
   66.70 +     * @return new instance
   66.71 +     */
   66.72 +    public static <AmountType, IdentifierType> CurrencyValue<AmountType, IdentifierType> getCurrencyValue(AmountType amount, IdentifierType identifier) {
   66.73 +        return new CurrencyValue<AmountType, IdentifierType>(amount, identifier);
   66.74 +    }
   66.75 +}
    67.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    67.2 +++ b/task3/solution11/src/org/apidesign/apifest08/currency/ExchangeRateValue.java	Tue Oct 07 11:05:34 2008 +0200
    67.3 @@ -0,0 +1,78 @@
    67.4 +package org.apidesign.apifest08.currency;
    67.5 +
    67.6 +import java.io.Serializable;
    67.7 +
    67.8 +/**
    67.9 + * Value class, holding an exchange rate between two currencies.
   67.10 + * Designed to be an immutable.
   67.11 + * 
   67.12 + * @author ked
   67.13 + */
   67.14 +public final class ExchangeRateValue<AmountType, IdentifierType> implements Serializable {
   67.15 +
   67.16 +    private final CurrencyValue<AmountType, IdentifierType> currencyA;
   67.17 +    private final CurrencyValue<AmountType, IdentifierType> currencyB;
   67.18 +
   67.19 +    private ExchangeRateValue(
   67.20 +            CurrencyValue<AmountType, IdentifierType> currencyA,
   67.21 +            CurrencyValue<AmountType, IdentifierType> currencyB) {
   67.22 +        if (currencyA.getIdentifier() == null ||
   67.23 +            currencyB.getIdentifier() == null ||
   67.24 +            currencyA.getIdentifier().equals(currencyB)) {
   67.25 +                throw new IllegalArgumentException("Inappropriate exchange rates' identifiers!");
   67.26 +        }
   67.27 +
   67.28 +        this.currencyA = currencyA;
   67.29 +        this.currencyB = currencyB;
   67.30 +    }
   67.31 +
   67.32 +    public CurrencyValue<AmountType, IdentifierType> getCurrencyA() {
   67.33 +        return currencyA;
   67.34 +    }
   67.35 +
   67.36 +    public CurrencyValue<AmountType, IdentifierType> getCurrencyB() {
   67.37 +        return currencyB;
   67.38 +    }
   67.39 +
   67.40 +    @Override
   67.41 +    public boolean equals(Object obj) {
   67.42 +        if (obj == null) {
   67.43 +            return false;
   67.44 +        }
   67.45 +        if (getClass() != obj.getClass()) {
   67.46 +            return false;
   67.47 +        }
   67.48 +        final ExchangeRateValue other = (ExchangeRateValue) obj;
   67.49 +        if (this.currencyA != other.currencyA && (this.currencyA == null || !this.currencyA.equals(other.currencyA))) {
   67.50 +            return false;
   67.51 +        }
   67.52 +        if (this.currencyB != other.currencyB && (this.currencyB == null || !this.currencyB.equals(other.currencyB))) {
   67.53 +            return false;
   67.54 +        }
   67.55 +        return true;
   67.56 +    }
   67.57 +
   67.58 +    @Override
   67.59 +    public int hashCode() {
   67.60 +        int hash = 3;
   67.61 +        hash = 71 * hash + (this.currencyA != null ? this.currencyA.hashCode() : 0);
   67.62 +        hash = 71 * hash + (this.currencyB != null ? this.currencyB.hashCode() : 0);
   67.63 +        return hash;
   67.64 +    }
   67.65 +
   67.66 +    /**
   67.67 +     * Creates new instance.
   67.68 +     * Generic types of the new instance are derived from types of the parameters.
   67.69 +     * 
   67.70 +     * @param <AmountType> type of the currency amount
   67.71 +     * @param <IdentifierType> type of the currency identifier
   67.72 +     * @param currencyA one currency of the exchange rate
   67.73 +     * @param currencyB another currency of the exchange rate
   67.74 +     * @return new instance
   67.75 +     */
   67.76 +    public static <AmountType, IdentifierType> ExchangeRateValue<AmountType, IdentifierType> getExchangeRate(
   67.77 +            CurrencyValue<AmountType, IdentifierType> currencyA,
   67.78 +            CurrencyValue<AmountType, IdentifierType> currencyB) {
   67.79 +        return new ExchangeRateValue<AmountType, IdentifierType>(currencyA, currencyB);
   67.80 +    }
   67.81 +}
    68.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    68.2 +++ b/task3/solution11/test/org/apidesign/apifest08/test/Task1Test.java	Tue Oct 07 11:05:34 2008 +0200
    68.3 @@ -0,0 +1,161 @@
    68.4 +package org.apidesign.apifest08.test;
    68.5 +
    68.6 +import junit.framework.TestCase;
    68.7 +import org.apidesign.apifest08.currency.Convertor;
    68.8 +import org.apidesign.apifest08.currency.CurrencyValue;
    68.9 +
   68.10 +/** Finish the Convertor API, and then write bodies of methods inside
   68.11 + * of this class to match the given tasks. To fullfil your task, use the
   68.12 + * API define in the <code>org.apidesign.apifest08.currency</code> package.
   68.13 + * Do not you reflection, or other hacks as your code
   68.14 + * shall run without any runtime permissions.
   68.15 + */
   68.16 +public class Task1Test extends TestCase {
   68.17 +    public Task1Test(String testName) {
   68.18 +        super(testName);
   68.19 +    }
   68.20 +
   68.21 +    @Override
   68.22 +    protected void setUp() throws Exception {
   68.23 +    }
   68.24 +
   68.25 +    @Override
   68.26 +    protected void tearDown() throws Exception {
   68.27 +    }
   68.28 +
   68.29 +    //
   68.30 +    // Imagine that there are three parts of the whole system:
   68.31 +    // 1. there is someone who knows the current exchange rate
   68.32 +    // 2. there is someone who wants to do the conversion
   68.33 +    // 3. there is the API between 1. and 2. which allows them to communicate
   68.34 +    // Please design such API
   68.35 +    //
   68.36 +
   68.37 +    /** Create convertor that understands two currencies, CZK and
   68.38 +     *  USD. Make 1 USD == 17 CZK. This is a method provided for #1 group -
   68.39 +     *  e.g. those that know the exchange rate. They somehow need to create
   68.40 +     *  the objects from the API and tell them the exchange rate. The API itself
   68.41 +     *  knows nothing about any rates, before the createCZKtoUSD method is called.
   68.42 +     *
   68.43 +     * Creation of the convertor shall not require subclassing of any class
   68.44 +     * or interface on the client side.
   68.45 +     *
   68.46 +     * @return prepared convertor ready for converting USD to CZK and CZK to USD
   68.47 +     */
   68.48 +    public static Convertor<Integer, String> createCZKtoUSD() {
   68.49 +        return Convertor.getConvertorIntegerString(
   68.50 +                CurrencyValue.getCurrencyValue(1, "USD"),
   68.51 +                CurrencyValue.getCurrencyValue(17, "CZK")
   68.52 +        );
   68.53 +    }
   68.54 +
   68.55 +    /** Create convertor that understands two currencies, CZK and
   68.56 +     *  SKK. Make 100 SKK == 80 CZK. Again this is method for the #1 group -
   68.57 +     *  it knows the exchange rate, and needs to use the API to create objects
   68.58 +     *  with the exchange rate. Anyone shall be ready to call this method without
   68.59 +     *  any other method being called previously. The API itself shall know
   68.60 +     *  nothing about any rates, before this method is called.
   68.61 +     *
   68.62 +     * Creation of the convertor shall not require subclassing of any class
   68.63 +     * or interface on the client side.
   68.64 +     * 
   68.65 +     * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
   68.66 +     */
   68.67 +    public static Convertor<Integer, String> createSKKtoCZK() {
   68.68 +        return Convertor.getConvertorIntegerString(
   68.69 +                CurrencyValue.getCurrencyValue(100, "SKK"),
   68.70 +                CurrencyValue.getCurrencyValue(80, "CZK")
   68.71 +        );
   68.72 +    }
   68.73 +
   68.74 +    //
   68.75 +    // now the methods for group #2 follow:
   68.76 +    // this group knows nothing about exchange rates, but knows how to use
   68.77 +    // the API to do conversions. It somehow (by calling one of the factory
   68.78 +    // methods) gets objects from the API and uses them to do the conversions.
   68.79 +    //
   68.80 +    
   68.81 +    /** Use the convertor from <code>createCZKtoUSD</code> method and do few conversions
   68.82 +     * with it.
   68.83 +     */
   68.84 +    public void testCurrencyCZKUSD() throws Exception {
   68.85 +        Convertor<Integer, String> c = createCZKtoUSD();
   68.86 +        
   68.87 +        CurrencyValue<Integer, String> result;
   68.88 +        
   68.89 +        // convert $5 to CZK using c:
   68.90 +        // assertEquals("Result is 85 CZK");
   68.91 +        result = c.convert("CZK", CurrencyValue.getCurrencyValue(5, "USD"));
   68.92 +        assertEquals(CurrencyValue.getCurrencyValue(85, "CZK"), result);
   68.93 +
   68.94 +        // convert $8 to CZK
   68.95 +        // assertEquals("Result is 136 CZK");
   68.96 +        result = c.convert("CZK", CurrencyValue.getCurrencyValue(8, "USD"));
   68.97 +        assertEquals(CurrencyValue.getCurrencyValue(136, "CZK"), result);
   68.98 +
   68.99 +        // convert 1003CZK to USD
  68.100 +        // assertEquals("Result is 59 USD");
  68.101 +        result = c.convert("USD", CurrencyValue.getCurrencyValue(1003, "CZK"));
  68.102 +        assertEquals(CurrencyValue.getCurrencyValue(59, "USD"), result);
  68.103 +    }
  68.104 +
  68.105 +    /** Use the convertor from <code>createSKKtoCZK</code> method and do few conversions
  68.106 +     * with it.
  68.107 +     */
  68.108 +    public void testCurrencySKKCZK() throws Exception {
  68.109 +        Convertor<Integer, String> c = createSKKtoCZK();
  68.110 +        
  68.111 +        CurrencyValue<Integer, String> result;
  68.112 +        
  68.113 +        // convert 16CZK using c:
  68.114 +        // assertEquals("Result is 20 SKK");
  68.115 +        result = c.convert("SKK", CurrencyValue.getCurrencyValue(16, "CZK"));
  68.116 +        assertEquals(CurrencyValue.getCurrencyValue(20, "SKK"), result);
  68.117 +
  68.118 +        // convert 500SKK to CZK
  68.119 +        // assertEquals("Result is 400 CZK");
  68.120 +        result = c.convert("CZK", CurrencyValue.getCurrencyValue(500, "SKK"));
  68.121 +        assertEquals(CurrencyValue.getCurrencyValue(400, "CZK"), result);
  68.122 +    }
  68.123 +
  68.124 +    /** Verify that the CZK to USD convertor knows nothing about SKK.
  68.125 +     */
  68.126 +    public void testCannotConvertToSKKwithCZKUSDConvertor() throws Exception {
  68.127 +        Convertor<Integer, String> c = createCZKtoUSD();
  68.128 +        try {
  68.129 +            // convert $5 to SKK, the API shall say this is not possible
  68.130 +            c.convert("SKK", CurrencyValue.getCurrencyValue(16, "CZK"));
  68.131 +            assertTrue("Should not convert", false);
  68.132 +        } catch (Exception e) {
  68.133 +            assertTrue(true);
  68.134 +        }
  68.135 +        try {
  68.136 +            // convert 500 SKK to CZK, the API shall say this is not possible
  68.137 +            c.convert("CZK", CurrencyValue.getCurrencyValue(500, "SKK"));
  68.138 +            assertTrue("Should not convert", false);
  68.139 +        } catch (Exception e) {
  68.140 +            assertTrue(true);
  68.141 +        }
  68.142 +        
  68.143 +    }
  68.144 +
  68.145 +    /** Verify that the CZK to SKK convertor knows nothing about USD.
  68.146 +     */
  68.147 +    public void testCannotConvertToUSDwithSKKCZKConvertor() throws Exception {
  68.148 +        Convertor<Integer, String> c = createSKKtoCZK();
  68.149 +        try {
  68.150 +            // convert $5 to SKK, the API shall say this is not possible
  68.151 +            c.convert("SKK", CurrencyValue.getCurrencyValue(5, "USD"));
  68.152 +            assertTrue("Should not convert", false);
  68.153 +        } catch (Exception e) {
  68.154 +            assertTrue(true);
  68.155 +        }
  68.156 +        try {
  68.157 +            // convert 500 CZK to USD, the API shall say this is not possible
  68.158 +            c.convert("USD", CurrencyValue.getCurrencyValue(500, "CZK"));
  68.159 +            assertTrue("Should not convert", false);
  68.160 +        } catch (Exception e) {
  68.161 +            assertTrue(true);
  68.162 +        }
  68.163 +    }
  68.164 +}
    69.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    69.2 +++ b/task3/solution11/test/org/apidesign/apifest08/test/Task2Test.java	Tue Oct 07 11:05:34 2008 +0200
    69.3 @@ -0,0 +1,140 @@
    69.4 +package org.apidesign.apifest08.test;
    69.5 +
    69.6 +import java.util.ArrayList;
    69.7 +import java.util.Collection;
    69.8 +import junit.framework.TestCase;
    69.9 +import org.apidesign.apifest08.currency.Convertor;
   69.10 +import org.apidesign.apifest08.currency.CurrencyValue;
   69.11 +import org.apidesign.apifest08.currency.ExchangeRateValue;
   69.12 +
   69.13 +/** There are many currencies around the world and many banks manipulate
   69.14 + * with more than one or two at the same time. As banks are usually the
   69.15 + * best paying clients, which is true even in case of your Convertor API,
   69.16 + * it is reasonable to listen to their requests.
   69.17 + * <p>
   69.18 + * The quest for today is to enhance your existing convertor API to hold
   69.19 + * information about many currencies and allow conversions between any of them.
   69.20 + * Also, as conversion rates for diferent currencies usually arise from various
   69.21 + * bank departments, there is another important need. There is a need to
   69.22 + * compose two convertors into one by merging all the information about
   69.23 + * currencies they know about.
   69.24 + */
   69.25 +public class Task2Test extends TestCase {
   69.26 +
   69.27 +    public Task2Test(String testName) {
   69.28 +        super(testName);
   69.29 +    }
   69.30 +
   69.31 +    @Override
   69.32 +    protected void setUp() throws Exception {
   69.33 +    }
   69.34 +
   69.35 +    @Override
   69.36 +    protected void tearDown() throws Exception {
   69.37 +    }
   69.38 +
   69.39 +    // As in Task1Test, keep in mind, that there are three parts
   69.40 +    // of the whole system:
   69.41 +    // 1. there is someone who knows the current exchange rate
   69.42 +    // 2. there is someone who wants to do the conversion
   69.43 +    // 3. there is the API between 1. and 2. which allows them to communicate
   69.44 +    // 
   69.45 +    // Please backward compatibly enhance your existing API to support following
   69.46 +    // usecases:
   69.47 +    //
   69.48 +    /** Create convertor that understands two currencies, CZK and
   69.49 +     *  SKK. Make 100 SKK == 75 CZK. This is method for the group of users that
   69.50 +     *  knows the exchange rate, and needs to use the API to create objects
   69.51 +     *  with the exchange rate. Anyone shall be ready to call this method without
   69.52 +     *  any other method being called previously. The API itself shall know
   69.53 +     *  nothing about any rates, before this method is called.
   69.54 +     */
   69.55 +    public static Convertor<Integer, String> createTripleConvertor() {
   69.56 +        // Rates: 1USD = 15CZK
   69.57 +        // Rates: 1USD = 20SKK
   69.58 +        // Rates: 75CZK = 100SKK
   69.59 +        Collection<ExchangeRateValue<Integer, String>> exchangeRates =
   69.60 +                new ArrayList<ExchangeRateValue<Integer, String>>();
   69.61 +        exchangeRates.add(ExchangeRateValue.getExchangeRate(
   69.62 +                CurrencyValue.getCurrencyValue(1, "USD"),
   69.63 +                CurrencyValue.getCurrencyValue(15, "CZK")));
   69.64 +        exchangeRates.add(ExchangeRateValue.getExchangeRate(
   69.65 +                CurrencyValue.getCurrencyValue(1, "USD"),
   69.66 +                CurrencyValue.getCurrencyValue(20, "SKK")));
   69.67 +        exchangeRates.add(ExchangeRateValue.getExchangeRate(
   69.68 +                CurrencyValue.getCurrencyValue(75, "CZK"),
   69.69 +                CurrencyValue.getCurrencyValue(100, "SKK")));
   69.70 +        return Convertor.getConvertorIntegerString(exchangeRates);
   69.71 +    }
   69.72 +
   69.73 +    /** Define convertor that understands three currencies. Use it.
   69.74 +     */
   69.75 +    public void testConvertorForUSDandCZKandSKK() throws Exception {
   69.76 +        Convertor<Integer, String> c = createTripleConvertor();
   69.77 +
   69.78 +        CurrencyValue<Integer, String> result;
   69.79 +        // convert $5 to CZK using c:
   69.80 +        // assertEquals("Result is 75 CZK");
   69.81 +        result = c.convert("CZK", CurrencyValue.getCurrencyValue(5, "USD"));
   69.82 +        assertEquals(CurrencyValue.getCurrencyValue(75, "CZK"), result);
   69.83 +
   69.84 +        // convert $5 to SKK using c:
   69.85 +        // assertEquals("Result is 100 SKK");
   69.86 +        result = c.convert("SKK", CurrencyValue.getCurrencyValue(5, "USD"));
   69.87 +        assertEquals(CurrencyValue.getCurrencyValue(100, "SKK"), result);
   69.88 +
   69.89 +        // convert 200SKK to CZK using c:
   69.90 +        // assertEquals("Result is 150 CZK");
   69.91 +        result = c.convert("CZK", CurrencyValue.getCurrencyValue(200, "SKK"));
   69.92 +        assertEquals(CurrencyValue.getCurrencyValue(150, "CZK"), result);
   69.93 +
   69.94 +        // convert 200SKK to USK using c:
   69.95 +        // assertEquals("Result is 10 USD");
   69.96 +        result = c.convert("USD", CurrencyValue.getCurrencyValue(200, "SKK"));
   69.97 +        assertEquals(CurrencyValue.getCurrencyValue(10, "USD"), result);
   69.98 +    }
   69.99 +
  69.100 +    /** Merge all currency rates of convertor 1 with convertor 2.
  69.101 +     * Implement this using your API, preferably this method just delegates
  69.102 +     * into some API method which does the actual work, without requiring
  69.103 +     * API clients to code anything complex.
  69.104 +     */
  69.105 +    public static Convertor<Integer, String> merge(Convertor<Integer, String> one, Convertor<Integer, String> two) {
  69.106 +        return Convertor.mergeConvertorsIntegerString(one, two);
  69.107 +    }
  69.108 +
  69.109 +    /** Join the convertors from previous task, Task1Test and show that it
  69.110 +     * can be used to do reasonable conversions.
  69.111 +     */
  69.112 +    public void testConvertorComposition() throws Exception {
  69.113 +        Convertor<Integer, String> c = merge(
  69.114 +                Task1Test.createCZKtoUSD(),
  69.115 +                Task1Test.createSKKtoCZK());
  69.116 +
  69.117 +        CurrencyValue<Integer, String> result;
  69.118 +        // convert $5 to CZK using c:
  69.119 +        // assertEquals("Result is 85 CZK");
  69.120 +        result = c.convert("CZK", CurrencyValue.getCurrencyValue(5, "USD"));
  69.121 +        assertEquals(CurrencyValue.getCurrencyValue(85, "CZK"), result);
  69.122 +
  69.123 +        // convert $8 to CZK using c:
  69.124 +        // assertEquals("Result is 136 CZK");
  69.125 +        result = c.convert("CZK", CurrencyValue.getCurrencyValue(8, "USD"));
  69.126 +        assertEquals(CurrencyValue.getCurrencyValue(136, "CZK"), result);
  69.127 +
  69.128 +        // convert 1003CZK to USD using c:
  69.129 +        // assertEquals("Result is 59 USD");
  69.130 +        result = c.convert("USD", CurrencyValue.getCurrencyValue(1003, "CZK"));
  69.131 +        assertEquals(CurrencyValue.getCurrencyValue(59, "USD"), result);
  69.132 +
  69.133 +        // convert 16CZK using c:
  69.134 +        // assertEquals("Result is 20 SKK");
  69.135 +        result = c.convert("SKK", CurrencyValue.getCurrencyValue(16, "CZK"));
  69.136 +        assertEquals(CurrencyValue.getCurrencyValue(20, "SKK"), result);
  69.137 +
  69.138 +        // convert 500SKK to CZK using c:
  69.139 +        // assertEquals("Result is 400 CZK");
  69.140 +        result = c.convert("CZK", CurrencyValue.getCurrencyValue(500, "SKK"));
  69.141 +        assertEquals(CurrencyValue.getCurrencyValue(400, "CZK"), result);
  69.142 +    }
  69.143 +}
    70.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    70.2 +++ b/task3/solution12/build.xml	Tue Oct 07 11:05:34 2008 +0200
    70.3 @@ -0,0 +1,69 @@
    70.4 +<?xml version="1.0" encoding="UTF-8"?>
    70.5 +<!-- You may freely edit this file. See commented blocks below for -->
    70.6 +<!-- some examples of how to customize the build. -->
    70.7 +<!-- (If you delete it and reopen the project it will be recreated.) -->
    70.8 +<project name="currency" default="default" basedir=".">
    70.9 +    <description>Builds, tests, and runs the project.</description>
   70.10 +    <import file="nbproject/build-impl.xml"/>
   70.11 +    <!--
   70.12 +
   70.13 +    There exist several targets which are by default empty and which can be 
   70.14 +    used for execution of your tasks. These targets are usually executed 
   70.15 +    before and after some main targets. They are: 
   70.16 +
   70.17 +      -pre-init:                 called before initialization of project properties
   70.18 +      -post-init:                called after initialization of project properties
   70.19 +      -pre-compile:              called before javac compilation
   70.20 +      -post-compile:             called after javac compilation
   70.21 +      -pre-compile-single:       called before javac compilation of single file
   70.22 +      -post-compile-single:      called after javac compilation of single file
   70.23 +      -pre-compile-test:         called before javac compilation of JUnit tests
   70.24 +      -post-compile-test:        called after javac compilation of JUnit tests
   70.25 +      -pre-compile-test-single:  called before javac compilation of single JUnit test
   70.26 +      -post-compile-test-single: called after javac compilation of single JUunit test
   70.27 +      -pre-jar:                  called before JAR building
   70.28 +      -post-jar:                 called after JAR building
   70.29 +      -post-clean:               called after cleaning build products
   70.30 +
   70.31 +    (Targets beginning with '-' are not intended to be called on their own.)
   70.32 +
   70.33 +    Example of inserting an obfuscator after compilation could look like this:
   70.34 +
   70.35 +        <target name="-post-compile">
   70.36 +            <obfuscate>
   70.37 +                <fileset dir="${build.classes.dir}"/>
   70.38 +            </obfuscate>
   70.39 +        </target>
   70.40 +
   70.41 +    For list of available properties check the imported 
   70.42 +    nbproject/build-impl.xml file. 
   70.43 +
   70.44 +
   70.45 +    Another way to customize the build is by overriding existing main targets.
   70.46 +    The targets of interest are: 
   70.47 +
   70.48 +      -init-macrodef-javac:     defines macro for javac compilation
   70.49 +      -init-macrodef-junit:     defines macro for junit execution
   70.50 +      -init-macrodef-debug:     defines macro for class debugging
   70.51 +      -init-macrodef-java:      defines macro for class execution
   70.52 +      -do-jar-with-manifest:    JAR building (if you are using a manifest)
   70.53 +      -do-jar-without-manifest: JAR building (if you are not using a manifest)
   70.54 +      run:                      execution of project 
   70.55 +      -javadoc-build:           Javadoc generation
   70.56 +      test-report:              JUnit report generation
   70.57 +
   70.58 +    An example of overriding the target for project execution could look like this:
   70.59 +
   70.60 +        <target name="run" depends="currency-impl.jar">
   70.61 +            <exec dir="bin" executable="launcher.exe">
   70.62 +                <arg file="${dist.jar}"/>
   70.63 +            </exec>
   70.64 +        </target>
   70.65 +
   70.66 +    Notice that the overridden target depends on the jar target and not only on 
   70.67 +    the compile target as the regular run target does. Again, for a list of available 
   70.68 +    properties which you can use, check the target you are overriding in the
   70.69 +    nbproject/build-impl.xml file. 
   70.70 +
   70.71 +    -->
   70.72 +</project>
    71.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    71.2 +++ b/task3/solution12/nbproject/build-impl.xml	Tue Oct 07 11:05:34 2008 +0200
    71.3 @@ -0,0 +1,642 @@
    71.4 +<?xml version="1.0" encoding="UTF-8"?>
    71.5 +<!--
    71.6 +*** GENERATED FROM project.xml - DO NOT EDIT  ***
    71.7 +***         EDIT ../build.xml INSTEAD         ***
    71.8 +
    71.9 +For the purpose of easier reading the script
   71.10 +is divided into following sections:
   71.11 +
   71.12 +  - initialization
   71.13 +  - compilation
   71.14 +  - jar
   71.15 +  - execution
   71.16 +  - debugging
   71.17 +  - javadoc
   71.18 +  - junit compilation
   71.19 +  - junit execution
   71.20 +  - junit debugging
   71.21 +  - applet
   71.22 +  - cleanup
   71.23 +
   71.24 +        -->
   71.25 +<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="Currency_Convertor_Solution_12-impl">
   71.26 +    <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
   71.27 +    <!-- 
   71.28 +                ======================
   71.29 +                INITIALIZATION SECTION 
   71.30 +                ======================
   71.31 +            -->
   71.32 +    <target name="-pre-init">
   71.33 +        <!-- Empty placeholder for easier customization. -->
   71.34 +        <!-- You can override this target in the ../build.xml file. -->
   71.35 +    </target>
   71.36 +    <target depends="-pre-init" name="-init-private">
   71.37 +        <property file="nbproject/private/config.properties"/>
   71.38 +        <property file="nbproject/private/configs/${config}.properties"/>
   71.39 +        <property file="nbproject/private/private.properties"/>
   71.40 +    </target>
   71.41 +    <target depends="-pre-init,-init-private" name="-init-user">
   71.42 +        <property file="${user.properties.file}"/>
   71.43 +        <!-- The two properties below are usually overridden -->
   71.44 +        <!-- by the active platform. Just a fallback. -->
   71.45 +        <property name="default.javac.source" value="1.4"/>
   71.46 +        <property name="default.javac.target" value="1.4"/>
   71.47 +    </target>
   71.48 +    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
   71.49 +        <property file="nbproject/configs/${config}.properties"/>
   71.50 +        <property file="nbproject/project.properties"/>
   71.51 +    </target>
   71.52 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
   71.53 +        <available file="${manifest.file}" property="manifest.available"/>
   71.54 +        <condition property="manifest.available+main.class">
   71.55 +            <and>
   71.56 +                <isset property="manifest.available"/>
   71.57 +                <isset property="main.class"/>
   71.58 +                <not>
   71.59 +                    <equals arg1="${main.class}" arg2="" trim="true"/>
   71.60 +                </not>
   71.61 +            </and>
   71.62 +        </condition>
   71.63 +        <condition property="manifest.available+main.class+mkdist.available">
   71.64 +            <and>
   71.65 +                <istrue value="${manifest.available+main.class}"/>
   71.66 +                <isset property="libs.CopyLibs.classpath"/>
   71.67 +            </and>
   71.68 +        </condition>
   71.69 +        <condition property="have.tests">
   71.70 +            <or>
   71.71 +                <available file="${test.src.dir}"/>
   71.72 +            </or>
   71.73 +        </condition>
   71.74 +        <condition property="have.sources">
   71.75 +            <or>
   71.76 +                <available file="${src.dir}"/>
   71.77 +            </or>
   71.78 +        </condition>
   71.79 +        <condition property="netbeans.home+have.tests">
   71.80 +            <and>
   71.81 +                <isset property="netbeans.home"/>
   71.82 +                <isset property="have.tests"/>
   71.83 +            </and>
   71.84 +        </condition>
   71.85 +        <condition property="no.javadoc.preview">
   71.86 +            <and>
   71.87 +                <isset property="javadoc.preview"/>
   71.88 +                <isfalse value="${javadoc.preview}"/>
   71.89 +            </and>
   71.90 +        </condition>
   71.91 +        <property name="run.jvmargs" value=""/>
   71.92 +        <property name="javac.compilerargs" value=""/>
   71.93 +        <property name="work.dir" value="${basedir}"/>
   71.94 +        <condition property="no.deps">
   71.95 +            <and>
   71.96 +                <istrue value="${no.dependencies}"/>
   71.97 +            </and>
   71.98 +        </condition>
   71.99 +        <property name="javac.debug" value="true"/>
  71.100 +        <property name="javadoc.preview" value="true"/>
  71.101 +        <property name="application.args" value=""/>
  71.102 +        <property name="source.encoding" value="${file.encoding}"/>
  71.103 +        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
  71.104 +            <and>
  71.105 +                <isset property="javadoc.encoding"/>
  71.106 +                <not>
  71.107 +                    <equals arg1="${javadoc.encoding}" arg2=""/>
  71.108 +                </not>
  71.109 +            </and>
  71.110 +        </condition>
  71.111 +        <property name="javadoc.encoding.used" value="${source.encoding}"/>
  71.112 +        <property name="includes" value="**"/>
  71.113 +        <property name="excludes" value=""/>
  71.114 +        <property name="do.depend" value="false"/>
  71.115 +        <condition property="do.depend.true">
  71.116 +            <istrue value="${do.depend}"/>
  71.117 +        </condition>
  71.118 +        <condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
  71.119 +            <and>
  71.120 +                <isset property="jaxws.endorsed.dir"/>
  71.121 +                <available file="nbproject/jaxws-build.xml"/>
  71.122 +            </and>
  71.123 +        </condition>
  71.124 +    </target>
  71.125 +    <target name="-post-init">
  71.126 +        <!-- Empty placeholder for easier customization. -->
  71.127 +        <!-- You can override this target in the ../build.xml file. -->
  71.128 +    </target>
  71.129 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
  71.130 +        <fail unless="src.dir">Must set src.dir</fail>
  71.131 +        <fail unless="test.src.dir">Must set test.src.dir</fail>
  71.132 +        <fail unless="build.dir">Must set build.dir</fail>
  71.133 +        <fail unless="dist.dir">Must set dist.dir</fail>
  71.134 +        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
  71.135 +        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
  71.136 +        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
  71.137 +        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
  71.138 +        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
  71.139 +        <fail unless="dist.jar">Must set dist.jar</fail>
  71.140 +    </target>
  71.141 +    <target name="-init-macrodef-property">
  71.142 +        <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
  71.143 +            <attribute name="name"/>
  71.144 +            <attribute name="value"/>
  71.145 +            <sequential>
  71.146 +                <property name="@{name}" value="${@{value}}"/>
  71.147 +            </sequential>
  71.148 +        </macrodef>
  71.149 +    </target>
  71.150 +    <target name="-init-macrodef-javac">
  71.151 +        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
  71.152 +            <attribute default="${src.dir}" name="srcdir"/>
  71.153 +            <attribute default="${build.classes.dir}" name="destdir"/>
  71.154 +            <attribute default="${javac.classpath}" name="classpath"/>
  71.155 +            <attribute default="${includes}" name="includes"/>
  71.156 +            <attribute default="${excludes}" name="excludes"/>
  71.157 +            <attribute default="${javac.debug}" name="debug"/>
  71.158 +            <attribute default="" name="sourcepath"/>
  71.159 +            <element name="customize" optional="true"/>
  71.160 +            <sequential>
  71.161 +                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
  71.162 +                    <classpath>
  71.163 +                        <path path="@{classpath}"/>
  71.164 +                    </classpath>
  71.165 +                    <compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
  71.166 +                    <customize/>
  71.167 +                </javac>
  71.168 +            </sequential>
  71.169 +        </macrodef>
  71.170 +        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
  71.171 +            <attribute default="${src.dir}" name="srcdir"/>
  71.172 +            <attribute default="${build.classes.dir}" name="destdir"/>
  71.173 +            <attribute default="${javac.classpath}" name="classpath"/>
  71.174 +            <sequential>
  71.175 +                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
  71.176 +                    <classpath>
  71.177 +                        <path path="@{classpath}"/>
  71.178 +                    </classpath>
  71.179 +                </depend>
  71.180 +            </sequential>
  71.181 +        </macrodef>
  71.182 +        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
  71.183 +            <attribute default="${build.classes.dir}" name="destdir"/>
  71.184 +            <sequential>
  71.185 +                <fail unless="javac.includes">Must set javac.includes</fail>
  71.186 +                <pathconvert pathsep="," property="javac.includes.binary">
  71.187 +                    <path>
  71.188 +                        <filelist dir="@{destdir}" files="${javac.includes}"/>
  71.189 +                    </path>
  71.190 +                    <globmapper from="*.java" to="*.class"/>
  71.191 +                </pathconvert>
  71.192 +                <delete>
  71.193 +                    <files includes="${javac.includes.binary}"/>
  71.194 +                </delete>
  71.195 +            </sequential>
  71.196 +        </macrodef>
  71.197 +    </target>
  71.198 +    <target name="-init-macrodef-junit">
  71.199 +        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
  71.200 +            <attribute default="${includes}" name="includes"/>
  71.201 +            <attribute default="${excludes}" name="excludes"/>
  71.202 +            <attribute default="**" name="testincludes"/>
  71.203 +            <sequential>
  71.204 +                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
  71.205 +                    <batchtest todir="${build.test.results.dir}">
  71.206 +                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
  71.207 +                            <filename name="@{testincludes}"/>
  71.208 +                        </fileset>
  71.209 +                    </batchtest>
  71.210 +                    <classpath>
  71.211 +                        <path path="${run.test.classpath}"/>
  71.212 +                    </classpath>
  71.213 +                    <syspropertyset>
  71.214 +                        <propertyref prefix="test-sys-prop."/>
  71.215 +                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
  71.216 +                    </syspropertyset>
  71.217 +                    <formatter type="brief" usefile="false"/>
  71.218 +                    <formatter type="xml"/>
  71.219 +                    <jvmarg line="${run.jvmargs}"/>
  71.220 +                </junit>
  71.221 +            </sequential>
  71.222 +        </macrodef>
  71.223 +    </target>
  71.224 +    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
  71.225 +        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
  71.226 +            <attribute default="${main.class}" name="name"/>
  71.227 +            <attribute default="${debug.classpath}" name="classpath"/>
  71.228 +            <attribute default="" name="stopclassname"/>
  71.229 +            <sequential>
  71.230 +                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
  71.231 +                    <classpath>
  71.232 +                        <path path="@{classpath}"/>
  71.233 +                    </classpath>
  71.234 +                </nbjpdastart>
  71.235 +            </sequential>
  71.236 +        </macrodef>
  71.237 +        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
  71.238 +            <attribute default="${build.classes.dir}" name="dir"/>
  71.239 +            <sequential>
  71.240 +                <nbjpdareload>
  71.241 +                    <fileset dir="@{dir}" includes="${fix.classes}">
  71.242 +                        <include name="${fix.includes}*.class"/>
  71.243 +                    </fileset>
  71.244 +                </nbjpdareload>
  71.245 +            </sequential>
  71.246 +        </macrodef>
  71.247 +    </target>
  71.248 +    <target name="-init-debug-args">
  71.249 +        <property name="version-output" value="java version &quot;${ant.java.version}"/>
  71.250 +        <condition property="have-jdk-older-than-1.4">
  71.251 +            <or>
  71.252 +                <contains string="${version-output}" substring="java version &quot;1.0"/>
  71.253 +                <contains string="${version-output}" substring="java version &quot;1.1"/>
  71.254 +                <contains string="${version-output}" substring="java version &quot;1.2"/>
  71.255 +                <contains string="${version-output}" substring="java version &quot;1.3"/>
  71.256 +            </or>
  71.257 +        </condition>
  71.258 +        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
  71.259 +            <istrue value="${have-jdk-older-than-1.4}"/>
  71.260 +        </condition>
  71.261 +        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
  71.262 +            <os family="windows"/>
  71.263 +        </condition>
  71.264 +        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
  71.265 +            <isset property="debug.transport"/>
  71.266 +        </condition>
  71.267 +    </target>
  71.268 +    <target depends="-init-debug-args" name="-init-macrodef-debug">
  71.269 +        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
  71.270 +            <attribute default="${main.class}" name="classname"/>
  71.271 +            <attribute default="${debug.classpath}" name="classpath"/>
  71.272 +            <element name="customize" optional="true"/>
  71.273 +            <sequential>
  71.274 +                <java classname="@{classname}" dir="${work.dir}" fork="true">
  71.275 +                    <jvmarg line="${debug-args-line}"/>
  71.276 +                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
  71.277 +                    <jvmarg line="${run.jvmargs}"/>
  71.278 +                    <classpath>
  71.279 +                        <path path="@{classpath}"/>
  71.280 +                    </classpath>
  71.281 +                    <syspropertyset>
  71.282 +                        <propertyref prefix="run-sys-prop."/>
  71.283 +                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
  71.284 +                    </syspropertyset>
  71.285 +                    <customize/>
  71.286 +                </java>
  71.287 +            </sequential>
  71.288 +        </macrodef>
  71.289 +    </target>
  71.290 +    <target name="-init-macrodef-java">
  71.291 +        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
  71.292 +            <attribute default="${main.class}" name="classname"/>
  71.293 +            <element name="customize" optional="true"/>
  71.294 +            <sequential>
  71.295 +                <java classname="@{classname}" dir="${work.dir}" fork="true">
  71.296 +                    <jvmarg line="${run.jvmargs}"/>
  71.297 +                    <classpath>
  71.298 +                        <path path="${run.classpath}"/>
  71.299 +                    </classpath>
  71.300 +                    <syspropertyset>
  71.301 +                        <propertyref prefix="run-sys-prop."/>
  71.302 +                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
  71.303 +                    </syspropertyset>
  71.304 +                    <customize/>
  71.305 +                </java>
  71.306 +            </sequential>
  71.307 +        </macrodef>
  71.308 +    </target>
  71.309 +    <target name="-init-presetdef-jar">
  71.310 +        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
  71.311 +            <jar compress="${jar.compress}" jarfile="${dist.jar}">
  71.312 +                <j2seproject1:fileset dir="${build.classes.dir}"/>
  71.313 +            </jar>
  71.314 +        </presetdef>
  71.315 +    </target>
  71.316 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar" name="init"/>
  71.317 +    <!--
  71.318 +                ===================
  71.319 +                COMPILATION SECTION
  71.320 +                ===================
  71.321 +            -->
  71.322 +    <target depends="init" name="deps-jar" unless="no.deps"/>
  71.323 +    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
  71.324 +    <target depends="init" name="-check-automatic-build">
  71.325 +        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
  71.326 +    </target>
  71.327 +    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
  71.328 +        <antcall target="clean"/>
  71.329 +    </target>
  71.330 +    <target depends="init,deps-jar" name="-pre-pre-compile">
  71.331 +        <mkdir dir="${build.classes.dir}"/>
  71.332 +    </target>
  71.333 +    <target name="-pre-compile">
  71.334 +        <!-- Empty placeholder for easier customization. -->
  71.335 +        <!-- You can override this target in the ../build.xml file. -->
  71.336 +    </target>
  71.337 +    <target if="do.depend.true" name="-compile-depend">
  71.338 +        <j2seproject3:depend/>
  71.339 +    </target>
  71.340 +    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
  71.341 +        <j2seproject3:javac/>
  71.342 +        <copy todir="${build.classes.dir}">
  71.343 +            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  71.344 +        </copy>
  71.345 +    </target>
  71.346 +    <target name="-post-compile">
  71.347 +        <!-- Empty placeholder for easier customization. -->
  71.348 +        <!-- You can override this target in the ../build.xml file. -->
  71.349 +    </target>
  71.350 +    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
  71.351 +    <target name="-pre-compile-single">
  71.352 +        <!-- Empty placeholder for easier customization. -->
  71.353 +        <!-- You can override this target in the ../build.xml file. -->
  71.354 +    </target>
  71.355 +    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
  71.356 +        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
  71.357 +        <j2seproject3:force-recompile/>
  71.358 +        <j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
  71.359 +    </target>
  71.360 +    <target name="-post-compile-single">
  71.361 +        <!-- Empty placeholder for easier customization. -->
  71.362 +        <!-- You can override this target in the ../build.xml file. -->
  71.363 +    </target>
  71.364 +    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
  71.365 +    <!--
  71.366 +                ====================
  71.367 +                JAR BUILDING SECTION
  71.368 +                ====================
  71.369 +            -->
  71.370 +    <target depends="init" name="-pre-pre-jar">
  71.371 +        <dirname file="${dist.jar}" property="dist.jar.dir"/>
  71.372 +        <mkdir dir="${dist.jar.dir}"/>
  71.373 +    </target>
  71.374 +    <target name="-pre-jar">
  71.375 +        <!-- Empty placeholder for easier customization. -->
  71.376 +        <!-- You can override this target in the ../build.xml file. -->
  71.377 +    </target>
  71.378 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
  71.379 +        <j2seproject1:jar/>
  71.380 +    </target>
  71.381 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
  71.382 +        <j2seproject1:jar manifest="${manifest.file}"/>
  71.383 +    </target>
  71.384 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
  71.385 +        <j2seproject1:jar manifest="${manifest.file}">
  71.386 +            <j2seproject1:manifest>
  71.387 +                <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
  71.388 +            </j2seproject1:manifest>
  71.389 +        </j2seproject1:jar>
  71.390 +        <echo>To run this application from the command line without Ant, try:</echo>
  71.391 +        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
  71.392 +        <property location="${dist.jar}" name="dist.jar.resolved"/>
  71.393 +        <pathconvert property="run.classpath.with.dist.jar">
  71.394 +            <path path="${run.classpath}"/>
  71.395 +            <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
  71.396 +        </pathconvert>
  71.397 +        <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
  71.398 +    </target>
  71.399 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
  71.400 +        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
  71.401 +        <pathconvert property="run.classpath.without.build.classes.dir">
  71.402 +            <path path="${run.classpath}"/>
  71.403 +            <map from="${build.classes.dir.resolved}" to=""/>
  71.404 +        </pathconvert>
  71.405 +        <pathconvert pathsep=" " property="jar.classpath">
  71.406 +            <path path="${run.classpath.without.build.classes.dir}"/>
  71.407 +            <chainedmapper>
  71.408 +                <flattenmapper/>
  71.409 +                <globmapper from="*" to="lib/*"/>
  71.410 +            </chainedmapper>
  71.411 +        </pathconvert>
  71.412 +        <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
  71.413 +        <copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
  71.414 +            <fileset dir="${build.classes.dir}"/>
  71.415 +            <manifest>
  71.416 +                <attribute name="Main-Class" value="${main.class}"/>
  71.417 +                <attribute name="Class-Path" value="${jar.classpath}"/>
  71.418 +            </manifest>
  71.419 +        </copylibs>
  71.420 +        <echo>To run this application from the command line without Ant, try:</echo>
  71.421 +        <property location="${dist.jar}" name="dist.jar.resolved"/>
  71.422 +        <echo>java -jar "${dist.jar.resolved}"</echo>
  71.423 +    </target>
  71.424 +    <target name="-post-jar">
  71.425 +        <!-- Empty placeholder for easier customization. -->
  71.426 +        <!-- You can override this target in the ../build.xml file. -->
  71.427 +    </target>
  71.428 +    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
  71.429 +    <!--
  71.430 +                =================
  71.431 +                EXECUTION SECTION
  71.432 +                =================
  71.433 +            -->
  71.434 +    <target depends="init,compile" description="Run a main class." name="run">
  71.435 +        <j2seproject1:java>
  71.436 +            <customize>
  71.437 +                <arg line="${application.args}"/>
  71.438 +            </customize>
  71.439 +        </j2seproject1:java>
  71.440 +    </target>
  71.441 +    <target name="-do-not-recompile">
  71.442 +        <property name="javac.includes.binary" value=""/>
  71.443 +    </target>
  71.444 +    <target depends="init,-do-not-recompile,compile-single" name="run-single">
  71.445 +        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
  71.446 +        <j2seproject1:java classname="${run.class}"/>
  71.447 +    </target>
  71.448 +    <!--
  71.449 +                =================
  71.450 +                DEBUGGING SECTION
  71.451 +                =================
  71.452 +            -->
  71.453 +    <target depends="init" if="netbeans.home" name="-debug-start-debugger">
  71.454 +        <j2seproject1:nbjpdastart name="${debug.class}"/>
  71.455 +    </target>
  71.456 +    <target depends="init,compile" name="-debug-start-debuggee">
  71.457 +        <j2seproject3:debug>
  71.458 +            <customize>
  71.459 +                <arg line="${application.args}"/>
  71.460 +            </customize>
  71.461 +        </j2seproject3:debug>
  71.462 +    </target>
  71.463 +    <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
  71.464 +    <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
  71.465 +        <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
  71.466 +    </target>
  71.467 +    <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
  71.468 +    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
  71.469 +        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
  71.470 +        <j2seproject3:debug classname="${debug.class}"/>
  71.471 +    </target>
  71.472 +    <target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
  71.473 +    <target depends="init" name="-pre-debug-fix">
  71.474 +        <fail unless="fix.includes">Must set fix.includes</fail>
  71.475 +        <property name="javac.includes" value="${fix.includes}.java"/>
  71.476 +    </target>
  71.477 +    <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
  71.478 +        <j2seproject1:nbjpdareload/>
  71.479 +    </target>
  71.480 +    <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
  71.481 +    <!--
  71.482 +                ===============
  71.483 +                JAVADOC SECTION
  71.484 +                ===============
  71.485 +            -->
  71.486 +    <target depends="init" name="-javadoc-build">
  71.487 +        <mkdir dir="${dist.javadoc.dir}"/>
  71.488 +        <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
  71.489 +            <classpath>
  71.490 +                <path path="${javac.classpath}"/>
  71.491 +            </classpath>
  71.492 +            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
  71.493 +                <filename name="**/*.java"/>
  71.494 +            </fileset>
  71.495 +        </javadoc>
  71.496 +    </target>
  71.497 +    <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
  71.498 +        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
  71.499 +    </target>
  71.500 +    <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
  71.501 +    <!--
  71.502 +                =========================
  71.503 +                JUNIT COMPILATION SECTION
  71.504 +                =========================
  71.505 +            -->
  71.506 +    <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
  71.507 +        <mkdir dir="${build.test.classes.dir}"/>
  71.508 +    </target>
  71.509 +    <target name="-pre-compile-test">
  71.510 +        <!-- Empty placeholder for easier customization. -->
  71.511 +        <!-- You can override this target in the ../build.xml file. -->
  71.512 +    </target>
  71.513 +    <target if="do.depend.true" name="-compile-test-depend">
  71.514 +        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
  71.515 +    </target>
  71.516 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
  71.517 +        <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
  71.518 +        <copy todir="${build.test.classes.dir}">
  71.519 +            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  71.520 +        </copy>
  71.521 +    </target>
  71.522 +    <target name="-post-compile-test">
  71.523 +        <!-- Empty placeholder for easier customization. -->
  71.524 +        <!-- You can override this target in the ../build.xml file. -->
  71.525 +    </target>
  71.526 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
  71.527 +    <target name="-pre-compile-test-single">
  71.528 +        <!-- Empty placeholder for easier customization. -->
  71.529 +        <!-- You can override this target in the ../build.xml file. -->
  71.530 +    </target>
  71.531 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
  71.532 +        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
  71.533 +        <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
  71.534 +        <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
  71.535 +        <copy todir="${build.test.classes.dir}">
  71.536 +            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  71.537 +        </copy>
  71.538 +    </target>
  71.539 +    <target name="-post-compile-test-single">
  71.540 +        <!-- Empty placeholder for easier customization. -->
  71.541 +        <!-- You can override this target in the ../build.xml file. -->
  71.542 +    </target>
  71.543 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
  71.544 +    <!--
  71.545 +                =======================
  71.546 +                JUNIT EXECUTION SECTION
  71.547 +                =======================
  71.548 +            -->
  71.549 +    <target depends="init" if="have.tests" name="-pre-test-run">
  71.550 +        <mkdir dir="${build.test.results.dir}"/>
  71.551 +    </target>
  71.552 +    <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
  71.553 +        <j2seproject3:junit testincludes="**/*Test.java"/>
  71.554 +    </target>
  71.555 +    <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
  71.556 +        <fail if="tests.failed">Some tests failed; see details above.</fail>
  71.557 +    </target>
  71.558 +    <target depends="init" if="have.tests" name="test-report"/>
  71.559 +    <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
  71.560 +    <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
  71.561 +    <target depends="init" if="have.tests" name="-pre-test-run-single">
  71.562 +        <mkdir dir="${build.test.results.dir}"/>
  71.563 +    </target>
  71.564 +    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
  71.565 +        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
  71.566 +        <j2seproject3:junit excludes="" includes="${test.includes}"/>
  71.567 +    </target>
  71.568 +    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
  71.569 +        <fail if="tests.failed">Some tests failed; see details above.</fail>
  71.570 +    </target>
  71.571 +    <target depends="init,-do-not-recompile,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
  71.572 +    <!--
  71.573 +                =======================
  71.574 +                JUNIT DEBUGGING SECTION
  71.575 +                =======================
  71.576 +            -->
  71.577 +    <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
  71.578 +        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
  71.579 +        <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
  71.580 +        <delete file="${test.report.file}"/>
  71.581 +        <mkdir dir="${build.test.results.dir}"/>
  71.582 +        <j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
  71.583 +            <customize>
  71.584 +                <syspropertyset>
  71.585 +                    <propertyref prefix="test-sys-prop."/>
  71.586 +                    <mapper from="test-sys-prop.*" to="*" type="glob"/>
  71.587 +                </syspropertyset>
  71.588 +                <arg value="${test.class}"/>
  71.589 +                <arg value="showoutput=true"/>
  71.590 +                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
  71.591 +                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
  71.592 +            </customize>
  71.593 +        </j2seproject3:debug>
  71.594 +    </target>
  71.595 +    <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
  71.596 +        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
  71.597 +    </target>
  71.598 +    <target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
  71.599 +    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
  71.600 +        <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
  71.601 +    </target>
  71.602 +    <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
  71.603 +    <!--
  71.604 +                =========================
  71.605 +                APPLET EXECUTION SECTION
  71.606 +                =========================
  71.607 +            -->
  71.608 +    <target depends="init,compile-single" name="run-applet">
  71.609 +        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
  71.610 +        <j2seproject1:java classname="sun.applet.AppletViewer">
  71.611 +            <customize>
  71.612 +                <arg value="${applet.url}"/>
  71.613 +            </customize>
  71.614 +        </j2seproject1:java>
  71.615 +    </target>
  71.616 +    <!--
  71.617 +                =========================
  71.618 +                APPLET DEBUGGING  SECTION
  71.619 +                =========================
  71.620 +            -->
  71.621 +    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
  71.622 +        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
  71.623 +        <j2seproject3:debug classname="sun.applet.AppletViewer">
  71.624 +            <customize>
  71.625 +                <arg value="${applet.url}"/>
  71.626 +            </customize>
  71.627 +        </j2seproject3:debug>
  71.628 +    </target>
  71.629 +    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
  71.630 +    <!--
  71.631 +                ===============
  71.632 +                CLEANUP SECTION
  71.633 +                ===============
  71.634 +            -->
  71.635 +    <target depends="init" name="deps-clean" unless="no.deps"/>
  71.636 +    <target depends="init" name="-do-clean">
  71.637 +        <delete dir="${build.dir}"/>
  71.638 +        <delete dir="${dist.dir}"/>
  71.639 +    </target>
  71.640 +    <target name="-post-clean">
  71.641 +        <!-- Empty placeholder for easier customization. -->
  71.642 +        <!-- You can override this target in the ../build.xml file. -->
  71.643 +    </target>
  71.644 +    <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
  71.645 +</project>
    72.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    72.2 +++ b/task3/solution12/nbproject/genfiles.properties	Tue Oct 07 11:05:34 2008 +0200
    72.3 @@ -0,0 +1,8 @@
    72.4 +build.xml.data.CRC32=2ab820eb
    72.5 +build.xml.script.CRC32=58a52595
    72.6 +build.xml.stylesheet.CRC32=be360661
    72.7 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
    72.8 +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
    72.9 +nbproject/build-impl.xml.data.CRC32=b63e115b
   72.10 +nbproject/build-impl.xml.script.CRC32=3bdfc4fa
   72.11 +nbproject/build-impl.xml.stylesheet.CRC32=e55b27f5
    73.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    73.2 +++ b/task3/solution12/nbproject/project.properties	Tue Oct 07 11:05:34 2008 +0200
    73.3 @@ -0,0 +1,68 @@
    73.4 +application.title=currency
    73.5 +application.vendor=apidesign.org
    73.6 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
    73.7 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
    73.8 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=default
    73.9 +build.classes.dir=${build.dir}/classes
   73.10 +build.classes.excludes=**/*.java,**/*.form
   73.11 +# This directory is removed when the project is cleaned:
   73.12 +build.dir=build
   73.13 +build.generated.dir=${build.dir}/generated
   73.14 +# Only compile against the classpath explicitly listed here:
   73.15 +build.sysclasspath=ignore
   73.16 +build.test.classes.dir=${build.dir}/test/classes
   73.17 +build.test.results.dir=${build.dir}/test/results
   73.18 +debug.classpath=\
   73.19 +    ${run.classpath}
   73.20 +debug.test.classpath=\
   73.21 +    ${run.test.classpath}
   73.22 +# This directory is removed when the project is cleaned:
   73.23 +dist.dir=dist
   73.24 +dist.jar=${dist.dir}/currency.jar
   73.25 +dist.javadoc.dir=${dist.dir}/javadoc
   73.26 +excludes=
   73.27 +file.reference.junit-4.4.jar=../../libs/junit-4.4.jar
   73.28 +file.reference.src-apifest08=..
   73.29 +includes=**
   73.30 +jar.compress=false
   73.31 +javac.classpath=
   73.32 +# Space-separated list of extra javac options
   73.33 +javac.compilerargs=
   73.34 +javac.deprecation=false
   73.35 +javac.source=1.5
   73.36 +javac.target=1.5
   73.37 +javac.test.classpath=\
   73.38 +    ${javac.classpath}:\
   73.39 +    ${build.classes.dir}:\
   73.40 +    ${file.reference.junit-4.4.jar}
   73.41 +javadoc.additionalparam=
   73.42 +javadoc.author=false
   73.43 +javadoc.encoding=
   73.44 +javadoc.noindex=false
   73.45 +javadoc.nonavbar=false
   73.46 +javadoc.notree=false
   73.47 +javadoc.private=false
   73.48 +javadoc.splitindex=true
   73.49 +javadoc.use=true
   73.50 +javadoc.version=false
   73.51 +javadoc.windowtitle=
   73.52 +jnlp.codebase.type=local
   73.53 +jnlp.codebase.url=file:/home/jarda/src/apifest08/currency/dist
   73.54 +jnlp.descriptor=application
   73.55 +jnlp.enabled=false
   73.56 +jnlp.offline-allowed=false
   73.57 +jnlp.signed=false
   73.58 +meta.inf.dir=${src.dir}/META-INF
   73.59 +platform.active=default_platform
   73.60 +run.classpath=\
   73.61 +    ${javac.classpath}:\
   73.62 +    ${build.classes.dir}
   73.63 +# Space-separated list of JVM arguments used when running the project
   73.64 +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
   73.65 +# or test-sys-prop.name=value to set system properties for unit tests):
   73.66 +run.jvmargs=
   73.67 +run.test.classpath=\
   73.68 +    ${javac.test.classpath}:\
   73.69 +    ${build.test.classes.dir}
   73.70 +src.dir=src
   73.71 +test.src.dir=test
    74.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    74.2 +++ b/task3/solution12/nbproject/project.xml	Tue Oct 07 11:05:34 2008 +0200
    74.3 @@ -0,0 +1,16 @@
    74.4 +<?xml version="1.0" encoding="UTF-8"?>
    74.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
    74.6 +    <type>org.netbeans.modules.java.j2seproject</type>
    74.7 +    <configuration>
    74.8 +        <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
    74.9 +            <name>Currency Convertor Solution 12</name>
   74.10 +            <minimum-ant-version>1.6.5</minimum-ant-version>
   74.11 +            <source-roots>
   74.12 +                <root id="src.dir"/>
   74.13 +            </source-roots>
   74.14 +            <test-roots>
   74.15 +                <root id="test.src.dir"/>
   74.16 +            </test-roots>
   74.17 +        </data>
   74.18 +    </configuration>
   74.19 +</project>
    75.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    75.2 +++ b/task3/solution12/src/org/apidesign/apifest08/currency/Convertor.java	Tue Oct 07 11:05:34 2008 +0200
    75.3 @@ -0,0 +1,184 @@
    75.4 +package org.apidesign.apifest08.currency;
    75.5 +
    75.6 +import java.util.ArrayList;
    75.7 +import java.util.Currency;
    75.8 +import java.util.Hashtable;
    75.9 +import java.util.List;
   75.10 +
   75.11 +import org.apidesign.apifest08.currency.exceptions.ConvertorException;
   75.12 +import org.apidesign.apifest08.currency.exceptions.InvalidCurrencyException;
   75.13 +import org.apidesign.apifest08.currency.exceptions.UnknownConvertorException;
   75.14 +
   75.15 +/**
   75.16 + * This is the skeleton class for your API. You need to make it public, so it is accessible to your client code
   75.17 + * (currently in Task1Test.java) file.
   75.18 + * <p>
   75.19 + * Feel free to create additional classes or rename this one, just keep all the API and its implementation in this
   75.20 + * package. Do not spread it outside to other packages.
   75.21 + */
   75.22 +public class Convertor {
   75.23 +
   75.24 +  private static Hashtable<String, ExchangeRate> exchangeRates;
   75.25 +
   75.26 +  private Hashtable<String, ExchangeRate> convertorInstanceExchangeRates; 
   75.27 +
   75.28 +  private Convertor(List<Currency> currencies) throws UnknownConvertorException {
   75.29 +	  convertorInstanceExchangeRates = new Hashtable<String, ExchangeRate>();
   75.30 +	  for (Currency currency1 : currencies) {
   75.31 +		for (Currency currency2 : currencies) {
   75.32 +			if(!currency1.getCurrencyCode().equals(currency2.getCurrencyCode())) {
   75.33 +				String key = currency1.getCurrencyCode() + currency2.getCurrencyCode();
   75.34 +				ExchangeRate exchangeRate = exchangeRates.get(key);
   75.35 +				convertorInstanceExchangeRates.put(key, exchangeRate);
   75.36 +			}
   75.37 +		}
   75.38 +	}
   75.39 +  }
   75.40 +
   75.41 +  /**
   75.42 +   * Sets convertor rate for selected currencies.
   75.43 +   * @param currency1
   75.44 +   *          one of the currencies we want to convert to/from
   75.45 +   * @param currency2
   75.46 +   *          the other currency
   75.47 +   * @param rate
   75.48 +   *          exchange rate from currency1 to currency2
   75.49 +   * @param unit
   75.50 +   *          unit of exchangeRate (USD->CZK - unit=1, you exchange one dollar, SKK->CZK unit=100, exchange rate is for
   75.51 +   *          100SKK)
   75.52 +   */
   75.53 +  public static void setConvertorRates(Currency currency1, Currency currency2, double rate, double unit) {
   75.54 +    if (currency1 == null || currency2 == null) {
   75.55 +      throw new ConvertorException("None of the currencies should be null!!!");
   75.56 +    }
   75.57 +
   75.58 +    if (rate <= 0 || unit <= 0) {
   75.59 +      throw new ConvertorException("Rate(" + rate + ") and unit(" + unit + ") has to be grater then zero!!!");
   75.60 +    }
   75.61 +
   75.62 +    if (exchangeRates == null) {
   75.63 +      exchangeRates = new Hashtable<String, ExchangeRate>();
   75.64 +    }
   75.65 +
   75.66 +    String key12 = currency1.getCurrencyCode() + currency2.getCurrencyCode();
   75.67 +    String key21 = currency2.getCurrencyCode() + currency1.getCurrencyCode();
   75.68 +    double recountedRate = (unit / rate) * unit;
   75.69 +
   75.70 +    exchangeRates.put(key12, new ExchangeRate(currency1, currency2, rate, unit));
   75.71 +    exchangeRates.put(key21, new ExchangeRate(currency2, currency1, recountedRate, unit));
   75.72 +
   75.73 +  }
   75.74 +  
   75.75 +  /**
   75.76 +   * Merge exchange rates of actual convertor with exchange rates from selected 
   75.77 +   * convertor. If there are same currencies in both convertors, these from selected
   75.78 +   * convertor rewrites these in actual convertor.
   75.79 +   * @param convertor convertor to merge with actual one
   75.80 +   * @return convertor with merged exchange rates 
   75.81 +   */
   75.82 +  public Convertor merge(Convertor convertor) {
   75.83 +	  convertorInstanceExchangeRates.putAll(convertor.getInstanceExchangeRates());
   75.84 +	  return this;
   75.85 +  }
   75.86 +
   75.87 +  /**
   75.88 +   * Creates new instance of convertor.
   75.89 +   * @param currency1
   75.90 +   *          one of the currencies we want to convert to/from
   75.91 +   * @param currency2
   75.92 +   *          the other currency
   75.93 +   * @return new instance of convertor
   75.94 +   * @throws UnknownConvertorException
   75.95 +   *           thrown if convertor for selected currencies has not been defined
   75.96 +   */
   75.97 +  public static Convertor getConvertorInstance(Currency... currencies) throws UnknownConvertorException {
   75.98 +   	List<Currency> currencyList = new ArrayList<Currency>();
   75.99 +   	
  75.100 +   	if(currencies.length < 2) {
  75.101 +   		throw new ConvertorException("To get convertor instance, you have to select at least two currencies!!!");
  75.102 +   	}
  75.103 +
  75.104 +   	for (Currency currency1 : currencies) {
  75.105 +   		for (Currency currency2 : currencies) {
  75.106 +   	   		if(currency1 == null || currency2 == null) {
  75.107 +   	   			throw new ConvertorException("None of the currencies should be null!!!");
  75.108 +   	   		}
  75.109 +   	   		
  75.110 +   			if(!currency1.getCurrencyCode().equals(currency2.getCurrencyCode())) {
  75.111 +   				String key12 = currency1.getCurrencyCode() + currency2.getCurrencyCode();
  75.112 +   				String key21 = currency2.getCurrencyCode() + currency1.getCurrencyCode();
  75.113 +   				if (!(exchangeRates.containsKey(key12) && exchangeRates.containsKey(key21))) {
  75.114 +   					throw new UnknownConvertorException("Selected convertor (" + currency1.getCurrencyCode() + "<->"
  75.115 +   		    			+ currency2.getCurrencyCode() + ") has not defined exchange rates!!!");
  75.116 +   				}
  75.117 +   			}
  75.118 +		}
  75.119 +   		
  75.120 +   		currencyList.add(currency1);
  75.121 +	}
  75.122 +    
  75.123 +    return new Convertor(currencyList);
  75.124 +  }
  75.125 +
  75.126 +  /**
  75.127 +   * Converts selected amout of selected currency to other currency of this convertor instance.
  75.128 +   * @param amount
  75.129 +   *          amount to convert
  75.130 +   * @param originalCurrency
  75.131 +   *          currency of this amount
  75.132 +   * @param newCurrency
  75.133 +   *          currency to which we want convert
  75.134 +   * @return converted amount
  75.135 +   * @throws InvalidCurrencyException
  75.136 +   *           while one or both currencies doesn't fit for this convertor
  75.137 +   */
  75.138 +  public double convert(double amount, Currency originalCurrency, Currency newCurrency) throws InvalidCurrencyException {
  75.139 +    ExchangeRate actualyUsedExchangeRate = null;
  75.140 +
  75.141 +    if (originalCurrency == null) {
  75.142 +      throw new ConvertorException("Original currency is null!!!");
  75.143 +    }
  75.144 +
  75.145 +    if (newCurrency == null) {
  75.146 +      throw new ConvertorException("Destination currency is null!!!");
  75.147 +    }
  75.148 +
  75.149 +    actualyUsedExchangeRate = getExchangeRate(originalCurrency, newCurrency);
  75.150 +
  75.151 +    return countResult(actualyUsedExchangeRate, amount);
  75.152 +  }
  75.153 +
  75.154 +  private double countResult(ExchangeRate actualyUsedExchangeRate, double amount) {
  75.155 +    return amount * actualyUsedExchangeRate.getRate() / actualyUsedExchangeRate.getUnit();
  75.156 +  }
  75.157 +
  75.158 +  /**
  75.159 +   * Decides the direction of conversion and returns instance of actual exchange rate.
  75.160 +   * @param actualCurrency
  75.161 +   *          actual currency we want to convert
  75.162 +   * @return actual exchange rate of this convertor for selected currency
  75.163 +   */
  75.164 +  private ExchangeRate getExchangeRate(Currency originalCurrency, Currency newCurrency) throws InvalidCurrencyException {
  75.165 +    ExchangeRate actualyUsedExchangeRate = null;
  75.166 +    
  75.167 +    String key = originalCurrency.getCurrencyCode() + newCurrency.getCurrencyCode();
  75.168 +
  75.169 +    if(convertorInstanceExchangeRates.containsKey(key)) {
  75.170 +      actualyUsedExchangeRate = convertorInstanceExchangeRates.get(key);
  75.171 +    } else {
  75.172 +      throw new InvalidCurrencyException("This convertor could not be used for converting selected currencies (" + originalCurrency.getCurrencyCode() + "->"
  75.173 +          + newCurrency.getCurrencyCode() + ") !!!");
  75.174 +    }
  75.175 +
  75.176 +    return actualyUsedExchangeRate;
  75.177 +  }
  75.178 +  
  75.179 +  /**
  75.180 +   * Returns exchange rates for actual instance of convertor.
  75.181 +   * @return exchange rates for actual instance of convertor
  75.182 +   */
  75.183 +  Hashtable<String, ExchangeRate> getInstanceExchangeRates() {
  75.184 +	  return convertorInstanceExchangeRates;
  75.185 +  }
  75.186 +  
  75.187 +}
    76.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    76.2 +++ b/task3/solution12/src/org/apidesign/apifest08/currency/ExchangeRate.java	Tue Oct 07 11:05:34 2008 +0200
    76.3 @@ -0,0 +1,35 @@
    76.4 +package org.apidesign.apifest08.currency;
    76.5 +
    76.6 +import java.util.Currency;
    76.7 +
    76.8 +public class ExchangeRate {
    76.9 +
   76.10 +  private Currency originalCurrency;
   76.11 +  private Currency newCurrency;
   76.12 +  private double unit;
   76.13 +  private double rate;
   76.14 +
   76.15 +  public ExchangeRate(Currency originalCurrency, Currency newCurrency, double rate, double unit) {
   76.16 +    this.newCurrency = newCurrency;
   76.17 +    this.originalCurrency = originalCurrency;
   76.18 +    this.rate = rate;
   76.19 +    this.unit = unit;
   76.20 +  }
   76.21 +
   76.22 +  public Currency getOriginalCurrency() {
   76.23 +    return originalCurrency;
   76.24 +  }
   76.25 +
   76.26 +  public Currency getNewCurrency() {
   76.27 +    return newCurrency;
   76.28 +  }
   76.29 +
   76.30 +  public double getUnit() {
   76.31 +    return unit;
   76.32 +  }
   76.33 +
   76.34 +  public double getRate() {
   76.35 +    return rate;
   76.36 +  }
   76.37 +
   76.38 +}
    77.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    77.2 +++ b/task3/solution12/src/org/apidesign/apifest08/currency/exceptions/ConvertorException.java	Tue Oct 07 11:05:34 2008 +0200
    77.3 @@ -0,0 +1,20 @@
    77.4 +package org.apidesign.apifest08.currency.exceptions;
    77.5 +
    77.6 +public class ConvertorException extends RuntimeException {
    77.7 +
    77.8 +  public ConvertorException() {
    77.9 +  }
   77.10 +
   77.11 +  public ConvertorException(String message) {
   77.12 +    super(message);
   77.13 +  }
   77.14 +
   77.15 +  public ConvertorException(Throwable cause) {
   77.16 +    super(cause);
   77.17 +  }
   77.18 +
   77.19 +  public ConvertorException(String message, Throwable cause) {
   77.20 +    super(message, cause);
   77.21 +  }
   77.22 +
   77.23 +}
    78.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    78.2 +++ b/task3/solution12/src/org/apidesign/apifest08/currency/exceptions/InvalidCurrencyException.java	Tue Oct 07 11:05:34 2008 +0200
    78.3 @@ -0,0 +1,20 @@
    78.4 +package org.apidesign.apifest08.currency.exceptions;
    78.5 +
    78.6 +public class InvalidCurrencyException extends Exception {
    78.7 +
    78.8 +  public InvalidCurrencyException() {
    78.9 +  }
   78.10 +
   78.11 +  public InvalidCurrencyException(String message) {
   78.12 +    super(message);
   78.13 +  }
   78.14 +
   78.15 +  public InvalidCurrencyException(Throwable cause) {
   78.16 +    super(cause);
   78.17 +  }
   78.18 +
   78.19 +  public InvalidCurrencyException(String message, Throwable cause) {
   78.20 +    super(message, cause);
   78.21 +  }
   78.22 +
   78.23 +}
    79.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    79.2 +++ b/task3/solution12/src/org/apidesign/apifest08/currency/exceptions/UnknownConvertorException.java	Tue Oct 07 11:05:34 2008 +0200
    79.3 @@ -0,0 +1,20 @@
    79.4 +package org.apidesign.apifest08.currency.exceptions;
    79.5 +
    79.6 +public class UnknownConvertorException extends Exception {
    79.7 +
    79.8 +  public UnknownConvertorException() {
    79.9 +  }
   79.10 +
   79.11 +  public UnknownConvertorException(String message) {
   79.12 +    super(message);
   79.13 +  }
   79.14 +
   79.15 +  public UnknownConvertorException(Throwable cause) {
   79.16 +    super(cause);
   79.17 +  }
   79.18 +
   79.19 +  public UnknownConvertorException(String message, Throwable cause) {
   79.20 +    super(message, cause);
   79.21 +  }
   79.22 +
   79.23 +}
    80.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    80.2 +++ b/task3/solution12/test/org/apidesign/apifest08/test/Task1Test.java	Tue Oct 07 11:05:34 2008 +0200
    80.3 @@ -0,0 +1,174 @@
    80.4 +package org.apidesign.apifest08.test;
    80.5 +
    80.6 +import java.util.Currency;
    80.7 +
    80.8 +import junit.framework.TestCase;
    80.9 +
   80.10 +import org.apidesign.apifest08.currency.Convertor;
   80.11 +import org.apidesign.apifest08.currency.exceptions.InvalidCurrencyException;
   80.12 +import org.apidesign.apifest08.currency.exceptions.UnknownConvertorException;
   80.13 +
   80.14 +/**
   80.15 + * Finish the Convertor API, and then write bodies of methods inside of this class to match the given tasks. To fullfil
   80.16 + * your task, use the API define in the <code>org.apidesign.apifest08.currency</code> package. Do not you reflection, or
   80.17 + * other hacks as your code shall run without any runtime permissions.
   80.18 + */
   80.19 +public class Task1Test extends TestCase {
   80.20 +  public Task1Test(String testName) {
   80.21 +    super(testName);
   80.22 +  }
   80.23 +
   80.24 +  @Override
   80.25 +  protected void setUp() throws Exception {
   80.26 +  }
   80.27 +
   80.28 +  @Override
   80.29 +  protected void tearDown() throws Exception {
   80.30 +  }
   80.31 +
   80.32 +  //
   80.33 +  // Imagine that there are three parts of the whole system:
   80.34 +  // 1. there is someone who knows the current exchange rate
   80.35 +  // 2. there is someone who wants to do the conversion
   80.36 +  // 3. there is the API between 1. and 2. which allows them to communicate
   80.37 +  // Please design such API
   80.38 +  //
   80.39 +
   80.40 +  /**
   80.41 +   * Create convertor that understands two currencies, CZK and USD. Make 1 USD == 17 CZK. This is a method provided for
   80.42 +   * #1 group - e.g. those that know the exchange rate. They somehow need to create the objects from the API and tell
   80.43 +   * them the exchange rate. The API itself knows nothing about any rates, before the createCZKtoUSD method is called.
   80.44 +   * Creation of the convertor shall not require subclassing of any class or interface on the client side.
   80.45 +   * @return prepared convertor ready for converting USD to CZK and CZK to USD
   80.46 +   */
   80.47 +  public static Convertor createCZKtoUSD() {
   80.48 +    // set exchange rates
   80.49 +    Convertor.setConvertorRates(Currency.getInstance("USD"), Currency.getInstance("CZK"), 17d, 1d);
   80.50 +
   80.51 +    // create new instance
   80.52 +    Convertor convertor = null;
   80.53 +    try {
   80.54 +      convertor = Convertor.getConvertorInstance(Currency.getInstance("USD"), Currency.getInstance("CZK"));
   80.55 +    } catch (UnknownConvertorException e) {
   80.56 +      e.printStackTrace();
   80.57 +    }
   80.58 +
   80.59 +    return convertor;
   80.60 +  }
   80.61 +
   80.62 +  /**
   80.63 +   * Create convertor that understands two currencies, CZK and SKK. Make 100 SKK == 80 CZK. Again this is method for the
   80.64 +   * #1 group - it knows the exchange rate, and needs to use the API to create objects with the exchange rate. Anyone
   80.65 +   * shall be ready to call this method without any other method being called previously. The API itself shall know
   80.66 +   * nothing about any rates, before this method is called. Creation of the convertor shall not require subclassing of
   80.67 +   * any class or interface on the client side.
   80.68 +   * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
   80.69 +   */
   80.70 +  public static Convertor createSKKtoCZK() {
   80.71 +    // set exchange rates
   80.72 +    Convertor.setConvertorRates(Currency.getInstance("SKK"), Currency.getInstance("CZK"), 80d, 100d);
   80.73 +
   80.74 +    // create new instance
   80.75 +    Convertor convertor = null;
   80.76 +    try {
   80.77 +      convertor = Convertor.getConvertorInstance(Currency.getInstance("SKK"), Currency.getInstance("CZK"));
   80.78 +    } catch (UnknownConvertorException e) {
   80.79 +      e.printStackTrace();
   80.80 +    }
   80.81 +
   80.82 +    return convertor;
   80.83 +  }
   80.84 +
   80.85 +  //
   80.86 +  // now the methods for group #2 follow:
   80.87 +  // this group knows nothing about exchange rates, but knows how to use
   80.88 +  // the API to do conversions. It somehow (by calling one of the factory
   80.89 +  // methods) gets objects from the API and uses them to do the conversions.
   80.90 +  //
   80.91 +
   80.92 +  /**
   80.93 +   * Use the convertor from <code>createCZKtoUSD</code> method and do few conversions with it.
   80.94 +   */
   80.95 +  public void testCurrencyCZKUSD() throws Exception {
   80.96 +    Convertor c = createCZKtoUSD();
   80.97 +    // convert $5 to CZK using c:
   80.98 +    double result = c.convert(5, Currency.getInstance("USD"), Currency.getInstance("CZK"));
   80.99 +    assertEquals("Result is not 85 CZK", 85.0, result);
  80.100 +
  80.101 +    // convert $8 to CZK
  80.102 +    result = c.convert(8, Currency.getInstance("USD"), Currency.getInstance("CZK"));
  80.103 +    assertEquals("Result is not 136 CZK", 136.0, result);
  80.104 +
  80.105 +    // convert 1003CZK to USD
  80.106 +    result = c.convert(1003, Currency.getInstance("CZK"), Currency.getInstance("USD"));
  80.107 +    assertEquals("Result is not 59 USD", 59.0, result);
  80.108 +  }
  80.109 +
  80.110 +  /**
  80.111 +   * Use the convertor from <code>createSKKtoCZK</code> method and do few conversions with it.
  80.112 +   */
  80.113 +  public void testCurrencySKKCZK() throws Exception {
  80.114 +    Convertor c = createSKKtoCZK();
  80.115 +
  80.116 +    // convert 16CZK using c:
  80.117 +    double result = c.convert(16, Currency.getInstance("CZK"), Currency.getInstance("SKK"));
  80.118 +    assertEquals("Result is not 20 SKK", 20.0, result);
  80.119 +
  80.120 +    // convert 500SKK to CZK
  80.121 +    result = c.convert(500, Currency.getInstance("SKK"), Currency.getInstance("CZK"));
  80.122 +    assertEquals("Result is not 400 CZK", 400.0, result);
  80.123 +  }
  80.124 +
  80.125 +  /**
  80.126 +   * Verify that the CZK to USD convertor knows nothing about SKK.
  80.127 +   */
  80.128 +  public void testCannotConvertToSKKwithCZKUSDConvertor() throws Exception {
  80.129 +    Convertor c = createCZKtoUSD();
  80.130 +    boolean exceptionThrown = false;
  80.131 +
  80.132 +    // convert $5 to SKK, the API shall say this is not possible
  80.133 +    try {
  80.134 +      c.convert(5, Currency.getInstance("USD"), Currency.getInstance("SKK"));
  80.135 +      exceptionThrown = false;
  80.136 +    } catch (InvalidCurrencyException e) {
  80.137 +      exceptionThrown = true;
  80.138 +    }
  80.139 +    assertEquals("It should be impossible to convert to SKK with USD->CZK convertor", true, exceptionThrown);
  80.140 +
  80.141 +    // convert 500 SKK to CZK, the API shall say this is not possible
  80.142 +    try {
  80.143 +      c.convert(500, Currency.getInstance("SKK"), Currency.getInstance("CZK"));
  80.144 +      exceptionThrown = false;
  80.145 +    } catch (InvalidCurrencyException e) {
  80.146 +      exceptionThrown = true;
  80.147 +    }
  80.148 +    assertEquals("It should be impossible to convert from SKK with USD->CZK convertor", true, exceptionThrown);
  80.149 +
  80.150 +  }
  80.151 +
  80.152 +  /**
  80.153 +   * Verify that the CZK to SKK convertor knows nothing about USD.
  80.154 +   */
  80.155 +  public void testCannotConvertToSKKwithSKKCZKConvertor() throws Exception {
  80.156 +    Convertor c = createSKKtoCZK();
  80.157 +    boolean exceptionThrown = false;
  80.158 +
  80.159 +    // convert $5 to SKK, the API shall say this is not possible
  80.160 +    try {
  80.161 +      c.convert(5, Currency.getInstance("USD"), Currency.getInstance("SKK"));
  80.162 +      exceptionThrown = false;
  80.163 +    } catch (InvalidCurrencyException e) {
  80.164 +      exceptionThrown = true;
  80.165 +    }
  80.166 +    assertEquals("It should be impossible to convert form USD with SKK->CZK convertor", true, exceptionThrown);
  80.167 +
  80.168 +    // convert 500 CZK to USD, the API shall say this is not possible
  80.169 +    try {
  80.170 +      c.convert(500, Currency.getInstance("CZK"), Currency.getInstance("USD"));
  80.171 +      exceptionThrown = false;
  80.172 +    } catch (InvalidCurrencyException e) {
  80.173 +      exceptionThrown = true;
  80.174 +    }
  80.175 +    assertEquals("It should be impossible to convert to USD with SKK->CZK convertor", true, exceptionThrown);
  80.176 +  }
  80.177 +}
    81.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    81.2 +++ b/task3/solution12/test/org/apidesign/apifest08/test/Task2Test.java	Tue Oct 07 11:05:34 2008 +0200
    81.3 @@ -0,0 +1,132 @@
    81.4 +package org.apidesign.apifest08.test;
    81.5 +
    81.6 +import java.util.Currency;
    81.7 +
    81.8 +import junit.framework.TestCase;
    81.9 +
   81.10 +import org.apidesign.apifest08.currency.Convertor;
   81.11 +import org.apidesign.apifest08.currency.exceptions.UnknownConvertorException;
   81.12 +
   81.13 +/** There are many currencies around the world and many banks manipulate
   81.14 + * with more than one or two at the same time. As banks are usually the
   81.15 + * best paying clients, which is true even in case of your Convertor API,
   81.16 + * it is reasonable to listen to their requests.
   81.17 + * <p>
   81.18 + * The quest for today is to enhance your existing convertor API to hold
   81.19 + * information about many currencies and allow conversions between any of them.
   81.20 + * Also, as conversion rates for diferent currencies usually arise from various
   81.21 + * bank departments, there is another important need. There is a need to
   81.22 + * compose two convertors into one by merging all the information about
   81.23 + * currencies they know about.
   81.24 + */
   81.25 +public class Task2Test extends TestCase {
   81.26 +    public Task2Test(String testName) {
   81.27 +        super(testName);
   81.28 +    }
   81.29 +
   81.30 +    @Override
   81.31 +    protected void setUp() throws Exception {
   81.32 +    }
   81.33 +
   81.34 +    @Override
   81.35 +    protected void tearDown() throws Exception {
   81.36 +    }
   81.37 +
   81.38 +    // As in Task1Test, keep in mind, that there are three parts
   81.39 +    // of the whole system:
   81.40 +    // 1. there is someone who knows the current exchange rate
   81.41 +    // 2. there is someone who wants to do the conversion
   81.42 +    // 3. there is the API between 1. and 2. which allows them to communicate
   81.43 +    // 
   81.44 +    // Please backward compatibly enhance your existing API to support following
   81.45 +    // usecases:
   81.46 +    //
   81.47 +    
   81.48 +    /** Create convertor that understands two currencies, CZK and
   81.49 +     *  SKK. Make 100 SKK == 75 CZK. This is method for the group of users that
   81.50 +     *  knows the exchange rate, and needs to use the API to create objects
   81.51 +     *  with the exchange rate. Anyone shall be ready to call this method without
   81.52 +     *  any other method being called previously. The API itself shall know
   81.53 +     *  nothing about any rates, before this method is called.
   81.54 +     */
   81.55 +    public static Convertor createTripleConvertor() {
   81.56 +        // Rates: 1USD = 15CZK
   81.57 +        // Rates: 1USD = 20SKK
   81.58 +        // Rates: 75CZK = 100SKK
   81.59 +    	// set exchange rates
   81.60 +    	Convertor.setConvertorRates(Currency.getInstance("USD"), Currency.getInstance("CZK"), 15, 1);
   81.61 +    	Convertor.setConvertorRates(Currency.getInstance("USD"), Currency.getInstance("SKK"), 20, 1);
   81.62 +    	Convertor.setConvertorRates(Currency.getInstance("SKK"), Currency.getInstance("CZK"), 75, 100);
   81.63 +        
   81.64 +        // create new instance
   81.65 +        Convertor convertor = null;
   81.66 +        try {
   81.67 +          convertor = Convertor.getConvertorInstance(Currency.getInstance("USD"), Currency.getInstance("SKK"), Currency.getInstance("CZK"));
   81.68 +        } catch (UnknownConvertorException e) {
   81.69 +          e.printStackTrace();
   81.70 +        }
   81.71 +    	return convertor;
   81.72 +    }
   81.73 +
   81.74 +    /** Define convertor that understands three currencies. Use it.
   81.75 +     */
   81.76 +    public void testConvertorForUSDandCZKandSKK() throws Exception {
   81.77 +        Convertor c = createTripleConvertor();
   81.78 +
   81.79 +        // convert $5 to CZK using c:
   81.80 +        double result = c.convert(5d, Currency.getInstance("USD"), Currency.getInstance("CZK"));
   81.81 +        assertEquals("Result is not 75 CZK", 75.0, result);
   81.82 +
   81.83 +        // convert $5 to SKK using c:
   81.84 +        result = c.convert(5d, Currency.getInstance("USD"), Currency.getInstance("SKK"));
   81.85 +        assertEquals("Result is not 100 SKK", 100.0, result);
   81.86 +
   81.87 +        // convert 200SKK to CZK using c:
   81.88 +        result = c.convert(200d, Currency.getInstance("SKK"), Currency.getInstance("CZK"));
   81.89 +        assertEquals("Result is not 150 CZK", 150.0, result);
   81.90 +
   81.91 +        // convert 200SKK to USK using c:
   81.92 +        result = c.convert(200d, Currency.getInstance("SKK"), Currency.getInstance("USD"));
   81.93 +        assertEquals("Result is not 10 USD", 10.0, result);
   81.94 +    }
   81.95 +
   81.96 +    /** Merge all currency rates of convertor 1 with convertor 2.
   81.97 +     * Implement this using your API, preferably this method just delegates
   81.98 +     * into some API method which does the actual work, without requiring
   81.99 +     * API clients to code anything complex.
  81.100 +     */
  81.101 +    public static Convertor merge(Convertor one, Convertor two) {
  81.102 +        return one.merge(two);
  81.103 +    }
  81.104 +
  81.105 +    /** Join the convertors from previous task, Task1Test and show that it
  81.106 +     * can be used to do reasonable conversions.
  81.107 +     */
  81.108 +    public void testConvertorComposition() throws Exception {
  81.109 +        Convertor c = merge(
  81.110 +            Task1Test.createCZKtoUSD(),
  81.111 +            Task1Test.createSKKtoCZK()
  81.112 +        );
  81.113 +
  81.114 +        // convert $5 to CZK using c:
  81.115 +        double result = c.convert(5d, Currency.getInstance("USD"), Currency.getInstance("CZK"));
  81.116 +        assertEquals("Result is not 85 CZK", 85.0, result);
  81.117 +
  81.118 +        // convert $8 to CZK using c:
  81.119 +        result = c.convert(8d, Currency.getInstance("USD"), Currency.getInstance("CZK"));
  81.120 +        assertEquals("Result is not 136 CZK", 136.0, result);
  81.121 +
  81.122 +        // convert 1003CZK to USD using c:
  81.123 +        result = c.convert(1003d, Currency.getInstance("CZK"), Currency.getInstance("USD"));
  81.124 +        assertEquals("Result is not 59 USD", 59.0, result);
  81.125 +
  81.126 +        // convert 16CZK using c:
  81.127 +        result = c.convert(16d, Currency.getInstance("CZK"), Currency.getInstance("SKK"));
  81.128 +        assertEquals("Result is not 20 SKK", 20.0, result);
  81.129 +
  81.130 +        // convert 500SKK to CZK using c:
  81.131 +        result = c.convert(500d, Currency.getInstance("SKK"), Currency.getInstance("CZK"));
  81.132 +        assertEquals("Result is not 400 CZK", 400.0, result);
  81.133 +
  81.134 +    }
  81.135 +}
    82.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    82.2 +++ b/task3/solution13/build.xml	Tue Oct 07 11:05:34 2008 +0200
    82.3 @@ -0,0 +1,69 @@
    82.4 +<?xml version="1.0" encoding="UTF-8"?>
    82.5 +<!-- You may freely edit this file. See commented blocks below for -->
    82.6 +<!-- some examples of how to customize the build. -->
    82.7 +<!-- (If you delete it and reopen the project it will be recreated.) -->
    82.8 +<project name="currency" default="default" basedir=".">
    82.9 +    <description>Builds, tests, and runs the project.</description>
   82.10 +    <import file="nbproject/build-impl.xml"/>
   82.11 +    <!--
   82.12 +
   82.13 +    There exist several targets which are by default empty and which can be 
   82.14 +    used for execution of your tasks. These targets are usually executed 
   82.15 +    before and after some main targets. They are: 
   82.16 +
   82.17 +      -pre-init:                 called before initialization of project properties
   82.18 +      -post-init:                called after initialization of project properties
   82.19 +      -pre-compile:              called before javac compilation
   82.20 +      -post-compile:             called after javac compilation
   82.21 +      -pre-compile-single:       called before javac compilation of single file
   82.22 +      -post-compile-single:      called after javac compilation of single file
   82.23 +      -pre-compile-test:         called before javac compilation of JUnit tests
   82.24 +      -post-compile-test:        called after javac compilation of JUnit tests
   82.25 +      -pre-compile-test-single:  called before javac compilation of single JUnit test
   82.26 +      -post-compile-test-single: called after javac compilation of single JUunit test
   82.27 +      -pre-jar:                  called before JAR building
   82.28 +      -post-jar:                 called after JAR building
   82.29 +      -post-clean:               called after cleaning build products
   82.30 +
   82.31 +    (Targets beginning with '-' are not intended to be called on their own.)
   82.32 +
   82.33 +    Example of inserting an obfuscator after compilation could look like this:
   82.34 +
   82.35 +        <target name="-post-compile">
   82.36 +            <obfuscate>
   82.37 +                <fileset dir="${build.classes.dir}"/>
   82.38 +            </obfuscate>
   82.39 +        </target>
   82.40 +
   82.41 +    For list of available properties check the imported 
   82.42 +    nbproject/build-impl.xml file. 
   82.43 +
   82.44 +
   82.45 +    Another way to customize the build is by overriding existing main targets.
   82.46 +    The targets of interest are: 
   82.47 +
   82.48 +      -init-macrodef-javac:     defines macro for javac compilation
   82.49 +      -init-macrodef-junit:     defines macro for junit execution
   82.50 +      -init-macrodef-debug:     defines macro for class debugging
   82.51 +      -init-macrodef-java:      defines macro for class execution
   82.52 +      -do-jar-with-manifest:    JAR building (if you are using a manifest)
   82.53 +      -do-jar-without-manifest: JAR building (if you are not using a manifest)
   82.54 +      run:                      execution of project 
   82.55 +      -javadoc-build:           Javadoc generation
   82.56 +      test-report:              JUnit report generation
   82.57 +
   82.58 +    An example of overriding the target for project execution could look like this:
   82.59 +
   82.60 +        <target name="run" depends="currency-impl.jar">
   82.61 +            <exec dir="bin" executable="launcher.exe">
   82.62 +                <arg file="${dist.jar}"/>
   82.63 +            </exec>
   82.64 +        </target>
   82.65 +
   82.66 +    Notice that the overridden target depends on the jar target and not only on 
   82.67 +    the compile target as the regular run target does. Again, for a list of available 
   82.68 +    properties which you can use, check the target you are overriding in the
   82.69 +    nbproject/build-impl.xml file. 
   82.70 +
   82.71 +    -->
   82.72 +</project>
    83.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    83.2 +++ b/task3/solution13/nbproject/build-impl.xml	Tue Oct 07 11:05:34 2008 +0200
    83.3 @@ -0,0 +1,642 @@
    83.4 +<?xml version="1.0" encoding="UTF-8"?>
    83.5 +<!--
    83.6 +*** GENERATED FROM project.xml - DO NOT EDIT  ***
    83.7 +***         EDIT ../build.xml INSTEAD         ***
    83.8 +
    83.9 +For the purpose of easier reading the script
   83.10 +is divided into following sections:
   83.11 +
   83.12 +  - initialization
   83.13 +  - compilation
   83.14 +  - jar
   83.15 +  - execution
   83.16 +  - debugging
   83.17 +  - javadoc
   83.18 +  - junit compilation
   83.19 +  - junit execution
   83.20 +  - junit debugging
   83.21 +  - applet
   83.22 +  - cleanup
   83.23 +
   83.24 +        -->
   83.25 +<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="Currency_Convertor_Solution_13-impl">
   83.26 +    <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
   83.27 +    <!-- 
   83.28 +                ======================
   83.29 +                INITIALIZATION SECTION 
   83.30 +                ======================
   83.31 +            -->
   83.32 +    <target name="-pre-init">
   83.33 +        <!-- Empty placeholder for easier customization. -->
   83.34 +        <!-- You can override this target in the ../build.xml file. -->
   83.35 +    </target>
   83.36 +    <target depends="-pre-init" name="-init-private">
   83.37 +        <property file="nbproject/private/config.properties"/>
   83.38 +        <property file="nbproject/private/configs/${config}.properties"/>
   83.39 +        <property file="nbproject/private/private.properties"/>
   83.40 +    </target>
   83.41 +    <target depends="-pre-init,-init-private" name="-init-user">
   83.42 +        <property file="${user.properties.file}"/>
   83.43 +        <!-- The two properties below are usually overridden -->
   83.44 +        <!-- by the active platform. Just a fallback. -->
   83.45 +        <property name="default.javac.source" value="1.4"/>
   83.46 +        <property name="default.javac.target" value="1.4"/>
   83.47 +    </target>
   83.48 +    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
   83.49 +        <property file="nbproject/configs/${config}.properties"/>
   83.50 +        <property file="nbproject/project.properties"/>
   83.51 +    </target>
   83.52 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
   83.53 +        <available file="${manifest.file}" property="manifest.available"/>
   83.54 +        <condition property="manifest.available+main.class">
   83.55 +            <and>
   83.56 +                <isset property="manifest.available"/>
   83.57 +                <isset property="main.class"/>
   83.58 +                <not>
   83.59 +                    <equals arg1="${main.class}" arg2="" trim="true"/>
   83.60 +                </not>
   83.61 +            </and>
   83.62 +        </condition>
   83.63 +        <condition property="manifest.available+main.class+mkdist.available">
   83.64 +            <and>
   83.65 +                <istrue value="${manifest.available+main.class}"/>
   83.66 +                <isset property="libs.CopyLibs.classpath"/>
   83.67 +            </and>
   83.68 +        </condition>
   83.69 +        <condition property="have.tests">
   83.70 +            <or>
   83.71 +                <available file="${test.src.dir}"/>
   83.72 +            </or>
   83.73 +        </condition>
   83.74 +        <condition property="have.sources">
   83.75 +            <or>
   83.76 +                <available file="${src.dir}"/>
   83.77 +            </or>
   83.78 +        </condition>
   83.79 +        <condition property="netbeans.home+have.tests">
   83.80 +            <and>
   83.81 +                <isset property="netbeans.home"/>
   83.82 +                <isset property="have.tests"/>
   83.83 +            </and>
   83.84 +        </condition>
   83.85 +        <condition property="no.javadoc.preview">
   83.86 +            <and>
   83.87 +                <isset property="javadoc.preview"/>
   83.88 +                <isfalse value="${javadoc.preview}"/>
   83.89 +            </and>
   83.90 +        </condition>
   83.91 +        <property name="run.jvmargs" value=""/>
   83.92 +        <property name="javac.compilerargs" value=""/>
   83.93 +        <property name="work.dir" value="${basedir}"/>
   83.94 +        <condition property="no.deps">
   83.95 +            <and>
   83.96 +                <istrue value="${no.dependencies}"/>
   83.97 +            </and>
   83.98 +        </condition>
   83.99 +        <property name="javac.debug" value="true"/>
  83.100 +        <property name="javadoc.preview" value="true"/>
  83.101 +        <property name="application.args" value=""/>
  83.102 +        <property name="source.encoding" value="${file.encoding}"/>
  83.103 +        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
  83.104 +            <and>
  83.105 +                <isset property="javadoc.encoding"/>
  83.106 +                <not>
  83.107 +                    <equals arg1="${javadoc.encoding}" arg2=""/>
  83.108 +                </not>
  83.109 +            </and>
  83.110 +        </condition>
  83.111 +        <property name="javadoc.encoding.used" value="${source.encoding}"/>
  83.112 +        <property name="includes" value="**"/>
  83.113 +        <property name="excludes" value=""/>
  83.114 +        <property name="do.depend" value="false"/>
  83.115 +        <condition property="do.depend.true">
  83.116 +            <istrue value="${do.depend}"/>
  83.117 +        </condition>
  83.118 +        <condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
  83.119 +            <and>
  83.120 +                <isset property="jaxws.endorsed.dir"/>
  83.121 +                <available file="nbproject/jaxws-build.xml"/>
  83.122 +            </and>
  83.123 +        </condition>
  83.124 +    </target>
  83.125 +    <target name="-post-init">
  83.126 +        <!-- Empty placeholder for easier customization. -->
  83.127 +        <!-- You can override this target in the ../build.xml file. -->
  83.128 +    </target>
  83.129 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
  83.130 +        <fail unless="src.dir">Must set src.dir</fail>
  83.131 +        <fail unless="test.src.dir">Must set test.src.dir</fail>
  83.132 +        <fail unless="build.dir">Must set build.dir</fail>
  83.133 +        <fail unless="dist.dir">Must set dist.dir</fail>
  83.134 +        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
  83.135 +        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
  83.136 +        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
  83.137 +        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
  83.138 +        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
  83.139 +        <fail unless="dist.jar">Must set dist.jar</fail>
  83.140 +    </target>
  83.141 +    <target name="-init-macrodef-property">
  83.142 +        <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
  83.143 +            <attribute name="name"/>
  83.144 +            <attribute name="value"/>
  83.145 +            <sequential>
  83.146 +                <property name="@{name}" value="${@{value}}"/>
  83.147 +            </sequential>
  83.148 +        </macrodef>
  83.149 +    </target>
  83.150 +    <target name="-init-macrodef-javac">
  83.151 +        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
  83.152 +            <attribute default="${src.dir}" name="srcdir"/>
  83.153 +            <attribute default="${build.classes.dir}" name="destdir"/>
  83.154 +            <attribute default="${javac.classpath}" name="classpath"/>
  83.155 +            <attribute default="${includes}" name="includes"/>
  83.156 +            <attribute default="${excludes}" name="excludes"/>
  83.157 +            <attribute default="${javac.debug}" name="debug"/>
  83.158 +            <attribute default="" name="sourcepath"/>
  83.159 +            <element name="customize" optional="true"/>
  83.160 +            <sequential>
  83.161 +                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
  83.162 +                    <classpath>
  83.163 +                        <path path="@{classpath}"/>
  83.164 +                    </classpath>
  83.165 +                    <compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
  83.166 +                    <customize/>
  83.167 +                </javac>
  83.168 +            </sequential>
  83.169 +        </macrodef>
  83.170 +        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
  83.171 +            <attribute default="${src.dir}" name="srcdir"/>
  83.172 +            <attribute default="${build.classes.dir}" name="destdir"/>
  83.173 +            <attribute default="${javac.classpath}" name="classpath"/>
  83.174 +            <sequential>
  83.175 +                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
  83.176 +                    <classpath>
  83.177 +                        <path path="@{classpath}"/>
  83.178 +                    </classpath>
  83.179 +                </depend>
  83.180 +            </sequential>
  83.181 +        </macrodef>
  83.182 +        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
  83.183 +            <attribute default="${build.classes.dir}" name="destdir"/>
  83.184 +            <sequential>
  83.185 +                <fail unless="javac.includes">Must set javac.includes</fail>
  83.186 +                <pathconvert pathsep="," property="javac.includes.binary">
  83.187 +                    <path>
  83.188 +                        <filelist dir="@{destdir}" files="${javac.includes}"/>
  83.189 +                    </path>
  83.190 +                    <globmapper from="*.java" to="*.class"/>
  83.191 +                </pathconvert>
  83.192 +                <delete>
  83.193 +                    <files includes="${javac.includes.binary}"/>
  83.194 +                </delete>
  83.195 +            </sequential>
  83.196 +        </macrodef>
  83.197 +    </target>
  83.198 +    <target name="-init-macrodef-junit">
  83.199 +        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
  83.200 +            <attribute default="${includes}" name="includes"/>
  83.201 +            <attribute default="${excludes}" name="excludes"/>
  83.202 +            <attribute default="**" name="testincludes"/>
  83.203 +            <sequential>
  83.204 +                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
  83.205 +                    <batchtest todir="${build.test.results.dir}">
  83.206 +                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
  83.207 +                            <filename name="@{testincludes}"/>
  83.208 +                        </fileset>
  83.209 +                    </batchtest>
  83.210 +                    <classpath>
  83.211 +                        <path path="${run.test.classpath}"/>
  83.212 +                    </classpath>
  83.213 +                    <syspropertyset>
  83.214 +                        <propertyref prefix="test-sys-prop."/>
  83.215 +                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
  83.216 +                    </syspropertyset>
  83.217 +                    <formatter type="brief" usefile="false"/>
  83.218 +                    <formatter type="xml"/>
  83.219 +                    <jvmarg line="${run.jvmargs}"/>
  83.220 +                </junit>
  83.221 +            </sequential>
  83.222 +        </macrodef>
  83.223 +    </target>
  83.224 +    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
  83.225 +        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
  83.226 +            <attribute default="${main.class}" name="name"/>
  83.227 +            <attribute default="${debug.classpath}" name="classpath"/>
  83.228 +            <attribute default="" name="stopclassname"/>
  83.229 +            <sequential>
  83.230 +                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
  83.231 +                    <classpath>
  83.232 +                        <path path="@{classpath}"/>
  83.233 +                    </classpath>
  83.234 +                </nbjpdastart>
  83.235 +            </sequential>
  83.236 +        </macrodef>
  83.237 +        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
  83.238 +            <attribute default="${build.classes.dir}" name="dir"/>
  83.239 +            <sequential>
  83.240 +                <nbjpdareload>
  83.241 +                    <fileset dir="@{dir}" includes="${fix.classes}">
  83.242 +                        <include name="${fix.includes}*.class"/>
  83.243 +                    </fileset>
  83.244 +                </nbjpdareload>
  83.245 +            </sequential>
  83.246 +        </macrodef>
  83.247 +    </target>
  83.248 +    <target name="-init-debug-args">
  83.249 +        <property name="version-output" value="java version &quot;${ant.java.version}"/>
  83.250 +        <condition property="have-jdk-older-than-1.4">
  83.251 +            <or>
  83.252 +                <contains string="${version-output}" substring="java version &quot;1.0"/>
  83.253 +                <contains string="${version-output}" substring="java version &quot;1.1"/>
  83.254 +                <contains string="${version-output}" substring="java version &quot;1.2"/>
  83.255 +                <contains string="${version-output}" substring="java version &quot;1.3"/>
  83.256 +            </or>
  83.257 +        </condition>
  83.258 +        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
  83.259 +            <istrue value="${have-jdk-older-than-1.4}"/>
  83.260 +        </condition>
  83.261 +        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
  83.262 +            <os family="windows"/>
  83.263 +        </condition>
  83.264 +        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
  83.265 +            <isset property="debug.transport"/>
  83.266 +        </condition>
  83.267 +    </target>
  83.268 +    <target depends="-init-debug-args" name="-init-macrodef-debug">
  83.269 +        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
  83.270 +            <attribute default="${main.class}" name="classname"/>
  83.271 +            <attribute default="${debug.classpath}" name="classpath"/>
  83.272 +            <element name="customize" optional="true"/>
  83.273 +            <sequential>
  83.274 +                <java classname="@{classname}" dir="${work.dir}" fork="true">
  83.275 +                    <jvmarg line="${debug-args-line}"/>
  83.276 +                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
  83.277 +                    <jvmarg line="${run.jvmargs}"/>
  83.278 +                    <classpath>
  83.279 +                        <path path="@{classpath}"/>
  83.280 +                    </classpath>
  83.281 +                    <syspropertyset>
  83.282 +                        <propertyref prefix="run-sys-prop."/>
  83.283 +                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
  83.284 +                    </syspropertyset>
  83.285 +                    <customize/>
  83.286 +                </java>
  83.287 +            </sequential>
  83.288 +        </macrodef>
  83.289 +    </target>
  83.290 +    <target name="-init-macrodef-java">
  83.291 +        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
  83.292 +            <attribute default="${main.class}" name="classname"/>
  83.293 +            <element name="customize" optional="true"/>
  83.294 +            <sequential>
  83.295 +                <java classname="@{classname}" dir="${work.dir}" fork="true">
  83.296 +                    <jvmarg line="${run.jvmargs}"/>
  83.297 +                    <classpath>
  83.298 +                        <path path="${run.classpath}"/>
  83.299 +                    </classpath>
  83.300 +                    <syspropertyset>
  83.301 +                        <propertyref prefix="run-sys-prop."/>
  83.302 +                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
  83.303 +                    </syspropertyset>
  83.304 +                    <customize/>
  83.305 +                </java>
  83.306 +            </sequential>
  83.307 +        </macrodef>
  83.308 +    </target>
  83.309 +    <target name="-init-presetdef-jar">
  83.310 +        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
  83.311 +            <jar compress="${jar.compress}" jarfile="${dist.jar}">
  83.312 +                <j2seproject1:fileset dir="${build.classes.dir}"/>
  83.313 +            </jar>
  83.314 +        </presetdef>
  83.315 +    </target>
  83.316 +    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar" name="init"/>
  83.317 +    <!--
  83.318 +                ===================
  83.319 +                COMPILATION SECTION
  83.320 +                ===================
  83.321 +            -->
  83.322 +    <target depends="init" name="deps-jar" unless="no.deps"/>
  83.323 +    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
  83.324 +    <target depends="init" name="-check-automatic-build">
  83.325 +        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
  83.326 +    </target>
  83.327 +    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
  83.328 +        <antcall target="clean"/>
  83.329 +    </target>
  83.330 +    <target depends="init,deps-jar" name="-pre-pre-compile">
  83.331 +        <mkdir dir="${build.classes.dir}"/>
  83.332 +    </target>
  83.333 +    <target name="-pre-compile">
  83.334 +        <!-- Empty placeholder for easier customization. -->
  83.335 +        <!-- You can override this target in the ../build.xml file. -->
  83.336 +    </target>
  83.337 +    <target if="do.depend.true" name="-compile-depend">
  83.338 +        <j2seproject3:depend/>
  83.339 +    </target>
  83.340 +    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
  83.341 +        <j2seproject3:javac/>
  83.342 +        <copy todir="${build.classes.dir}">
  83.343 +            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  83.344 +        </copy>
  83.345 +    </target>
  83.346 +    <target name="-post-compile">
  83.347 +        <!-- Empty placeholder for easier customization. -->
  83.348 +        <!-- You can override this target in the ../build.xml file. -->
  83.349 +    </target>
  83.350 +    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
  83.351 +    <target name="-pre-compile-single">
  83.352 +        <!-- Empty placeholder for easier customization. -->
  83.353 +        <!-- You can override this target in the ../build.xml file. -->
  83.354 +    </target>
  83.355 +    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
  83.356 +        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
  83.357 +        <j2seproject3:force-recompile/>
  83.358 +        <j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
  83.359 +    </target>
  83.360 +    <target name="-post-compile-single">
  83.361 +        <!-- Empty placeholder for easier customization. -->
  83.362 +        <!-- You can override this target in the ../build.xml file. -->
  83.363 +    </target>
  83.364 +    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
  83.365 +    <!--
  83.366 +                ====================
  83.367 +                JAR BUILDING SECTION
  83.368 +                ====================
  83.369 +            -->
  83.370 +    <target depends="init" name="-pre-pre-jar">
  83.371 +        <dirname file="${dist.jar}" property="dist.jar.dir"/>
  83.372 +        <mkdir dir="${dist.jar.dir}"/>
  83.373 +    </target>
  83.374 +    <target name="-pre-jar">
  83.375 +        <!-- Empty placeholder for easier customization. -->
  83.376 +        <!-- You can override this target in the ../build.xml file. -->
  83.377 +    </target>
  83.378 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
  83.379 +        <j2seproject1:jar/>
  83.380 +    </target>
  83.381 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
  83.382 +        <j2seproject1:jar manifest="${manifest.file}"/>
  83.383 +    </target>
  83.384 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
  83.385 +        <j2seproject1:jar manifest="${manifest.file}">
  83.386 +            <j2seproject1:manifest>
  83.387 +                <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
  83.388 +            </j2seproject1:manifest>
  83.389 +        </j2seproject1:jar>
  83.390 +        <echo>To run this application from the command line without Ant, try:</echo>
  83.391 +        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
  83.392 +        <property location="${dist.jar}" name="dist.jar.resolved"/>
  83.393 +        <pathconvert property="run.classpath.with.dist.jar">
  83.394 +            <path path="${run.classpath}"/>
  83.395 +            <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
  83.396 +        </pathconvert>
  83.397 +        <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
  83.398 +    </target>
  83.399 +    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
  83.400 +        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
  83.401 +        <pathconvert property="run.classpath.without.build.classes.dir">
  83.402 +            <path path="${run.classpath}"/>
  83.403 +            <map from="${build.classes.dir.resolved}" to=""/>
  83.404 +        </pathconvert>
  83.405 +        <pathconvert pathsep=" " property="jar.classpath">
  83.406 +            <path path="${run.classpath.without.build.classes.dir}"/>
  83.407 +            <chainedmapper>
  83.408 +                <flattenmapper/>
  83.409 +                <globmapper from="*" to="lib/*"/>
  83.410 +            </chainedmapper>
  83.411 +        </pathconvert>
  83.412 +        <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
  83.413 +        <copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
  83.414 +            <fileset dir="${build.classes.dir}"/>
  83.415 +            <manifest>
  83.416 +                <attribute name="Main-Class" value="${main.class}"/>
  83.417 +                <attribute name="Class-Path" value="${jar.classpath}"/>
  83.418 +            </manifest>
  83.419 +        </copylibs>
  83.420 +        <echo>To run this application from the command line without Ant, try:</echo>
  83.421 +        <property location="${dist.jar}" name="dist.jar.resolved"/>
  83.422 +        <echo>java -jar "${dist.jar.resolved}"</echo>
  83.423 +    </target>
  83.424 +    <target name="-post-jar">
  83.425 +        <!-- Empty placeholder for easier customization. -->
  83.426 +        <!-- You can override this target in the ../build.xml file. -->
  83.427 +    </target>
  83.428 +    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
  83.429 +    <!--
  83.430 +                =================
  83.431 +                EXECUTION SECTION
  83.432 +                =================
  83.433 +            -->
  83.434 +    <target depends="init,compile" description="Run a main class." name="run">
  83.435 +        <j2seproject1:java>
  83.436 +            <customize>
  83.437 +                <arg line="${application.args}"/>
  83.438 +            </customize>
  83.439 +        </j2seproject1:java>
  83.440 +    </target>
  83.441 +    <target name="-do-not-recompile">
  83.442 +        <property name="javac.includes.binary" value=""/>
  83.443 +    </target>
  83.444 +    <target depends="init,-do-not-recompile,compile-single" name="run-single">
  83.445 +        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
  83.446 +        <j2seproject1:java classname="${run.class}"/>
  83.447 +    </target>
  83.448 +    <!--
  83.449 +                =================
  83.450 +                DEBUGGING SECTION
  83.451 +                =================
  83.452 +            -->
  83.453 +    <target depends="init" if="netbeans.home" name="-debug-start-debugger">
  83.454 +        <j2seproject1:nbjpdastart name="${debug.class}"/>
  83.455 +    </target>
  83.456 +    <target depends="init,compile" name="-debug-start-debuggee">
  83.457 +        <j2seproject3:debug>
  83.458 +            <customize>
  83.459 +                <arg line="${application.args}"/>
  83.460 +            </customize>
  83.461 +        </j2seproject3:debug>
  83.462 +    </target>
  83.463 +    <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
  83.464 +    <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
  83.465 +        <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
  83.466 +    </target>
  83.467 +    <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
  83.468 +    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
  83.469 +        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
  83.470 +        <j2seproject3:debug classname="${debug.class}"/>
  83.471 +    </target>
  83.472 +    <target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
  83.473 +    <target depends="init" name="-pre-debug-fix">
  83.474 +        <fail unless="fix.includes">Must set fix.includes</fail>
  83.475 +        <property name="javac.includes" value="${fix.includes}.java"/>
  83.476 +    </target>
  83.477 +    <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
  83.478 +        <j2seproject1:nbjpdareload/>
  83.479 +    </target>
  83.480 +    <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
  83.481 +    <!--
  83.482 +                ===============
  83.483 +                JAVADOC SECTION
  83.484 +                ===============
  83.485 +            -->
  83.486 +    <target depends="init" name="-javadoc-build">
  83.487 +        <mkdir dir="${dist.javadoc.dir}"/>
  83.488 +        <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
  83.489 +            <classpath>
  83.490 +                <path path="${javac.classpath}"/>
  83.491 +            </classpath>
  83.492 +            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
  83.493 +                <filename name="**/*.java"/>
  83.494 +            </fileset>
  83.495 +        </javadoc>
  83.496 +    </target>
  83.497 +    <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
  83.498 +        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
  83.499 +    </target>
  83.500 +    <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
  83.501 +    <!--
  83.502 +                =========================
  83.503 +                JUNIT COMPILATION SECTION
  83.504 +                =========================
  83.505 +            -->
  83.506 +    <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
  83.507 +        <mkdir dir="${build.test.classes.dir}"/>
  83.508 +    </target>
  83.509 +    <target name="-pre-compile-test">
  83.510 +        <!-- Empty placeholder for easier customization. -->
  83.511 +        <!-- You can override this target in the ../build.xml file. -->
  83.512 +    </target>
  83.513 +    <target if="do.depend.true" name="-compile-test-depend">
  83.514 +        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
  83.515 +    </target>
  83.516 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
  83.517 +        <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
  83.518 +        <copy todir="${build.test.classes.dir}">
  83.519 +            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  83.520 +        </copy>
  83.521 +    </target>
  83.522 +    <target name="-post-compile-test">
  83.523 +        <!-- Empty placeholder for easier customization. -->
  83.524 +        <!-- You can override this target in the ../build.xml file. -->
  83.525 +    </target>
  83.526 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
  83.527 +    <target name="-pre-compile-test-single">
  83.528 +        <!-- Empty placeholder for easier customization. -->
  83.529 +        <!-- You can override this target in the ../build.xml file. -->
  83.530 +    </target>
  83.531 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
  83.532 +        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
  83.533 +        <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
  83.534 +        <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
  83.535 +        <copy todir="${build.test.classes.dir}">
  83.536 +            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
  83.537 +        </copy>
  83.538 +    </target>
  83.539 +    <target name="-post-compile-test-single">
  83.540 +        <!-- Empty placeholder for easier customization. -->
  83.541 +        <!-- You can override this target in the ../build.xml file. -->
  83.542 +    </target>
  83.543 +    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
  83.544 +    <!--
  83.545 +                =======================
  83.546 +                JUNIT EXECUTION SECTION
  83.547 +                =======================
  83.548 +            -->
  83.549 +    <target depends="init" if="have.tests" name="-pre-test-run">
  83.550 +        <mkdir dir="${build.test.results.dir}"/>
  83.551 +    </target>
  83.552 +    <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
  83.553 +        <j2seproject3:junit testincludes="**/*Test.java"/>
  83.554 +    </target>
  83.555 +    <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
  83.556 +        <fail if="tests.failed">Some tests failed; see details above.</fail>
  83.557 +    </target>
  83.558 +    <target depends="init" if="have.tests" name="test-report"/>
  83.559 +    <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
  83.560 +    <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
  83.561 +    <target depends="init" if="have.tests" name="-pre-test-run-single">
  83.562 +        <mkdir dir="${build.test.results.dir}"/>
  83.563 +    </target>
  83.564 +    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
  83.565 +        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
  83.566 +        <j2seproject3:junit excludes="" includes="${test.includes}"/>
  83.567 +    </target>
  83.568 +    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
  83.569 +        <fail if="tests.failed">Some tests failed; see details above.</fail>
  83.570 +    </target>
  83.571 +    <target depends="init,-do-not-recompile,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
  83.572 +    <!--
  83.573 +                =======================
  83.574 +                JUNIT DEBUGGING SECTION
  83.575 +                =======================
  83.576 +            -->
  83.577 +    <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
  83.578 +        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
  83.579 +        <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
  83.580 +        <delete file="${test.report.file}"/>
  83.581 +        <mkdir dir="${build.test.results.dir}"/>
  83.582 +        <j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
  83.583 +            <customize>
  83.584 +                <syspropertyset>
  83.585 +                    <propertyref prefix="test-sys-prop."/>
  83.586 +                    <mapper from="test-sys-prop.*" to="*" type="glob"/>
  83.587 +                </syspropertyset>
  83.588 +                <arg value="${test.class}"/>
  83.589 +                <arg value="showoutput=true"/>
  83.590 +                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
  83.591 +                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
  83.592 +            </customize>
  83.593 +        </j2seproject3:debug>
  83.594 +    </target>
  83.595 +    <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
  83.596 +        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
  83.597 +    </target>
  83.598 +    <target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
  83.599 +    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
  83.600 +        <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
  83.601 +    </target>
  83.602 +    <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
  83.603 +    <!--
  83.604 +                =========================
  83.605 +                APPLET EXECUTION SECTION
  83.606 +                =========================
  83.607 +            -->
  83.608 +    <target depends="init,compile-single" name="run-applet">
  83.609 +        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
  83.610 +        <j2seproject1:java classname="sun.applet.AppletViewer">
  83.611 +            <customize>
  83.612 +                <arg value="${applet.url}"/>
  83.613 +            </customize>
  83.614 +        </j2seproject1:java>
  83.615 +    </target>
  83.616 +    <!--
  83.617 +                =========================
  83.618 +                APPLET DEBUGGING  SECTION
  83.619 +                =========================
  83.620 +            -->
  83.621 +    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
  83.622 +        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
  83.623 +        <j2seproject3:debug classname="sun.applet.AppletViewer">
  83.624 +            <customize>
  83.625 +                <arg value="${applet.url}"/>
  83.626 +            </customize>
  83.627 +        </j2seproject3:debug>
  83.628 +    </target>
  83.629 +    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
  83.630 +    <!--
  83.631 +                ===============
  83.632 +                CLEANUP SECTION
  83.633 +                ===============
  83.634 +            -->
  83.635 +    <target depends="init" name="deps-clean" unless="no.deps"/>
  83.636 +    <target depends="init" name="-do-clean">
  83.637 +        <delete dir="${build.dir}"/>
  83.638 +        <delete dir="${dist.dir}"/>
  83.639 +    </target>
  83.640 +    <target name="-post-clean">
  83.641 +        <!-- Empty placeholder for easier customization. -->
  83.642 +        <!-- You can override this target in the ../build.xml file. -->
  83.643 +    </target>
  83.644 +    <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
  83.645 +</project>
    84.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    84.2 +++ b/task3/solution13/nbproject/genfiles.properties	Tue Oct 07 11:05:34 2008 +0200
    84.3 @@ -0,0 +1,8 @@
    84.4 +build.xml.data.CRC32=2ab820eb
    84.5 +build.xml.script.CRC32=58a52595
    84.6 +build.xml.stylesheet.CRC32=be360661
    84.7 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
    84.8 +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
    84.9 +nbproject/build-impl.xml.data.CRC32=de21ce77
   84.10 +nbproject/build-impl.xml.script.CRC32=0903858a
   84.11 +nbproject/build-impl.xml.stylesheet.CRC32=e55b27f5
    85.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    85.2 +++ b/task3/solution13/nbproject/project.properties	Tue Oct 07 11:05:34 2008 +0200
    85.3 @@ -0,0 +1,68 @@
    85.4 +application.title=currency
    85.5 +application.vendor=apidesign.org
    85.6 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
    85.7 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
    85.8 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=default
    85.9 +build.classes.dir=${build.dir}/classes
   85.10 +build.classes.excludes=**/*.java,**/*.form
   85.11 +# This directory is removed when the project is cleaned:
   85.12 +build.dir=build
   85.13 +build.generated.dir=${build.dir}/generated
   85.14 +# Only compile against the classpath explicitly listed here:
   85.15 +build.sysclasspath=ignore
   85.16 +build.test.classes.dir=${build.dir}/test/classes
   85.17 +build.test.results.dir=${build.dir}/test/results
   85.18 +debug.classpath=\
   85.19 +    ${run.classpath}
   85.20 +debug.test.classpath=\
   85.21 +    ${run.test.classpath}
   85.22 +# This directory is removed when the project is cleaned:
   85.23 +dist.dir=dist
   85.24 +dist.jar=${dist.dir}/currency.jar
   85.25 +dist.javadoc.dir=${dist.dir}/javadoc
   85.26 +excludes=
   85.27 +file.reference.junit-4.4.jar=../../libs/junit-4.4.jar
   85.28 +file.reference.src-apifest08=..
   85.29 +includes=**
   85.30 +jar.compress=false
   85.31 +javac.classpath=
   85.32 +# Space-separated list of extra javac options
   85.33 +javac.compilerargs=
   85.34 +javac.deprecation=false
   85.35 +javac.source=1.5
   85.36 +javac.target=1.5
   85.37 +javac.test.classpath=\
   85.38 +    ${javac.classpath}:\
   85.39 +    ${build.classes.dir}:\
   85.40 +    ${file.reference.junit-4.4.jar}
   85.41 +javadoc.additionalparam=
   85.42 +javadoc.author=false
   85.43 +javadoc.encoding=
   85.44 +javadoc.noindex=false
   85.45 +javadoc.nonavbar=false
   85.46 +javadoc.notree=false
   85.47 +javadoc.private=false
   85.48 +javadoc.splitindex=true
   85.49 +javadoc.use=true
   85.50 +javadoc.version=false
   85.51 +javadoc.windowtitle=
   85.52 +jnlp.codebase.type=local
   85.53 +jnlp.codebase.url=file:/home/jarda/src/apifest08/currency/dist
   85.54 +jnlp.descriptor=application
   85.55 +jnlp.enabled=false
   85.56 +jnlp.offline-allowed=false
   85.57 +jnlp.signed=false
   85.58 +meta.inf.dir=${src.dir}/META-INF
   85.59 +platform.active=default_platform
   85.60 +run.classpath=\
   85.61 +    ${javac.classpath}:\
   85.62 +    ${build.classes.dir}
   85.63 +# Space-separated list of JVM arguments used when running the project
   85.64 +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
   85.65 +# or test-sys-prop.name=value to set system properties for unit tests):
   85.66 +run.jvmargs=
   85.67 +run.test.classpath=\
   85.68 +    ${javac.test.classpath}:\
   85.69 +    ${build.test.classes.dir}
   85.70 +src.dir=src
   85.71 +test.src.dir=test
    86.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    86.2 +++ b/task3/solution13/nbproject/project.xml	Tue Oct 07 11:05:34 2008 +0200
    86.3 @@ -0,0 +1,16 @@
    86.4 +<?xml version="1.0" encoding="UTF-8"?>
    86.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
    86.6 +    <type>org.netbeans.modules.java.j2seproject</type>
    86.7 +    <configuration>
    86.8 +        <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
    86.9 +            <name>Currency Convertor Solution 13</name>
   86.10 +            <minimum-ant-version>1.6.5</minimum-ant-version>
   86.11 +            <source-roots>
   86.12 +                <root id="src.dir"/>
   86.13 +            </source-roots>
   86.14 +            <test-roots>
   86.15 +                <root id="test.src.dir"/>
   86.16 +            </test-roots>
   86.17 +        </data>
   86.18 +    </configuration>
   86.19 +</project>
    87.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    87.2 +++ b/task3/solution13/src/org/apidesign/apifest08/currency/ConversionNotSupportedException.java	Tue Oct 07 11:05:34 2008 +0200
    87.3 @@ -0,0 +1,85 @@
    87.4 +package org.apidesign.apifest08.currency;
    87.5 +
    87.6 +/**
    87.7 + * Conversion not suported exception. This expecption may optionaly describe which conversion was required and failed.
    87.8 + * Required conversion can be found in {@link #getFromCurrecyCode() } and {@link #getToCurrecyCode() }.
    87.9 + * 
   87.10 + * @author arnostvalicek
   87.11 + * @since version2
   87.12 + */
   87.13 +public class ConversionNotSupportedException extends ConvertorException {
   87.14 +    String from;
   87.15 +    String to;
   87.16 +    boolean reversed;
   87.17 +    
   87.18 +    public ConversionNotSupportedException() {
   87.19 +        super();
   87.20 +    }
   87.21 +
   87.22 +    public ConversionNotSupportedException(String message) {
   87.23 +        super(message);
   87.24 +    }
   87.25 +
   87.26 +    public ConversionNotSupportedException(String message, Throwable cause) {
   87.27 +        super(message, cause);
   87.28 +    }
   87.29 +
   87.30 +    public ConversionNotSupportedException(Throwable cause) {
   87.31 +        super(cause);
   87.32 +    }
   87.33 +    
   87.34 +    /**
   87.35 +     * Create exception witd additional information about currencies which are not supported in coversion.
   87.36 +     * @param from Code of source currency.
   87.37 +     * @param to Code of target currency.
   87.38 +     * @param twoWay Set to <code>false</code> if <em>From-&gt;To</em> is not supported.
   87.39 +     *               Set to <code>true</code> if both ways <em>From-&gt;To</em> and <em>To->From</em> conversions are not supported.
   87.40 +     *               
   87.41 +     */
   87.42 +    public ConversionNotSupportedException(String from, String to, boolean twoWay) {
   87.43 +        this.from = from;
   87.44 +        this.to = to;
   87.45 +        this.reversed = true;
   87.46 +    }
   87.47 +
   87.48 +    @Override
   87.49 +    public String toString() {
   87.50 +        if (from!=null && to !=null) {
   87.51 +          if (reversed) {
   87.52 +             return "Neither onversion nor reverted conversion from " + from + " to " + to + "  is not supported,"; 
   87.53 +          }  else {
   87.54 +             return "Conversion from " + from + " to " + to + "  is not supported,"; 
   87.55 +          }
   87.56 +        } else {
   87.57 +            return super.toString();
   87.58 +        }
   87.59 +    }
   87.60 +    
   87.61 +    /**
   87.62 +     * Returns code of source currency. This value may be null.
   87.63 +     * @return Returns code of source currency.
   87.64 +     */
   87.65 +    public String getFromCurrecyCode() {
   87.66 +        return from;
   87.67 +    }
   87.68 +
   87.69 +    /**
   87.70 +     * Returns code of target currency. This value may be null.
   87.71 +     * @return Returns code of target currency.
   87.72 +     */    public String getToCurrecyCode() {
   87.73 +        return to;
   87.74 +    }
   87.75 +     
   87.76 +    /**
   87.77 +     * Returns if one way of two way conversion is not supported.
   87.78 +     * 
   87.79 +     * Value <code>false</code> means one way conversion is not supported. Value <code>true</code> means
   87.80 +     * that two way conversio is not supported.
   87.81 +     * 
   87.82 +     * @return Returs <code>false</code> for one way conversion, <code>true</code> for two way conversion.
   87.83 +     */ 
   87.84 +    public boolean getTwoWayConversion() {
   87.85 +        return reversed;
   87.86 +    }
   87.87 +
   87.88 +}
    88.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    88.2 +++ b/task3/solution13/src/org/apidesign/apifest08/currency/ConversionResult.java	Tue Oct 07 11:05:34 2008 +0200
    88.3 @@ -0,0 +1,49 @@
    88.4 +
    88.5 +package org.apidesign.apifest08.currency;
    88.6 +
    88.7 +import java.math.BigDecimal;
    88.8 +
    88.9 +/**
   88.10 + * Result of currency conversion. Holds converted value and remainder.
   88.11 + * <p>
   88.12 + * <em>Converted</em> describes value converted to <em>target</em> currenty. <em>Remainder</em> describes
   88.13 + * how much from original <em>amount</em> was not possible to convert. Convertor never loses any (small) money
   88.14 + * in conversion error (rounding), but instead of rounding is converts only as much as possible and keeps rest as remainder.
   88.15 + * 
   88.16 + * @author arnostvalicek
   88.17 + */
   88.18 +public class ConversionResult {
   88.19 +    private BigDecimal converted;
   88.20 +    private BigDecimal remainder;
   88.21 +    
   88.22 +    /**
   88.23 +     * Get converted value.
   88.24 +     * @return Returns converted value.
   88.25 +     */
   88.26 +    public BigDecimal getConverted() {
   88.27 +        return converted;
   88.28 +    }
   88.29 +
   88.30 +    void setConverted(BigDecimal converted) {
   88.31 +        this.converted = converted;
   88.32 +    }
   88.33 +
   88.34 +    
   88.35 +    /**
   88.36 +     * Get remainder of conversion. Remainder is set if part of converted amount which can't be converted 
   88.37 +     * because this target currency precision can't handle small numbers. Remainder value is in <em>from currency</em>
   88.38 +     * <p>
   88.39 +     * Converter never loses any precision in conversion. Remainer describes how much of amount can't be converted. 
   88.40 +     * If we substract <em>remainder</em> from <em>amount</em> we will be able to get exact conversion.
   88.41 +     * 
   88.42 +     * @return Returns remainder of conversion.
   88.43 +     */
   88.44 +    public BigDecimal getRemainder() {
   88.45 +        return remainder;
   88.46 +    }
   88.47 +
   88.48 +    void setRemainder(BigDecimal remainder) {
   88.49 +        this.remainder = remainder;
   88.50 +    }
   88.51 +
   88.52 +}
    89.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    89.2 +++ b/task3/solution13/src/org/apidesign/apifest08/currency/Convertor.java	Tue Oct 07 11:05:34 2008 +0200
    89.3 @@ -0,0 +1,213 @@
    89.4 +package org.apidesign.apifest08.currency;
    89.5 +
    89.6 +import java.math.BigDecimal;
    89.7 +import java.math.MathContext;
    89.8 +import java.math.RoundingMode;
    89.9 +
   89.10 +/** Convertor able to convert amount from one currency to other currency.
   89.11 + * <p>
   89.12 + * Conversion method are:
   89.13 + * <ul>
   89.14 + * <li>{@link #convert(ConvertorCurrency, ConvertorCurrency, BigDecimal)} - convert using exchange rate specified in exchange rate provide. <em>Do not try use reverted excahnage rate</em>. 
   89.15 + * <li>{@link #convertWithReversibleRates(ConvertorCurrency, ConvertorCurrency, BigDecimal)} - convert using exchange rate specified in exchange rate provide. <em>Try use reverted excahnage rate</em>. 
   89.16 + * </ul>
   89.17 + * 
   89.18 + * Exchange rate is provided by {@link ExchangeRateProvider}.
   89.19 + */
   89.20 +public class Convertor {
   89.21 +    private Convertor[] convertors;
   89.22 +
   89.23 +    /** Create new <code>Convertor</code> as merge of provided convertors. Merged convertor will use
   89.24 +     * provided convertors to convert between currencies.
   89.25 +     * <p>
   89.26 +     * Only one should be able to provide conversion between currencies. If more than one convertos
   89.27 +     * are able to convert currency, one of conversions will be used (it is not defined which).
   89.28 +     * 
   89.29 +     * @since version 2
   89.30 +     * @param convertors Convertor used to create merge-convertor.
   89.31 +     * @return Returns new convertor instance.
   89.32 +     */
   89.33 +    public static Convertor createConvertorAsMerge(Convertor[] convertors) {
   89.34 +        return new Convertor(convertors);
   89.35 +    }
   89.36 +    
   89.37 +    boolean remainderAllowed = true; //if false, remained is not allowed (should be true ideally, but can't handle it now)
   89.38 +    ExchangeRateProvider exchangeRateProvider; 
   89.39 +    
   89.40 +    /** Create simle convertor.
   89.41 +     */
   89.42 +    private Convertor() {
   89.43 +        this.convertors=new Convertor[0];
   89.44 +    }
   89.45 +    
   89.46 +    /** Create merge convertor.
   89.47 +     */            
   89.48 +    private Convertor(Convertor[] convertors) {
   89.49 +        this.convertors = convertors;       
   89.50 +    }
   89.51 +    
   89.52 +    /**
   89.53 +     * Create new <code>Convertor</code> using <code>ExchangeRateProvider</code>.
   89.54 +     * 
   89.55 +     * @param exchangeRateProvider {@link ExchangeRateProvider} used to get exchange rate.
   89.56 +     * 
   89.57 +     * @return Returns <code>Convertor</code> which can be used to convert money.
   89.58 +     * @since version1
   89.59 +     */
   89.60 +    public static Convertor createConvertor(ExchangeRateProvider exchangeRateProvider) {
   89.61 +        Convertor c = new Convertor();
   89.62 +
   89.63 +        c.exchangeRateProvider = exchangeRateProvider;
   89.64 +        return c;
   89.65 +    }
   89.66 +    
   89.67 +    /**
   89.68 +     * Convert <code>amount</code> from <code>fromCurrency</code> to <code>toCurrency</code> as specified
   89.69 +     * in <code>ExchangeRateProvider</code>.
   89.70 +     * 
   89.71 +     * @param amount Amount which should be converted. Can't be negative value (can be zero or positive).
   89.72 +     * @return Return <code>ConversionResult</code> which holds conversion result.
   89.73 +     * @since version1
   89.74 +     * @deprecated since version2. Use {@link #convert(ConvertorCurrency, ConvertorCurrency, BigDecimal) } - explicitly specify conversion currencies.
   89.75 +     */
   89.76 +    public ConversionResult convert(BigDecimal amount) {
   89.77 +        return convertValue(exchangeRateProvider.getFromCurrency(), exchangeRateProvider.getToCurrency(),amount, false,false);
   89.78 +    }
   89.79 +    
   89.80 +    /**
   89.81 +     * Convert <code>amount</code> from <code>toCurrency</code> to <code>fromCurrency</code> as specified
   89.82 +     * in <code>ExchangeRateProvider</code>. This is <em>reverted</em> order than suggested by  names of currency fields in <code>ExchangeRate</code>.
   89.83 +     * 
   89.84 +     * @param amount Amount which should be converted. Can't be negative value (can be zero or positive).
   89.85 +     * @return Return <code>ConversionResult</code> which holds conversion result.
   89.86 +     * @since version1
   89.87 +     * @deprecated since version2. Use {@link #convert(ConvertorCurrency, ConvertorCurrency, BigDecimal) } - explicitly specify conversion currencies.
   89.88 +     */
   89.89 +    public ConversionResult convertBack(BigDecimal amount) {
   89.90 +        return convertValue(exchangeRateProvider.getFromCurrency(), exchangeRateProvider.getToCurrency(),amount, true,false);
   89.91 +    }
   89.92 +
   89.93 +    private ConversionResult convertUsingSimpleConvertor(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency, boolean reversibleExRate, BigDecimal amount, boolean convertBack) throws ConversionNotSupportedException, RuntimeException {
   89.94 +        ConversionResult result = new ConversionResult();
   89.95 +
   89.96 +        //ExchangeRate rate = exchangeRateProvider.getExchangeRate();
   89.97 +        ExchangeRate rate;
   89.98 +        if (reversibleExRate) {
   89.99 +            rate = exchangeRateProvider.getReversibleExchangeRate(fromCurrency, toCurrency);
  89.100 +        } else {
  89.101 +            rate = exchangeRateProvider.getExchangeRate(fromCurrency, toCurrency);
  89.102 +        }
  89.103 +        if (rate == null) {
  89.104 +            return null;
  89.105 +        }
  89.106 +        
  89.107 +        int fromFranctionDigits = fromCurrency.getDefaultFractionDigits();
  89.108 +        int toFractionDigits = toCurrency.getDefaultFractionDigits();
  89.109 +
  89.110 +        if (toFractionDigits != 2) {
  89.111 +            throw new ConvertorException("Can't process currency with defaultFractionDigits!=2, " + exchangeRateProvider.getToCurrency() + " has " + toFractionDigits + " defaultFractionDigits");
  89.112 +        }
  89.113 +        if (fromFranctionDigits != 2) {
  89.114 +            throw new ConvertorException("Can't process currency with defaultFractionDigits!=2, " + exchangeRateProvider.getFromCurrency() + " has " + fromFranctionDigits + " defaultFractionDigits");
  89.115 +        }
  89.116 +
  89.117 +        if (amount.signum() == -1) {
  89.118 +            throw new RuntimeException("Can convert only non-negative value, current value is " + amount);
  89.119 +        }
  89.120 +
  89.121 +
  89.122 +        MathContext context = new MathContext(0, RoundingMode.DOWN);
  89.123 +
  89.124 +        BigDecimal from;
  89.125 +        BigDecimal to;
  89.126 +        if (convertBack) {
  89.127 +            //converting in reverted way
  89.128 +            to = rate.getFromValue();
  89.129 +            from = rate.getToValue();
  89.130 +        } else {
  89.131 +            //converting in normal way
  89.132 +            from = rate.getFromValue();
  89.133 +            to = rate.getToValue();
  89.134 +        }
  89.135 +
  89.136 +        BigDecimal amountCent = amount.movePointRight(2);
  89.137 +
  89.138 +        final BigDecimal multiplied = amountCent.multiply(to, context);
  89.139 +        BigDecimal[] division = multiplied.divideAndRemainder(from, context);
  89.140 +
  89.141 +        if (!remainderAllowed && !(BigDecimal.ZERO.equals(division[1]))) {
  89.142 +            throw new RuntimeException("Remained is not allowed - remaining amount is " + division[1] + " cents");
  89.143 +        } else {
  89.144 +            result.setRemainder(BigDecimal.ZERO);
  89.145 +        }
  89.146 +
  89.147 +        final BigDecimal converted = division[0].movePointLeft(2);
  89.148 +        result.setConverted(converted);
  89.149 +        //result.setRemainder(...);
  89.150 +        return result;
  89.151 +    }
  89.152 +    
  89.153 +
  89.154 +    private ConversionResult convertValue(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency,BigDecimal amount, boolean convertBack,boolean reversibleExRate) throws RuntimeException {
  89.155 +        //result.setRemainder(...);
  89.156 +        if (convertors.length==0) {
  89.157 +            return convertUsingSimpleConvertor(fromCurrency, toCurrency, reversibleExRate, amount, convertBack);
  89.158 +        } else {
  89.159 +            ConversionResult result = null;
  89.160 +            for (int i = 0;i<convertors.length;i++) {
  89.161 +                Convertor subConvertor = convertors[i];
  89.162 +                result = subConvertor.convertValue(fromCurrency, toCurrency, amount, convertBack, reversibleExRate);
  89.163 +                if (result!=null) {
  89.164 +                    break;
  89.165 +                }
  89.166 +            }
  89.167 +            return result;
  89.168 +        }
  89.169 +    }
  89.170 +    
  89.171 +    /**
  89.172 +     * Convert <code>value</code> from <code>fromCurrency</code> to <code>toCurrency</code>.
  89.173 +     * <p>
  89.174 +     * Exchange rate is provided by exchange rate provider which was specified when Convertor was created.
  89.175 +     * This method is using only exchange rate from->to and not trying to use reverted excange rate to->from.
  89.176 +     * 
  89.177 +     * @param fromCurrency Source currency to convert from.
  89.178 +     * @param toCurrency Target currency to convert to.
  89.179 +     * @param value Value in source currency which should be converted.
  89.180 +     * @return Return conversion result.
  89.181 +     * @since version2
  89.182 +     * @throws ConversionNotSupportedException If conversion from <code>fromCurrency</code> to <code>toCurrency</code> is not supported.
  89.183 +     */
  89.184 +    public ConversionResult convert(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency, BigDecimal value) {
  89.185 +        ConversionResult result = convertValue(fromCurrency, toCurrency, value, false,false);
  89.186 +        if (result==null) {
  89.187 +            //throw new ConversionNotSupportedException("Conversion from " + fromCurrency + " to " + toCurrency + " is not supported");
  89.188 +            throw new ConversionNotSupportedException(fromCurrency.getCurrencyCode(),toCurrency.getCurrencyCode(),false);
  89.189 +        }
  89.190 +        return result;
  89.191 +    }
  89.192 +    
  89.193 +    /**
  89.194 +     * Convert <code>value</code> from <code>fromCurrency</code> to <code>toCurrency</code>.
  89.195 +     * Exchange rate is provided by exchange rate provider which was specified when Convertor was created.
  89.196 +     * <p>
  89.197 +     *  This method is using only exchange rate from->to and if not found, it is trying to use reverted excange rate to->from.
  89.198 +     * 
  89.199 +     * @param fromCurrency Source currency to convert from.
  89.200 +     * @param toCurrency Target currency to convert to.
  89.201 +     * @param value Value in source currency which should be converted.
  89.202 +     * @return Return conversion result.
  89.203 +     * @since version2
  89.204 +     * @throws ConversionNotSupportedException If conversion from <code>fromCurrency</code> to <code>toCurrency</code> 
  89.205 +     *         is not supported and neither conversion from <code>toCurrency</code> to <code>fromCurrency</code> is not supported.
  89.206 +     */
  89.207 +    public ConversionResult convertWithReversibleRates(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency, BigDecimal value) {
  89.208 +        ConversionResult result = convertValue(fromCurrency, toCurrency, value, false,true);
  89.209 +        if (result==null) {
  89.210 +            //throw new ConversionNotSupportedException("Neither onversion nor reverted conversion from " + fromCurrency + " to " + toCurrency + "  is not supported,");
  89.211 +            throw new ConversionNotSupportedException(fromCurrency.getCurrencyCode(),toCurrency.getCurrencyCode(),true);
  89.212 +        }
  89.213 +        return result;
  89.214 +    }
  89.215 +    
  89.216 +}
    90.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    90.2 +++ b/task3/solution13/src/org/apidesign/apifest08/currency/ConvertorCurrency.java	Tue Oct 07 11:05:34 2008 +0200
    90.3 @@ -0,0 +1,63 @@
    90.4 +
    90.5 +package org.apidesign.apifest08.currency;
    90.6 +
    90.7 +import java.util.Currency;
    90.8 +
    90.9 +/**
   90.10 + * Desription of currency. 
   90.11 + * 
   90.12 + * Java has similar class {@link java.util.Currency}, but original class is not flexible
   90.13 + * enough, we use our own implementation of currency.
   90.14 + *
   90.15 + * @author arnostvalicek
   90.16 + */
   90.17 +public class ConvertorCurrency {
   90.18 +
   90.19 +    private Currency currency;
   90.20 +
   90.21 +    private void setJavaCurrency(Currency javaCurrency) {
   90.22 +        this.currency = javaCurrency;
   90.23 +    }
   90.24 +
   90.25 +    /**
   90.26 +     * Static method providing instance of <code>ConvertorCurrency</code> base of currency code.
   90.27 +     * 
   90.28 +     * @param currencyCode Code of required currency.
   90.29 +     * @return Returns required <code>ConvertorCurrency</code>
   90.30 +     */
   90.31 +    public static ConvertorCurrency getInstance(String currencyCode) {
   90.32 +        ConvertorCurrency convertorCurrency = new ConvertorCurrency();
   90.33 +        convertorCurrency.setJavaCurrency(Currency.getInstance(currencyCode));
   90.34 +        return convertorCurrency;
   90.35 +    }
   90.36 +
   90.37 +    /**
   90.38 +     * Gets the default number of fraction digits used with this currency. For example, the default number of fraction digits for the Euro is 2, while for the Japanese Yen it's 0.
   90.39 +     * @return Returns the default number of fraction digits used with this currency.
   90.40 +     */
   90.41 +    public int getDefaultFractionDigits() {
   90.42 +        return currency.getDefaultFractionDigits();
   90.43 +    }
   90.44 +
   90.45 +    @Override
   90.46 +    public boolean equals(Object obj) {
   90.47 +        boolean result;
   90.48 +        if (obj instanceof ConvertorCurrency) {
   90.49 +            ConvertorCurrency that = (ConvertorCurrency) obj;
   90.50 +            result = currency.equals(that.currency);
   90.51 +        } else {
   90.52 +            result = false;
   90.53 +        }
   90.54 +        return result;
   90.55 +    }
   90.56 +    
   90.57 +
   90.58 +    @Override
   90.59 +    public String toString() {
   90.60 +        return  "ConvertorCurrency[" + (currency != null ? currency.toString() : "NO-BASE-CURRENCY")+"]";
   90.61 +    }
   90.62 +    
   90.63 +    String getCurrencyCode() {
   90.64 +        return currency.getCurrencyCode();
   90.65 +    }
   90.66 +}
    91.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    91.2 +++ b/task3/solution13/src/org/apidesign/apifest08/currency/ConvertorException.java	Tue Oct 07 11:05:34 2008 +0200
    91.3 @@ -0,0 +1,25 @@
    91.4 +package org.apidesign.apifest08.currency;
    91.5 +
    91.6 +/**
    91.7 + * Common Convertor exception.
    91.8 + * 
    91.9 + * @author arnostvalicek
   91.10 + */
   91.11 +public class ConvertorException extends RuntimeException {
   91.12 +
   91.13 +    public ConvertorException(Throwable cause) {
   91.14 +        super(cause);
   91.15 +    }
   91.16 +
   91.17 +    public ConvertorException(String message, Throwable cause) {
   91.18 +        super(message, cause);
   91.19 +    }
   91.20 +
   91.21 +    public ConvertorException(String message) {
   91.22 +        super(message);
   91.23 +    }
   91.24 +
   91.25 +    public ConvertorException() {
   91.26 +    }
   91.27 +  
   91.28 +}
    92.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    92.2 +++ b/task3/solution13/src/org/apidesign/apifest08/currency/ExchangeRate.java	Tue Oct 07 11:05:34 2008 +0200
    92.3 @@ -0,0 +1,68 @@
    92.4 +
    92.5 +package org.apidesign.apifest08.currency;
    92.6 +
    92.7 +import java.math.BigDecimal;
    92.8 +
    92.9 +/**
   92.10 + * Exchange rate value. Contains <code>from</code> and <code>to</code> value.
   92.11 + * 
   92.12 + * @author arnostvalicek
   92.13 + */
   92.14 +public class ExchangeRate {
   92.15 +    private BigDecimal numberFor;
   92.16 +    private BigDecimal numberGet;
   92.17 +
   92.18 +    /**
   92.19 +     * Constructor for new exchange rate holding two values - <em>from value</em> and <em>to value</em>
   92.20 +     * @param fromValue Exchange rate <em>from value</em>
   92.21 +     * @param toValue Exchange rate <em>to value</em>
   92.22 +     */
   92.23 +    public  ExchangeRate(BigDecimal fromValue, BigDecimal toValue) {
   92.24 +        this.numberFor = fromValue;
   92.25 +        this.numberGet = toValue;
   92.26 +    }
   92.27 +    
   92.28 +    /**
   92.29 +     * Create new instance of <code>ExchangeRate</code> based on provided exchange rate, but swapping its
   92.30 +     * <em>from</em> and <em>to</em> value.
   92.31 +     * <p>
   92.32 +     * Provided exchange rate is not chaged, this method returns different instance describing reverted exchange rate.
   92.33 +     * 
   92.34 +     * @param rate Exchange rate which describes rate to be reverted.
   92.35 +     * @return Instance of reverted rate.
   92.36 +     */
   92.37 +    public static ExchangeRate createRevertedRate(ExchangeRate rate) {
   92.38 +        ExchangeRate reverted = new ExchangeRate(rate.getToValue(), rate.getFromValue());
   92.39 +        return reverted;
   92.40 +    }
   92.41 +
   92.42 +    @Override
   92.43 +    public String toString() {
   92.44 +        return "for "+numberFor+" recieve "+numberGet+" @"+getClass().getName();
   92.45 +    }
   92.46 +    
   92.47 +    /**
   92.48 +     * Return exchange rate <em>from</em> value stored in this object.
   92.49 +     * @return Returns <em>from</em> value for this exchange rate.
   92.50 +     */
   92.51 +    public BigDecimal getFromValue() {
   92.52 +        return numberFor;
   92.53 +    }
   92.54 +    
   92.55 +    /**
   92.56 +     * Return exchange rate <em>to</em> value stored in this object.
   92.57 +     * @return Returns <em>to</em> value for this exchange rate.
   92.58 +     */
   92.59 +    public BigDecimal getToValue() {
   92.60 +        return numberGet;
   92.61 +    }
   92.62 +    
   92.63 +    
   92.64 +//    public ExchangeRate createExchangeRate(BigDecimal forValue, BigDecimal getValue) {
   92.65 +//        ExchangeRate rate = new ExchangeRate(forValue, getValue);
   92.66 +//        return rate;
   92.67 +//    }
   92.68 +    
   92.69 +    
   92.70 +    
   92.71 +}
    93.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    93.2 +++ b/task3/solution13/src/org/apidesign/apifest08/currency/ExchangeRateProvider.java	Tue Oct 07 11:05:34 2008 +0200
    93.3 @@ -0,0 +1,152 @@
    93.4 +
    93.5 +package org.apidesign.apifest08.currency;
    93.6 +
    93.7 +import java.math.BigDecimal;
    93.8 +import java.util.Date;
    93.9 +import java.util.HashMap;
   93.10 +import java.util.Map;
   93.11 +
   93.12 +/**
   93.13 + * Exchange rate provider. Provides fixed exchange rate which does not depend
   93.14 + * on date (method {@link #getExchangeRate()} ).
   93.15 + * 
   93.16 + * Date dependend exchange rate to be implemented.
   93.17 + * 
   93.18 + * @author arnostvalicek
   93.19 + */
   93.20 +public class ExchangeRateProvider {
   93.21 +    BigDecimal fromValue, toValue;
   93.22 +    ConvertorCurrency fromCurrency, toCurrency;
   93.23 +    
   93.24 +    Map exchangeRateMap = new HashMap();
   93.25 +
   93.26 +    /**
   93.27 +     * Simple constructor for <code>ExchangeRateProviderM</code> which can provide fixed exchange rate.
   93.28 +     * 
   93.29 +     * Describes conversion <em>from ONE</em> to <em>to ONE</em> currency.
   93.30 +     * 
   93.31 +     * @param fromValue From value. BigDecimal value, precision should be set to currency precision.
   93.32 +     * @param fromCurrency From currency.
   93.33 +     * @param toValue To value. BigDecimal value, precision should be set to currency precision.
   93.34 +     * @param toCurrency To currency.
   93.35 +     * @deprecated deprecated since task2. Use {@link #createExchangeRateProvider() } instead of this constructor.
   93.36 +     */
   93.37 +    public ExchangeRateProvider(BigDecimal fromValue, ConvertorCurrency fromCurrency, BigDecimal toValue, ConvertorCurrency toCurrency) {
   93.38 +        this.fromValue = fromValue;
   93.39 +        this.toValue = toValue;
   93.40 +        this.fromCurrency = fromCurrency;
   93.41 +        this.toCurrency = toCurrency;
   93.42 +    }
   93.43 +    
   93.44 +    private ExchangeRateProvider() {
   93.45 +        
   93.46 +    }
   93.47 +    
   93.48 +    /**
   93.49 +     * Static method to create new exchange rate provider. This exchange rate provider does not contain
   93.50 +     * any exchange rates (this is difference to public constructor).
   93.51 +     * @return New <code>ExchangeRateProvider</code>
   93.52 +     */
   93.53 +    public static ExchangeRateProvider createExchangeRateProvider() {
   93.54 +        ExchangeRateProvider provider = new ExchangeRateProvider();
   93.55 +        return provider;
   93.56 +    }
   93.57 +    
   93.58 +    /**
   93.59 +     * Add new exchange rate to <code></code> to this exchange rate provider.
   93.60 +     * <p>
   93.61 +     * Example of specifiing conversion rate: 100 SKK == 80 CZK:<br>
   93.62 +     * <code>addFixedCurencyRate(ConvertorCurrency.getInstance("SKK"), new BigDecimal(100), ConvertorCurrency.getInstance("CZK"),  new BigDecimal(80));</code>
   93.63 +     * <p>
   93.64 +     * 
   93.65 +     * @param fromCurrency Source currency.
   93.66 +     * @param fromValue Valye for from currency.
   93.67 +     * @param toCurrency Target currency.
   93.68 +     * @param toValue Value for target currency.
   93.69 +     */
   93.70 +    public synchronized void addFixedCurencyRate(ConvertorCurrency fromCurrency, BigDecimal fromValue, ConvertorCurrency toCurrency, BigDecimal toValue) {
   93.71 +        if (fromValue==null) {
   93.72 +            throw new NullPointerException("fromValue can't be null");
   93.73 +        }
   93.74 +        if (toValue==null) {
   93.75 +            throw new NullPointerException("toValue can't be null");
   93.76 +        }
   93.77 +        Map map2 = (Map) exchangeRateMap.get(fromCurrency);
   93.78 +        if (map2==null) {
   93.79 +            map2 = new HashMap();
   93.80 +            exchangeRateMap.put(fromCurrency, map2);
   93.81 +        }
   93.82 +        
   93.83 +        ExchangeRate rate = new ExchangeRate(fromValue, toValue);
   93.84 +        map2.put(toCurrency, rate);
   93.85 +    }
   93.86 +    
   93.87 +    /**
   93.88 +     * Get fixed exange rate for currencies (from->to).
   93.89 +     * @return Returns exchange rate.
   93.90 +     * @deprecated deprecated since task2. Use {@link #getExchangeRate(ConvertorCurrency, ConvertorCurrency) }
   93.91 +     */
   93.92 +    public ExchangeRate getExchangeRate() {
   93.93 +        return new ExchangeRate(fromValue, toValue);
   93.94 +    }
   93.95 +
   93.96 +    
   93.97 +    /**
   93.98 +     * Get fixed exange rate for currencies (from->to).
   93.99 +     * @return Returns exchange rate or <code>null</code> if exchange rate not found.
  93.100 +     */
  93.101 +    public ExchangeRate getExchangeRate(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency) {
  93.102 +        return getExchangeRateImpl(fromCurrency, toCurrency);
  93.103 +    }
  93.104 +    
  93.105 +    /**
  93.106 +     * Get fixed exange rate for currencies (from->to) or reversed exchange rate (to->from).
  93.107 +     * @return Returns exchange rate or <code>null</code> if exchange rate not found.
  93.108 +     */
  93.109 +    public ExchangeRate getReversibleExchangeRate(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency) {
  93.110 +       ExchangeRate rate = getExchangeRateImpl(fromCurrency, toCurrency);
  93.111 +       if (rate==null) {
  93.112 +           ExchangeRate revertedRate = getExchangeRateImpl(toCurrency, fromCurrency);
  93.113 +           if (revertedRate!=null) {
  93.114 +            rate = ExchangeRate.createRevertedRate(revertedRate);
  93.115 +           }
  93.116 +       }
  93.117 +       return rate;
  93.118 +    }
  93.119 +        
  93.120 +
  93.121 +    
  93.122 +    /**
  93.123 +     * Get exchange rate for currencies (from->to) based on provided date.
  93.124 +     * @param date Date for which exchange rate should be provided.
  93.125 +     * @return Returns exchange rate 
  93.126 +     * @deprecated deprecated since task2. No real implementation in version2.
  93.127 +     */
  93.128 +    public ExchangeRate getExchangeRate(Date date) {
  93.129 +        return new ExchangeRate(fromValue, toValue);
  93.130 +    }
  93.131 +    
  93.132 +
  93.133 +    ConvertorCurrency getFromCurrency() {
  93.134 +        return fromCurrency;
  93.135 +    }
  93.136 +    
  93.137 +    ConvertorCurrency getToCurrency() {
  93.138 +        return toCurrency;
  93.139 +    }
  93.140 +
  93.141 +    private ExchangeRate getExchangeRateImpl(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency) {
  93.142 +        if (fromValue != null && toValue != null && fromCurrency.equals(this.fromCurrency) && toCurrency.equals(this.toCurrency)) {
  93.143 +            return new ExchangeRate(fromValue, toValue);
  93.144 +        }
  93.145 +        //return new ExchangeRate(fromValue, toValue);
  93.146 +        Map map2 = (Map) exchangeRateMap.get(fromCurrency);
  93.147 +        if (map2 == null) {
  93.148 +            return null;
  93.149 +        }
  93.150 +        ExchangeRate result = (ExchangeRate) map2.get(toCurrency);
  93.151 +        return result;
  93.152 +    }
  93.153 +    
  93.154 +
  93.155 +}
    94.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    94.2 +++ b/task3/solution13/test/org/apidesign/apifest08/test/Task1Test.java	Tue Oct 07 11:05:34 2008 +0200
    94.3 @@ -0,0 +1,223 @@
    94.4 +package org.apidesign.apifest08.test;
    94.5 +
    94.6 +import java.math.BigDecimal;
    94.7 +import junit.framework.TestCase;
    94.8 +import org.apidesign.apifest08.currency.ConversionResult;
    94.9 +import org.apidesign.apifest08.currency.Convertor;
   94.10 +import org.apidesign.apifest08.currency.ConvertorCurrency;
   94.11 +import org.apidesign.apifest08.currency.ExchangeRateProvider;
   94.12 +import org.apidesign.apifest08.currency.ConversionNotSupportedException;
   94.13 +
   94.14 +/** Finish the Convertor API, and then write bodies of methods inside
   94.15 + * of this class to match the given tasks. To fullfil your task, use the
   94.16 + * API define in the <code>org.apidesign.apifest08.currency</code> package.
   94.17 + * Do not you reflection, or other hacks as your code
   94.18 + * shall run without any runtime permissions.
   94.19 + */
   94.20 +public class Task1Test extends TestCase {
   94.21 +    public Task1Test(String testName) {
   94.22 +        super(testName);
   94.23 +    }
   94.24 +
   94.25 +    @Override
   94.26 +    protected void setUp() throws Exception {
   94.27 +    }
   94.28 +
   94.29 +    @Override
   94.30 +    protected void tearDown() throws Exception {
   94.31 +    }
   94.32 +
   94.33 +    /** Create convertor that understands two currencies, CZK and
   94.34 +     *  USD. Make 1 USD == 17 CZK.
   94.35 +     *
   94.36 +     * Creation of the convertor shall not require subclassing of any class
   94.37 +     * or interface on the client side.
   94.38 +     *
   94.39 +     * @return prepared convertor ready for converting USD to CZK and CZK to USD
   94.40 +     */
   94.41 +    public static Convertor createCZKtoUSD() {
   94.42 +        ConvertorCurrency fromCurrency = ConvertorCurrency.getInstance("CZK");
   94.43 +        ConvertorCurrency toCurrency = ConvertorCurrency.getInstance("USD");
   94.44 +        ExchangeRateProvider exchangeRateProvider = new ExchangeRateProvider(new BigDecimal(17), fromCurrency, new BigDecimal(1), toCurrency);
   94.45 +        
   94.46 +        return Convertor.createConvertor(exchangeRateProvider);
   94.47 +    }
   94.48 +
   94.49 +    /** Create convertor that understands two currencies, CZK and
   94.50 +     *  SKK. Make 100 SKK == 80 CZK.
   94.51 +     *
   94.52 +     * Creation of the convertor shall not require subclassing of any class
   94.53 +     * or interface on the client side.
   94.54 +     * 
   94.55 +     * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
   94.56 +     */
   94.57 +    public static Convertor createSKKtoCZK() {
   94.58 +        ConvertorCurrency fromCurrency = ConvertorCurrency.getInstance("SKK");
   94.59 +        ConvertorCurrency toCurrency = ConvertorCurrency.getInstance("CZK");
   94.60 +        ExchangeRateProvider exchangeRateProvider = new ExchangeRateProvider(new BigDecimal(100), fromCurrency, new BigDecimal(80), toCurrency);
   94.61 +        
   94.62 +        return Convertor.createConvertor(exchangeRateProvider);
   94.63 +    }
   94.64 +    
   94.65 +    
   94.66 +    public static Convertor createCZKtoYEN() {
   94.67 +        ConvertorCurrency fromCurrency = ConvertorCurrency.getInstance("CZK");
   94.68 +        ConvertorCurrency toCurrency = ConvertorCurrency.getInstance("JPY");
   94.69 +        ExchangeRateProvider exchangeRateProvider = new ExchangeRateProvider(new BigDecimal(1), fromCurrency, new BigDecimal(1), toCurrency);
   94.70 +        
   94.71 +        return Convertor.createConvertor(exchangeRateProvider);
   94.72 +    }
   94.73 +    
   94.74 +    /** Use the convertor from <code>createCZKtoUSD</code> method and do few conversions
   94.75 +     * with it.
   94.76 +     */
   94.77 +    public void testCurrencyCZKUSD() throws Exception {
   94.78 +        Convertor convertCzkUsd = createCZKtoUSD();
   94.79 +
   94.80 +        {
   94.81 +            // convert $1 to CZK using c:
   94.82 +            ConversionResult result = convertCzkUsd.convertBack(new BigDecimal(1));
   94.83 +            assertEquals("Result is 17 CZK", new BigDecimal("17.00"), result.getConverted());
   94.84 +            assertEquals("No Remainer", BigDecimal.ZERO, result.getRemainder());
   94.85 +        }
   94.86 +
   94.87 +        {
   94.88 +            // convert 17CKZ to $ using c:
   94.89 +            ConversionResult result = convertCzkUsd.convert(new BigDecimal(17));
   94.90 +            assertEquals("Result is 1 $", new BigDecimal("1.00"), result.getConverted());
   94.91 +            assertEquals("No Remainer", BigDecimal.ZERO, result.getRemainder());
   94.92 +        }
   94.93 +
   94.94 +        {
   94.95 +            // convert $5 to CZK using c:
   94.96 +            ConversionResult result = convertCzkUsd.convertBack(new BigDecimal(5));
   94.97 +            assertEquals("Result is 85 CZK", new BigDecimal("85.00"), result.getConverted());
   94.98 +            assertEquals("No Remainer", BigDecimal.ZERO, result.getRemainder());
   94.99 +        }
  94.100 +        
  94.101 +        {
  94.102 +            // convert $8 to CZK
  94.103 +            ConversionResult result = convertCzkUsd.convertBack(new BigDecimal(8));
  94.104 +            assertEquals("Result is 136 CZK", new BigDecimal("136.00"), result.getConverted());
  94.105 +            assertEquals("No Remainer", BigDecimal.ZERO, result.getRemainder());
  94.106 +        }
  94.107 +
  94.108 +        {
  94.109 +            // convert 1003CZK to USD
  94.110 +            ConversionResult result = convertCzkUsd.convert(new BigDecimal(1003));
  94.111 +            assertEquals("Result is 59 USD", new BigDecimal("59.00"), result.getConverted());
  94.112 +            assertEquals("No Remainer", BigDecimal.ZERO, result.getRemainder());
  94.113 +        }
  94.114 +    }
  94.115 +
  94.116 +    /** Use the convertor from <code>createSKKtoCZK</code> method and do few conversions
  94.117 +     * with it.
  94.118 +     */
  94.119 +    public void testCurrencySKKCZK() throws Exception {
  94.120 +        Convertor convertSkkCzk = createSKKtoCZK();
  94.121 +        {
  94.122 +            // convert 100SKK using c:
  94.123 +            ConversionResult result = convertSkkCzk.convert(new BigDecimal(100));
  94.124 +            assertEquals("Result is 80 CZK", new BigDecimal("80.00"), result.getConverted());
  94.125 +        }
  94.126 +        {
  94.127 +            // convert 80CZK using c:
  94.128 +            ConversionResult result = convertSkkCzk.convertBack(new BigDecimal(80));
  94.129 +            assertEquals("Result is 100 SKK", new BigDecimal("100.00"), result.getConverted());
  94.130 +        }
  94.131 +        
  94.132 +        {
  94.133 +            // convert 16CZK using c:
  94.134 +            ConversionResult result = convertSkkCzk.convertBack(new BigDecimal(16));
  94.135 +            assertEquals("Result is 20 SKK", new BigDecimal("20.00"), result.getConverted());
  94.136 +        }
  94.137 +
  94.138 +        {
  94.139 +            // convert 500SKK to CZK
  94.140 +            ConversionResult result = convertSkkCzk.convert(new BigDecimal(500));
  94.141 +            assertEquals("Result is 400 CZK", new BigDecimal("400.00"), result.getConverted());
  94.142 +            assertEquals("No Remainer", BigDecimal.ZERO, result.getRemainder());            
  94.143 +        }
  94.144 +        
  94.145 +        {
  94.146 +            // convert 501SKK to CZK
  94.147 +            ConversionResult result = convertSkkCzk.convert(new BigDecimal(501));
  94.148 +            assertEquals("Result is 400 CZK", new BigDecimal("400.80"), result.getConverted());
  94.149 +            assertEquals("No Remainer", BigDecimal.ZERO, result.getRemainder());
  94.150 +            
  94.151 +        }
  94.152 +    }
  94.153 +    
  94.154 +    /**
  94.155 +     * Convert SKK to CZK. Convertor can't convert whole amout (can't convert one SKK cent to CZK). Remaining
  94.156 +     * amount is stored in remainder result.
  94.157 +     * 
  94.158 +     * Test is currently failing, because implementation can't handle this case.
  94.159 +     */
  94.160 +//    public void testConvertSmallUnits_failing() {
  94.161 +//        Convertor convertSkkCzk = createSKKtoCZK();
  94.162 +//        {
  94.163 +//            // convert 501SKK to CZK
  94.164 +//            ConversionResult result = convertSkkCzk.convert(new BigDecimal("501.01"));
  94.165 +//            assertEquals("Result is 400 CZK", new BigDecimal("400.80"), result.getConverted());
  94.166 +//            assertEquals("No Remainer", new BigDecimal("0.01"), result.getRemainder());
  94.167 +//            
  94.168 +//        }
  94.169 +//        
  94.170 +//    }
  94.171 +    
  94.172 +    /**
  94.173 +     * Test converting from CZK to JPY. Remained has scale of CZK.
  94.174 +     * 
  94.175 +     * This test is currently failing, because converter implementation currently can't handle conversion from "cent" to "no-cent" currency.
  94.176 +     */
  94.177 +//    public void testConvertCzkToJpy_failing() {
  94.178 +//        Convertor convertSkkCzk = createCZKtoYEN();
  94.179 +//        {
  94.180 +//            // convert 501SKK to CZK
  94.181 +//            ConversionResult result = convertSkkCzk.convert(new BigDecimal("120.00"));
  94.182 +//            assertEquals("Result is 120 YEN", new BigDecimal("120"), result.getConverted());
  94.183 +//            assertEquals("No Remainer", new BigDecimal("0.00"), result.getRemainder());
  94.184 +//            
  94.185 +//        }
  94.186 +//    }
  94.187 +    
  94.188 +    /**
  94.189 +     * Test converting from JPY to CZK. Remained has scale of JPY.
  94.190 +     * 
  94.191 +     * This test is currently failing, because converter implementation currently can't handle conversion from "cent" to "no-cent" currency.
  94.192 +     */
  94.193 +//    public void testConvertJpyToCzk_failing() {
  94.194 +//        Convertor convertSkkCzk = createCZKtoYEN();
  94.195 +//        {
  94.196 +//            // convert 501SKK to CZK
  94.197 +//            ConversionResult result = convertSkkCzk.convert(new BigDecimal("120.00"));
  94.198 +//            assertEquals("Result is 120 YEN", new BigDecimal("120"), result.getConverted());
  94.199 +//            assertEquals("No Remainer", new BigDecimal("0"), result.getRemainder());
  94.200 +//            
  94.201 +//        }
  94.202 +//    }
  94.203 +    
  94.204 +    public void testCannotConvertToSKKwithCZKUSDConvertor() throws Exception {
  94.205 +            Convertor c = createCZKtoUSD();
  94.206 +            // convert $5 to SKK, the API shall say this is not possible
  94.207 +            try {
  94.208 +                c.convert(ConvertorCurrency.getInstance("USD"), ConvertorCurrency.getInstance("SKK"), new BigDecimal(5));
  94.209 +                fail();
  94.210 +            } catch (ConversionNotSupportedException e) {
  94.211 +                //expected error;
  94.212 +                assertEquals("Exception From USD", "USD",e.getFromCurrecyCode());
  94.213 +                assertEquals("Exception To SKK", "SKK",e.getToCurrecyCode());
  94.214 +            }
  94.215 +            // convert 500 SKK to CZK, the API shall say this is not possible
  94.216 +            try {
  94.217 +                c.convert(ConvertorCurrency.getInstance("SKK"), ConvertorCurrency.getInstance("CZK"), new BigDecimal(500));
  94.218 +                fail();
  94.219 +            } catch (ConversionNotSupportedException e) {
  94.220 +                assertEquals("Exception From USD", "SKK",e.getFromCurrecyCode());
  94.221 +                assertEquals("Exception To SKK", "CZK",e.getToCurrecyCode());            }
  94.222 +    }
  94.223 +    
  94.224 + 
  94.225 +}
  94.226 +
    95.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    95.2 +++ b/task3/solution13/test/org/apidesign/apifest08/test/Task2Test.java	Tue Oct 07 11:05:34 2008 +0200
    95.3 @@ -0,0 +1,136 @@
    95.4 +package org.apidesign.apifest08.test;
    95.5 +
    95.6 +import java.math.BigDecimal;
    95.7 +import junit.framework.TestCase;
    95.8 +import org.apidesign.apifest08.currency.Convertor;
    95.9 +import org.apidesign.apifest08.currency.ConvertorCurrency;
   95.10 +import org.apidesign.apifest08.currency.ExchangeRateProvider;
   95.11 +
   95.12 +/** There are many currencies around the world and many banks manipulate
   95.13 + * with more than one or two at the same time. As banks are usually the
   95.14 + * best paying clients, which is true even in case of your Convertor API,
   95.15 + * it is reasonable to listen to their requests.
   95.16 + * <p>
   95.17 + * The quest for today is to enhance your existing convertor API to hold
   95.18 + * information about many currencies and allow conversions between any of them.
   95.19 + * Also, as conversion rates for diferent currencies usually arise from various
   95.20 + * bank departments, there is another important need. There is a need to
   95.21 + * compose two convertors into one by merging all the information about
   95.22 + * currencies they know about.
   95.23 + */
   95.24 +public class Task2Test extends TestCase {
   95.25 +    private static ConvertorCurrency currencyCZK = ConvertorCurrency.getInstance("CZK");
   95.26 +    private static ConvertorCurrency currencySKK = ConvertorCurrency.getInstance("SKK");
   95.27 +    private static ConvertorCurrency currencyUSD = ConvertorCurrency.getInstance("USD");
   95.28 +  
   95.29 +    public Task2Test(String testName) {
   95.30 +        super(testName);
   95.31 +    }
   95.32 +
   95.33 +    @Override
   95.34 +    protected void setUp() throws Exception {
   95.35 +
   95.36 +    }
   95.37 +
   95.38 +    @Override
   95.39 +    protected void tearDown() throws Exception {
   95.40 +    }
   95.41 +    
   95.42 +    public static Convertor createUsdToSkkConvertor() {
   95.43 +        ConvertorCurrency fromCurrency = currencyUSD;
   95.44 +        ConvertorCurrency toCurrency = currencyUSD;
   95.45 +        ExchangeRateProvider exchangeRateProvider = new ExchangeRateProvider(new BigDecimal(1), fromCurrency, new BigDecimal(20), toCurrency);
   95.46 +        
   95.47 +        return Convertor.createConvertor(exchangeRateProvider);
   95.48 +        
   95.49 +    }
   95.50 +
   95.51 +    // As in Task1Test, keep in mind, that there are three parts
   95.52 +    // of the whole system:
   95.53 +    // 1. there is someone who knows the current exchange rate
   95.54 +    // 2. there is someone who wants to do the conversion
   95.55 +    // 3. there is the API between 1. and 2. which allows them to communicate
   95.56 +    // 
   95.57 +    // Please backward compatibly enhance your existing API to support following
   95.58 +    // usecases:
   95.59 +    //
   95.60 +    
   95.61 +    /** Create convertor that understands two currencies, CZK and
   95.62 +     *  SKK. Make 100 SKK == 75 CZK. This is method for the group of users that
   95.63 +     *  knows the exchange rate, and needs to use the API to create objects
   95.64 +     *  with the exchange rate. Anyone shall be ready to call this method without
   95.65 +     *  any other method being called previously. The API itself shall know
   95.66 +     *  nothing about any rates, before this method is called.
   95.67 +     */
   95.68 +    public static Convertor createTripleConvertor() {
   95.69 +        ExchangeRateProvider exRateProvider = ExchangeRateProvider.createExchangeRateProvider();
   95.70 +        
   95.71 +        // Rates: 1USD = 15CZK
   95.72 +        exRateProvider.addFixedCurencyRate(currencyUSD, new BigDecimal(1),currencyCZK,  new BigDecimal(15));
   95.73 +        
   95.74 +        // Rates: 1USD = 20SKK
   95.75 +        exRateProvider.addFixedCurencyRate(currencyUSD, new BigDecimal(1), currencySKK,  new BigDecimal(20));
   95.76 +        
   95.77 +        // Rates: 75CZK = 100SKK
   95.78 +        exRateProvider.addFixedCurencyRate(currencyCZK, new BigDecimal(75), currencySKK,  new BigDecimal(100));
   95.79 +        
   95.80 +        Convertor c = Convertor.createConvertor(exRateProvider);
   95.81 +        
   95.82 +        return c;
   95.83 +    }
   95.84 +
   95.85 +    /** Define convertor that understands three currencies. Use it.
   95.86 +     */
   95.87 +    public void testConvertorForUSDandCZKandSKK() throws Exception {
   95.88 +        Convertor c = createTripleConvertor();
   95.89 +
   95.90 +        // convert $5 to CZK using c:
   95.91 +        assertEquals("Result is 75 CZK",new BigDecimal("75.00"),c.convertWithReversibleRates(currencyUSD, currencyCZK, new BigDecimal(5)).getConverted());
   95.92 +
   95.93 +
   95.94 +        // convert $5 to SKK using c:
   95.95 +        assertEquals("Result is 100 SKK",new BigDecimal("100.00"),c.convertWithReversibleRates(currencyUSD, currencySKK, new BigDecimal(5)).getConverted());
   95.96 +
   95.97 +        // convert 200SKK to CZK using c:
   95.98 +        assertEquals("Result is 150 CZK",new BigDecimal("150.00"),c.convertWithReversibleRates(currencySKK, currencyCZK, new BigDecimal(200)).getConverted());
   95.99 +
  95.100 +        // convert 200SKK to USK using c:
  95.101 +        // assertEquals("Result is 10 USD");
  95.102 +    }
  95.103 +
  95.104 +    /** Merge all currency rates of convertor 1 with convertor 2.
  95.105 +     * Implement this using your API, preferably this method just delegates
  95.106 +     * into some API method which does the actual work, without requiring
  95.107 +     * API clients to code anything complex.
  95.108 +     */
  95.109 +    public static Convertor merge(Convertor one, Convertor two) {
  95.110 +        return Convertor.createConvertorAsMerge(new Convertor[]{one, two});
  95.111 +    }
  95.112 +
  95.113 +    /** Join the convertors from previous task, Task1Test and show that it
  95.114 +     * can be used to do reasonable conversions.
  95.115 +     */
  95.116 +    public void testConvertorComposition() throws Exception {
  95.117 +        Convertor c = merge(
  95.118 +            Task1Test.createCZKtoUSD(),
  95.119 +            Task1Test.createSKKtoCZK()
  95.120 +        );
  95.121 +
  95.122 +        // convert $5 to CZK using c:
  95.123 +        assertEquals("Result is 85 CZK",new BigDecimal("85.00"),c.convertWithReversibleRates(currencyUSD, currencyCZK, new BigDecimal(5)).getConverted());
  95.124 +
  95.125 +        // convert $8 to CZK using c:
  95.126 +        // assertEquals("Result is 136 CZK");
  95.127 +        assertEquals("Result is 136 CZK",new BigDecimal("136.00"),c.convertWithReversibleRates(currencyUSD, currencyCZK, new BigDecimal(8)).getConverted());
  95.128 +
  95.129 +        // convert 1003CZK to USD using c:
  95.130 +        assertEquals("Result is 59 USD",new BigDecimal("59.00"),c.convertWithReversibleRates(currencyCZK, currencyUSD, new BigDecimal(1003)).getConverted());
  95.131 +
  95.132 +        // convert 16CZK using c:
  95.133 +        assertEquals("Result is 20 SKK",new BigDecimal("20.00"),c.convertWithReversibleRates(currencyCZK, currencySKK, new BigDecimal(16)).getConverted());
  95.134 +
  95.135 +        // convert 500SKK to CZK using c:
  95.136 +        assertEquals("Result is 400 CZK",new BigDecimal("400.00"),c.convertWithReversibleRates(currencySKK, currencyCZK, new BigDecimal(500)).getConverted());
  95.137 +
  95.138 +    }
  95.139 +}