1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/task4/solution02/build.xml Sat Oct 11 23:38:46 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/task4/solution02/nbproject/build-impl.xml Sat Oct 11 23:38:46 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 "${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 "1.0"/>
2.253 + <contains string="${version-output}" substring="java version "1.1"/>
2.254 + <contains string="${version-output}" substring="java version "1.2"/>
2.255 + <contains string="${version-output}" substring="java version "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/task4/solution02/nbproject/genfiles.properties Sat Oct 11 23:38:46 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/task4/solution02/nbproject/project.properties Sat Oct 11 23:38:46 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/task4/solution02/nbproject/project.xml Sat Oct 11 23:38:46 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/task4/solution02/src/org/apidesign/apifest08/currency/CompositeConvertor.java Sat Oct 11 23:38:46 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/task4/solution02/src/org/apidesign/apifest08/currency/Convertor.java Sat Oct 11 23:38:46 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/task4/solution02/src/org/apidesign/apifest08/currency/ConvertorFactory.java Sat Oct 11 23:38:46 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. Convertor created by this method is thread safe.
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. Convertor created by this method is thread safe.
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/task4/solution02/src/org/apidesign/apifest08/currency/DefaultConvertor.java Sat Oct 11 23:38:46 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/task4/solution02/src/org/apidesign/apifest08/currency/ExtendedConvertor.java Sat Oct 11 23:38:46 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/task4/solution02/src/org/apidesign/apifest08/currency/Money.java Sat Oct 11 23:38:46 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/task4/solution02/src/org/apidesign/apifest08/currency/MoneyImpl.java Sat Oct 11 23:38:46 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/task4/solution02/test/org/apidesign/apifest08/currency/CompositeConvertorTest.java Sat Oct 11 23:38:46 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/task4/solution02/test/org/apidesign/apifest08/test/ConvertorFactoryTest.java Sat Oct 11 23:38:46 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/task4/solution02/test/org/apidesign/apifest08/test/ConvertorTest.java Sat Oct 11 23:38:46 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/task4/solution02/test/org/apidesign/apifest08/test/MoneyTest.java Sat Oct 11 23:38:46 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/task4/solution02/test/org/apidesign/apifest08/test/OnlineConvertor.java Sat Oct 11 23:38:46 2008 +0200
17.3 @@ -0,0 +1,54 @@
17.4 +package org.apidesign.apifest08.test;
17.5 +
17.6 +import java.math.BigDecimal;
17.7 +import java.util.Currency;
17.8 +
17.9 +import org.apidesign.apifest08.currency.ConvertorFactory;
17.10 +import org.apidesign.apifest08.currency.ExtendedConvertor;
17.11 +import org.apidesign.apifest08.currency.Money;
17.12 +import org.apidesign.apifest08.currency.MoneyImpl;
17.13 +
17.14 +/**
17.15 + * Third party implementation of the convertor. IT IS NOT THREAD SAFE.
17.16 + * @author lukas
17.17 + *
17.18 + */
17.19 +class OnlineConvertor implements ExtendedConvertor {
17.20 +
17.21 + private static final BigDecimal LOWER_LIMIT = BigDecimal.valueOf(15);
17.22 + private static final BigDecimal HIGHER_LIMIT = BigDecimal.valueOf(16);
17.23 +
17.24 + private static final Currency USD = Currency.getInstance("USD");
17.25 + private static final Currency CZK = Currency.getInstance("CZK");
17.26 + private static final MoneyImpl ONE_USD = new MoneyImpl(1,USD);
17.27 +
17.28 + private ExtendedConvertor wrappedConvertor = ConvertorFactory.createConvertor(ONE_USD, new MoneyImpl(16, CZK));
17.29 +
17.30 + private BigDecimal increment = new BigDecimal("-0.01");
17.31 +
17.32 + public boolean isConversionSupported(Currency from, Currency to) {
17.33 + return wrappedConvertor.isConversionSupported(from, to);
17.34 + }
17.35 +
17.36 + public Money convert(Money amount, Currency destinationCurrency)
17.37 + throws IllegalArgumentException {
17.38 + Money result = wrappedConvertor.convert(amount, destinationCurrency);
17.39 + updateConvertor();
17.40 + return result;
17.41 + }
17.42 +
17.43 + /**
17.44 + * Prepares convertor for the next conversion.
17.45 + */
17.46 + private void updateConvertor() {
17.47 + BigDecimal currentRate = wrappedConvertor.convert(ONE_USD, CZK).getAmount();
17.48 + BigDecimal newRate = currentRate.add(increment);
17.49 +
17.50 + if (LOWER_LIMIT.compareTo(newRate)==0 || HIGHER_LIMIT.compareTo(newRate)==0)
17.51 + {
17.52 + increment = increment.negate();
17.53 + }
17.54 + wrappedConvertor = ConvertorFactory.createConvertor(ONE_USD, new MoneyImpl(newRate, CZK));
17.55 + }
17.56 +
17.57 +}
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/task4/solution02/test/org/apidesign/apifest08/test/OnlineConvertorTest.java Sat Oct 11 23:38:46 2008 +0200
18.3 @@ -0,0 +1,44 @@
18.4 +package org.apidesign.apifest08.test;
18.5 +import static junit.framework.Assert.assertEquals;
18.6 +import static org.apidesign.apifest08.currency.MoneyImpl.money;
18.7 +import static org.apidesign.apifest08.test.Task1Test.CZK;
18.8 +import static org.apidesign.apifest08.test.Task1Test.USD;
18.9 +
18.10 +import java.math.BigDecimal;
18.11 +
18.12 +import org.apidesign.apifest08.currency.Convertor;
18.13 +import org.apidesign.apifest08.currency.Money;
18.14 +import org.junit.Test;
18.15 +
18.16 +public class OnlineConvertorTest {
18.17 + private static final Money ONE_USD = money(1, USD);
18.18 +
18.19 + @Test
18.20 + public void testBounce()
18.21 + {
18.22 + Convertor c = Task3Test.createOnlineCZKUSDConvertor();
18.23 +
18.24 + doBounceTest(c);
18.25 + doBounceTest(c);
18.26 +
18.27 + }
18.28 +
18.29 + private void doBounceTest(Convertor c) {
18.30 + BigDecimal expectedRate = new BigDecimal(16);
18.31 + BigDecimal increment = new BigDecimal("0.01");
18.32 +
18.33 + for (int i=0;i<100;i++)
18.34 + {
18.35 + assertEquals(money(expectedRate,CZK), c.convert(ONE_USD, CZK));
18.36 + expectedRate = expectedRate.subtract(increment);
18.37 + }
18.38 +
18.39 + assertEquals(money(15,CZK), c.convert(ONE_USD, CZK));
18.40 +
18.41 + for (int i=0;i<99;i++)
18.42 + {
18.43 + expectedRate = expectedRate.add(increment);
18.44 + assertEquals(money(expectedRate,CZK), c.convert(ONE_USD, CZK));
18.45 + }
18.46 + }
18.47 +}
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
19.2 +++ b/task4/solution02/test/org/apidesign/apifest08/test/Task1Test.java Sat Oct 11 23:38:46 2008 +0200
19.3 @@ -0,0 +1,160 @@
19.4 +package org.apidesign.apifest08.test;
19.5 +
19.6 +import java.util.Currency;
19.7 +
19.8 +import junit.framework.TestCase;
19.9 +
19.10 +import org.apidesign.apifest08.currency.Convertor;
19.11 +import org.apidesign.apifest08.currency.ConvertorFactory;
19.12 +import org.apidesign.apifest08.currency.MoneyImpl;
19.13 +
19.14 +/** Finish the Convertor API, and then write bodies of methods inside
19.15 + * of this class to match the given tasks. To fullfil your task, use the
19.16 + * API define in the <code>org.apidesign.apifest08.currency</code> package.
19.17 + * Do not you reflection, or other hacks as your code
19.18 + * shall run without any runtime permissions.
19.19 + */
19.20 +public class Task1Test extends TestCase {
19.21 +
19.22 + public static final Currency USD = Currency.getInstance("USD");
19.23 + public static final Currency CZK = Currency.getInstance("CZK");
19.24 + public static final Currency SKK = Currency.getInstance("SKK");
19.25 +
19.26 + public Task1Test(String testName) {
19.27 + super(testName);
19.28 + }
19.29 +
19.30 + @Override
19.31 + protected void setUp() throws Exception {
19.32 + }
19.33 +
19.34 + @Override
19.35 + protected void tearDown() throws Exception {
19.36 + }
19.37 +
19.38 + //
19.39 + // Imagine that there are three parts of the whole system:
19.40 + // 1. there is someone who knows the current exchange rate
19.41 + // 2. there is someone who wants to do the conversion
19.42 + // 3. there is the API between 1. and 2. which allows them to communicate
19.43 + // Please design such API
19.44 + //
19.45 +
19.46 + /** Create convertor that understands two currencies, CZK and
19.47 + * USD. Make 1 USD == 17 CZK. This is a method provided for #1 group -
19.48 + * e.g. those that know the exchange rate. They somehow need to create
19.49 + * the objects from the API and tell them the exchange rate. The API itself
19.50 + * knows nothing about any rates, before the createCZKtoUSD method is called.
19.51 + *
19.52 + * Creation of the convertor shall not require subclassing of any class
19.53 + * or interface on the client side.
19.54 + *
19.55 + * @return prepared convertor ready for converting USD to CZK and CZK to USD
19.56 + */
19.57 + public static Convertor createCZKtoUSD() {
19.58 + return ConvertorFactory.createConvertor(new MoneyImpl(17,CZK), new MoneyImpl(1,USD));
19.59 + }
19.60 +
19.61 + /** Create convertor that understands two currencies, CZK and
19.62 + * SKK. Make 100 SKK == 80 CZK. Again this is method for the #1 group -
19.63 + * it knows the exchange rate, and needs to use the API to create objects
19.64 + * with the exchange rate. Anyone shall be ready to call this method without
19.65 + * any other method being called previously. The API itself shall know
19.66 + * nothing about any rates, before this method is called.
19.67 + *
19.68 + * Creation of the convertor shall not require subclassing of any class
19.69 + * or interface on the client side.
19.70 + *
19.71 + * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
19.72 + */
19.73 + public static Convertor createSKKtoCZK() {
19.74 + return ConvertorFactory.createConvertor(new MoneyImpl(100,SKK), new MoneyImpl(80,CZK));
19.75 + }
19.76 +
19.77 + //
19.78 + // now the methods for group #2 follow:
19.79 + // this group knows nothing about exchange rates, but knows how to use
19.80 + // the API to do conversions. It somehow (by calling one of the factory
19.81 + // methods) gets objects from the API and uses them to do the conversions.
19.82 + //
19.83 +
19.84 + /** Use the convertor from <code>createCZKtoUSD</code> method and do few conversions
19.85 + * with it.
19.86 + */
19.87 + public void testCurrencyCZKUSD() throws Exception {
19.88 + Convertor c = createCZKtoUSD();
19.89 + // convert $5 to CZK using c:
19.90 + assertEquals("Result is 85 CZK",new MoneyImpl(85,CZK), c.convert(new MoneyImpl(5,USD),CZK));
19.91 +
19.92 + // convert $8 to CZK
19.93 + assertEquals("Result is 136 CZK",new MoneyImpl(136,CZK), c.convert(new MoneyImpl(8,USD),CZK));
19.94 +
19.95 + // convert 1003CZK to USD
19.96 + assertEquals("Result is 59 USD", new MoneyImpl(59,USD), c.convert(new MoneyImpl(1003,CZK),USD));
19.97 +
19.98 + }
19.99 +
19.100 + /** Use the convertor from <code>createSKKtoCZK</code> method and do few conversions
19.101 + * with it.
19.102 + */
19.103 + public void testCurrencySKKCZK() throws Exception {
19.104 + Convertor c = createSKKtoCZK();
19.105 + // convert 16CZK using c:
19.106 + assertEquals("Result is 20 SKK", new MoneyImpl(20,SKK), c.convert(new MoneyImpl(16,CZK),SKK));
19.107 +
19.108 + // convert 500SKK to CZK
19.109 + assertEquals("Result is 400 CZK", new MoneyImpl(400,CZK), c.convert(new MoneyImpl(500,SKK),CZK));
19.110 + }
19.111 +
19.112 + /** Verify that the CZK to USD convertor knows nothing about SKK.
19.113 + */
19.114 + public void testCannotConvertToSKKwithCZKUSDConvertor() throws Exception {
19.115 + Convertor c = createCZKtoUSD();
19.116 + // convert $5 to SKK, the API shall say this is not possible
19.117 + try
19.118 + {
19.119 + c.convert(new MoneyImpl(5, USD), SKK);
19.120 + fail("Exception expected");
19.121 + }
19.122 + catch(IllegalArgumentException e)
19.123 + {
19.124 + assertTrue("Ok",true);
19.125 + }
19.126 + // convert 500 SKK to CZK, the API shall say this is not possible
19.127 + try
19.128 + {
19.129 + c.convert(new MoneyImpl(500, SKK), CZK);
19.130 + fail("Exception expected");
19.131 + }
19.132 + catch(IllegalArgumentException e)
19.133 + {
19.134 + assertTrue("Ok",true);
19.135 + }
19.136 + }
19.137 +
19.138 + /** Verify that the CZK to SKK convertor knows nothing about USD.
19.139 + */
19.140 + public void testCannotConvertToUSDwithCZKSKKConvertor() throws Exception {
19.141 + Convertor c = createSKKtoCZK();
19.142 + // convert $5 to SKK, the API shall say this is not possible
19.143 + try
19.144 + {
19.145 + c.convert(new MoneyImpl(5, USD), SKK);
19.146 + fail("Exception expected");
19.147 + }
19.148 + catch(IllegalArgumentException e)
19.149 + {
19.150 + assertTrue("Ok",true);
19.151 + }
19.152 + // convert 500 CZK to USD, the API shall say this is not possible
19.153 + try
19.154 + {
19.155 + c.convert(new MoneyImpl(500, CZK), USD);
19.156 + fail("Exception expected");
19.157 + }
19.158 + catch(IllegalArgumentException e)
19.159 + {
19.160 + assertTrue("Ok",true);
19.161 + }
19.162 + }
19.163 +}
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
20.2 +++ b/task4/solution02/test/org/apidesign/apifest08/test/Task2Test.java Sat Oct 11 23:38:46 2008 +0200
20.3 @@ -0,0 +1,119 @@
20.4 +package org.apidesign.apifest08.test;
20.5 +
20.6 +import static org.apidesign.apifest08.currency.ConvertorFactory.createConvertor;
20.7 +import static org.apidesign.apifest08.currency.ConvertorFactory.mergeConvertors;
20.8 +import static org.apidesign.apifest08.currency.MoneyImpl.money;
20.9 +import static org.apidesign.apifest08.test.Task1Test.CZK;
20.10 +import static org.apidesign.apifest08.test.Task1Test.SKK;
20.11 +import static org.apidesign.apifest08.test.Task1Test.USD;
20.12 +import junit.framework.TestCase;
20.13 +
20.14 +import org.apidesign.apifest08.currency.Convertor;
20.15 +import org.apidesign.apifest08.currency.ExtendedConvertor;
20.16 +
20.17 +/** There are many currencies around the world and many banks manipulate
20.18 + * with more than one or two at the same time. As banks are usually the
20.19 + * best paying clients, which is true even in case of your Convertor API,
20.20 + * it is reasonable to listen to their requests.
20.21 + * <p>
20.22 + * The quest for today is to enhance your existing convertor API to hold
20.23 + * information about many currencies and allow conversions between any of them.
20.24 + * Also, as conversion rates for diferent currencies usually arise from various
20.25 + * bank departments, there is another important need. There is a need to
20.26 + * compose two convertors into one by merging all the information about
20.27 + * currencies they know about.
20.28 + */
20.29 +public class Task2Test extends TestCase {
20.30 + public Task2Test(String testName) {
20.31 + super(testName);
20.32 + }
20.33 +
20.34 + @Override
20.35 + protected void setUp() throws Exception {
20.36 + }
20.37 +
20.38 + @Override
20.39 + protected void tearDown() throws Exception {
20.40 + }
20.41 +
20.42 + // As in Task1Test, keep in mind, that there are three parts
20.43 + // of the whole system:
20.44 + // 1. there is someone who knows the current exchange rate
20.45 + // 2. there is someone who wants to do the conversion
20.46 + // 3. there is the API between 1. and 2. which allows them to communicate
20.47 + //
20.48 + // Please backward compatibly enhance your existing API to support following
20.49 + // usecases:
20.50 + //
20.51 +
20.52 + /** Create convertor that understands two currencies, CZK and
20.53 + * SKK. Make 100 SKK == 75 CZK. This is method for the group of users that
20.54 + * knows the exchange rate, and needs to use the API to create objects
20.55 + * with the exchange rate. Anyone shall be ready to call this method without
20.56 + * any other method being called previously. The API itself shall know
20.57 + * nothing about any rates, before this method is called.
20.58 + */
20.59 + public static Convertor createTripleConvertor() {
20.60 + // Rates: 1USD = 15CZK
20.61 + // Rates: 1USD = 20SKK
20.62 + // Rates: 75CZK = 100SKK
20.63 + return mergeConvertors(
20.64 + createConvertor(money(1, USD), money(15, CZK)),
20.65 + createConvertor(money(1, USD), money(20, SKK)),
20.66 + createConvertor(money(75, CZK), money(100, SKK))
20.67 + );
20.68 + }
20.69 +
20.70 + /** Define convertor that understands three currencies. Use it.
20.71 + */
20.72 + public void testConvertorForUSDandCZKandSKK() throws Exception {
20.73 + Convertor c = createTripleConvertor();
20.74 +
20.75 + // convert $5 to CZK using c:
20.76 + assertEquals("Result is 75 CZK", money(75, CZK),c.convert(money(5,USD), CZK));
20.77 +
20.78 + // convert $5 to SKK using c:
20.79 + assertEquals("Result is 100 SKK", money(100, SKK),c.convert(money(5,USD), SKK));
20.80 +
20.81 + // convert 200SKK to CZK using c:
20.82 + assertEquals("Result is 150 CZK", money(150, CZK),c.convert(money(200,SKK), CZK));
20.83 +
20.84 + // convert 200SKK to USK using c:
20.85 + assertEquals("Result is 10 USD", money(10, USD),c.convert(money(200,SKK), USD));
20.86 + }
20.87 +
20.88 + /** Merge all currency rates of convertor 1 with convertor 2.
20.89 + * Implement this using your API, preferably this method just delegates
20.90 + * into some API method which does the actual work, without requiring
20.91 + * API clients to code anything complex.
20.92 + */
20.93 + public static Convertor merge(Convertor one, Convertor two) {
20.94 + return mergeConvertors((ExtendedConvertor)one, (ExtendedConvertor)two);
20.95 + }
20.96 +
20.97 + /** Join the convertors from previous task, Task1Test and show that it
20.98 + * can be used to do reasonable conversions.
20.99 + */
20.100 + public void testConvertorComposition() throws Exception {
20.101 + Convertor c = merge(
20.102 + Task1Test.createCZKtoUSD(),
20.103 + Task1Test.createSKKtoCZK()
20.104 + );
20.105 +
20.106 + // convert $5 to CZK using c:
20.107 + assertEquals("Result is 85 CZK", money(85, CZK),c.convert(money(5,USD), CZK));
20.108 +
20.109 + // convert $8 to CZK using c:
20.110 + assertEquals("Result is 136 CZK", money(136, CZK),c.convert(money(8,USD), CZK));
20.111 +
20.112 + // convert 1003CZK to USD using c:
20.113 + assertEquals("Result is 59 USD", money(59, USD),c.convert(money(1003,CZK), USD));
20.114 +
20.115 + // convert 16CZK using c:
20.116 + assertEquals("Result is 20 SKK", money(20, SKK),c.convert(money(16,CZK), SKK));
20.117 +
20.118 + // convert 500SKK to CZK using c:
20.119 + assertEquals("Result is 400 CZK", money(400, CZK),c.convert(money(500,SKK), CZK));
20.120 +
20.121 + }
20.122 +}
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
21.2 +++ b/task4/solution02/test/org/apidesign/apifest08/test/Task3Test.java Sat Oct 11 23:38:46 2008 +0200
21.3 @@ -0,0 +1,100 @@
21.4 +package org.apidesign.apifest08.test;
21.5 +
21.6 +import static org.apidesign.apifest08.currency.MoneyImpl.money;
21.7 +import static org.apidesign.apifest08.test.Task1Test.CZK;
21.8 +import static org.apidesign.apifest08.test.Task1Test.SKK;
21.9 +import static org.apidesign.apifest08.test.Task1Test.USD;
21.10 +import junit.framework.TestCase;
21.11 +
21.12 +import org.apidesign.apifest08.currency.Convertor;
21.13 +
21.14 +/** The exchange rates are not always the same. They are changing. Day by day,
21.15 + * hour by hour, minute by minute. For every bank it is important to always
21.16 + * have the actual exchange rate available in the system. That is why let's
21.17 + * create a pluggable convertor that will always have up to date value of its
21.18 + * exchange rate.
21.19 + * <p>
21.20 + * The quest for today is to allow 3rd party developer to write a convertor
21.21 + * that adjusts its exchange rate everytime it is queried. This convertor is
21.22 + * written by independent vendor, the vendor knows only your Convertor API,
21.23 + * he does not know how the whole system looks and how the convertor is supposed
21.24 + * to be used.
21.25 + */
21.26 +public class Task3Test extends TestCase {
21.27 + public Task3Test(String testName) {
21.28 + super(testName);
21.29 + }
21.30 +
21.31 + @Override
21.32 + protected void setUp() throws Exception {
21.33 + }
21.34 +
21.35 + @Override
21.36 + protected void tearDown() throws Exception {
21.37 + }
21.38 +
21.39 + // Backward compatibly enhance your existing API to support following
21.40 + // usecases:
21.41 + //
21.42 +
21.43 +
21.44 + /** Without knowing anything about the surrounding system, write an
21.45 + * implementation of convertor that will return different rates everytime
21.46 + * it is queried. Convert USD to CZK and vice versa. Start with the rate of
21.47 + * 1USD = 16CZK and adjust it in favor of CZK by 0.01 CZK with every query.
21.48 + * As soon as you reach 1USD = 15CZK adjust it by 0.01 CZK in favor of USD
21.49 + * until you reach 1USD = 16CZK
21.50 + *
21.51 + * @return new instance of "online" USD and CZK convertor starting with rate 1USD = 16CZK
21.52 + */
21.53 + public static Convertor createOnlineCZKUSDConvertor() {
21.54 + // initial rate: 1USD = 16CZK
21.55 + // 2nd query 1USD = 15.99CZK
21.56 + // 3rd query 1USD = 15.98CZK
21.57 + // until 1USD = 15.00CZK
21.58 + // then 1USD = 15.01CZK
21.59 + // then 1USD = 15.02CZK
21.60 + // and so on and on up to 1USD = 16CZK
21.61 + // and then another round to 15, etc.
21.62 + return new OnlineConvertor();
21.63 + }
21.64 +
21.65 + public void testFewQueriesForOnlineConvertor() {
21.66 + Convertor c = createOnlineCZKUSDConvertor();
21.67 + doFewQueriesForOnlineConvertor(c);
21.68 + }
21.69 +
21.70 + static void doFewQueriesForOnlineConvertor(Convertor c) {
21.71 + // convert $5 to CZK using c:
21.72 + assertEquals("Result is 80 CZK", money(80,CZK), c.convert(money(5,USD), CZK));
21.73 +
21.74 + // convert $8 to CZK using c:
21.75 + assertEquals("Result is 127.92 CZK", money(127.92,CZK), c.convert(money(8,USD), CZK));
21.76 +
21.77 + // convert $1 to CZK using c:
21.78 + assertEquals("Result is 15.98 CZK", money(15.98,CZK), c.convert(money(1,USD), CZK));
21.79 +
21.80 + // convert 15.97CZK to USD using c:
21.81 + assertEquals("Result is 1 USD", money(1,USD), c.convert(money(15.97,CZK), USD));
21.82 + //assertEquals("Result is 1$");
21.83 +
21.84 + }
21.85 +
21.86 + /** Join the convertors and show they behave sane.
21.87 + */
21.88 + public void testOnlineConvertorComposition() throws Exception {
21.89 +
21.90 + Convertor c = Task2Test.merge(
21.91 + createOnlineCZKUSDConvertor(),
21.92 + Task1Test.createSKKtoCZK()
21.93 + );
21.94 +
21.95 + // convert 16CZK to SKK using c:
21.96 + assertEquals("Result is 20 SKK", money(20,SKK), c.convert(money(16,CZK), SKK));
21.97 +
21.98 + // convert 500SKK to CZK using c:
21.99 + assertEquals("Result is 400 CZK", money(400,CZK), c.convert(money(500,SKK), CZK));
21.100 +
21.101 + doFewQueriesForOnlineConvertor(c);
21.102 + }
21.103 +}
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
22.2 +++ b/task4/solution04/build.xml Sat Oct 11 23:38:46 2008 +0200
22.3 @@ -0,0 +1,69 @@
22.4 +<?xml version="1.0" encoding="UTF-8"?>
22.5 +<!-- You may freely edit this file. See commented blocks below for -->
22.6 +<!-- some examples of how to customize the build. -->
22.7 +<!-- (If you delete it and reopen the project it will be recreated.) -->
22.8 +<project name="currency" default="default" basedir=".">
22.9 + <description>Builds, tests, and runs the project.</description>
22.10 + <import file="nbproject/build-impl.xml"/>
22.11 + <!--
22.12 +
22.13 + There exist several targets which are by default empty and which can be
22.14 + used for execution of your tasks. These targets are usually executed
22.15 + before and after some main targets. They are:
22.16 +
22.17 + -pre-init: called before initialization of project properties
22.18 + -post-init: called after initialization of project properties
22.19 + -pre-compile: called before javac compilation
22.20 + -post-compile: called after javac compilation
22.21 + -pre-compile-single: called before javac compilation of single file
22.22 + -post-compile-single: called after javac compilation of single file
22.23 + -pre-compile-test: called before javac compilation of JUnit tests
22.24 + -post-compile-test: called after javac compilation of JUnit tests
22.25 + -pre-compile-test-single: called before javac compilation of single JUnit test
22.26 + -post-compile-test-single: called after javac compilation of single JUunit test
22.27 + -pre-jar: called before JAR building
22.28 + -post-jar: called after JAR building
22.29 + -post-clean: called after cleaning build products
22.30 +
22.31 + (Targets beginning with '-' are not intended to be called on their own.)
22.32 +
22.33 + Example of inserting an obfuscator after compilation could look like this:
22.34 +
22.35 + <target name="-post-compile">
22.36 + <obfuscate>
22.37 + <fileset dir="${build.classes.dir}"/>
22.38 + </obfuscate>
22.39 + </target>
22.40 +
22.41 + For list of available properties check the imported
22.42 + nbproject/build-impl.xml file.
22.43 +
22.44 +
22.45 + Another way to customize the build is by overriding existing main targets.
22.46 + The targets of interest are:
22.47 +
22.48 + -init-macrodef-javac: defines macro for javac compilation
22.49 + -init-macrodef-junit: defines macro for junit execution
22.50 + -init-macrodef-debug: defines macro for class debugging
22.51 + -init-macrodef-java: defines macro for class execution
22.52 + -do-jar-with-manifest: JAR building (if you are using a manifest)
22.53 + -do-jar-without-manifest: JAR building (if you are not using a manifest)
22.54 + run: execution of project
22.55 + -javadoc-build: Javadoc generation
22.56 + test-report: JUnit report generation
22.57 +
22.58 + An example of overriding the target for project execution could look like this:
22.59 +
22.60 + <target name="run" depends="currency-impl.jar">
22.61 + <exec dir="bin" executable="launcher.exe">
22.62 + <arg file="${dist.jar}"/>
22.63 + </exec>
22.64 + </target>
22.65 +
22.66 + Notice that the overridden target depends on the jar target and not only on
22.67 + the compile target as the regular run target does. Again, for a list of available
22.68 + properties which you can use, check the target you are overriding in the
22.69 + nbproject/build-impl.xml file.
22.70 +
22.71 + -->
22.72 +</project>
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
23.2 +++ b/task4/solution04/nbproject/build-impl.xml Sat Oct 11 23:38:46 2008 +0200
23.3 @@ -0,0 +1,642 @@
23.4 +<?xml version="1.0" encoding="UTF-8"?>
23.5 +<!--
23.6 +*** GENERATED FROM project.xml - DO NOT EDIT ***
23.7 +*** EDIT ../build.xml INSTEAD ***
23.8 +
23.9 +For the purpose of easier reading the script
23.10 +is divided into following sections:
23.11 +
23.12 + - initialization
23.13 + - compilation
23.14 + - jar
23.15 + - execution
23.16 + - debugging
23.17 + - javadoc
23.18 + - junit compilation
23.19 + - junit execution
23.20 + - junit debugging
23.21 + - applet
23.22 + - cleanup
23.23 +
23.24 + -->
23.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">
23.26 + <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
23.27 + <!--
23.28 + ======================
23.29 + INITIALIZATION SECTION
23.30 + ======================
23.31 + -->
23.32 + <target name="-pre-init">
23.33 + <!-- Empty placeholder for easier customization. -->
23.34 + <!-- You can override this target in the ../build.xml file. -->
23.35 + </target>
23.36 + <target depends="-pre-init" name="-init-private">
23.37 + <property file="nbproject/private/config.properties"/>
23.38 + <property file="nbproject/private/configs/${config}.properties"/>
23.39 + <property file="nbproject/private/private.properties"/>
23.40 + </target>
23.41 + <target depends="-pre-init,-init-private" name="-init-user">
23.42 + <property file="${user.properties.file}"/>
23.43 + <!-- The two properties below are usually overridden -->
23.44 + <!-- by the active platform. Just a fallback. -->
23.45 + <property name="default.javac.source" value="1.4"/>
23.46 + <property name="default.javac.target" value="1.4"/>
23.47 + </target>
23.48 + <target depends="-pre-init,-init-private,-init-user" name="-init-project">
23.49 + <property file="nbproject/configs/${config}.properties"/>
23.50 + <property file="nbproject/project.properties"/>
23.51 + </target>
23.52 + <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
23.53 + <available file="${manifest.file}" property="manifest.available"/>
23.54 + <condition property="manifest.available+main.class">
23.55 + <and>
23.56 + <isset property="manifest.available"/>
23.57 + <isset property="main.class"/>
23.58 + <not>
23.59 + <equals arg1="${main.class}" arg2="" trim="true"/>
23.60 + </not>
23.61 + </and>
23.62 + </condition>
23.63 + <condition property="manifest.available+main.class+mkdist.available">
23.64 + <and>
23.65 + <istrue value="${manifest.available+main.class}"/>
23.66 + <isset property="libs.CopyLibs.classpath"/>
23.67 + </and>
23.68 + </condition>
23.69 + <condition property="have.tests">
23.70 + <or>
23.71 + <available file="${test.src.dir}"/>
23.72 + </or>
23.73 + </condition>
23.74 + <condition property="have.sources">
23.75 + <or>
23.76 + <available file="${src.dir}"/>
23.77 + </or>
23.78 + </condition>
23.79 + <condition property="netbeans.home+have.tests">
23.80 + <and>
23.81 + <isset property="netbeans.home"/>
23.82 + <isset property="have.tests"/>
23.83 + </and>
23.84 + </condition>
23.85 + <condition property="no.javadoc.preview">
23.86 + <and>
23.87 + <isset property="javadoc.preview"/>
23.88 + <isfalse value="${javadoc.preview}"/>
23.89 + </and>
23.90 + </condition>
23.91 + <property name="run.jvmargs" value=""/>
23.92 + <property name="javac.compilerargs" value=""/>
23.93 + <property name="work.dir" value="${basedir}"/>
23.94 + <condition property="no.deps">
23.95 + <and>
23.96 + <istrue value="${no.dependencies}"/>
23.97 + </and>
23.98 + </condition>
23.99 + <property name="javac.debug" value="true"/>
23.100 + <property name="javadoc.preview" value="true"/>
23.101 + <property name="application.args" value=""/>
23.102 + <property name="source.encoding" value="${file.encoding}"/>
23.103 + <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
23.104 + <and>
23.105 + <isset property="javadoc.encoding"/>
23.106 + <not>
23.107 + <equals arg1="${javadoc.encoding}" arg2=""/>
23.108 + </not>
23.109 + </and>
23.110 + </condition>
23.111 + <property name="javadoc.encoding.used" value="${source.encoding}"/>
23.112 + <property name="includes" value="**"/>
23.113 + <property name="excludes" value=""/>
23.114 + <property name="do.depend" value="false"/>
23.115 + <condition property="do.depend.true">
23.116 + <istrue value="${do.depend}"/>
23.117 + </condition>
23.118 + <condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
23.119 + <and>
23.120 + <isset property="jaxws.endorsed.dir"/>
23.121 + <available file="nbproject/jaxws-build.xml"/>
23.122 + </and>
23.123 + </condition>
23.124 + </target>
23.125 + <target name="-post-init">
23.126 + <!-- Empty placeholder for easier customization. -->
23.127 + <!-- You can override this target in the ../build.xml file. -->
23.128 + </target>
23.129 + <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
23.130 + <fail unless="src.dir">Must set src.dir</fail>
23.131 + <fail unless="test.src.dir">Must set test.src.dir</fail>
23.132 + <fail unless="build.dir">Must set build.dir</fail>
23.133 + <fail unless="dist.dir">Must set dist.dir</fail>
23.134 + <fail unless="build.classes.dir">Must set build.classes.dir</fail>
23.135 + <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
23.136 + <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
23.137 + <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
23.138 + <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
23.139 + <fail unless="dist.jar">Must set dist.jar</fail>
23.140 + </target>
23.141 + <target name="-init-macrodef-property">
23.142 + <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
23.143 + <attribute name="name"/>
23.144 + <attribute name="value"/>
23.145 + <sequential>
23.146 + <property name="@{name}" value="${@{value}}"/>
23.147 + </sequential>
23.148 + </macrodef>
23.149 + </target>
23.150 + <target name="-init-macrodef-javac">
23.151 + <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
23.152 + <attribute default="${src.dir}" name="srcdir"/>
23.153 + <attribute default="${build.classes.dir}" name="destdir"/>
23.154 + <attribute default="${javac.classpath}" name="classpath"/>
23.155 + <attribute default="${includes}" name="includes"/>
23.156 + <attribute default="${excludes}" name="excludes"/>
23.157 + <attribute default="${javac.debug}" name="debug"/>
23.158 + <attribute default="" name="sourcepath"/>
23.159 + <element name="customize" optional="true"/>
23.160 + <sequential>
23.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}">
23.162 + <classpath>
23.163 + <path path="@{classpath}"/>
23.164 + </classpath>
23.165 + <compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
23.166 + <customize/>
23.167 + </javac>
23.168 + </sequential>
23.169 + </macrodef>
23.170 + <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
23.171 + <attribute default="${src.dir}" name="srcdir"/>
23.172 + <attribute default="${build.classes.dir}" name="destdir"/>
23.173 + <attribute default="${javac.classpath}" name="classpath"/>
23.174 + <sequential>
23.175 + <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
23.176 + <classpath>
23.177 + <path path="@{classpath}"/>
23.178 + </classpath>
23.179 + </depend>
23.180 + </sequential>
23.181 + </macrodef>
23.182 + <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
23.183 + <attribute default="${build.classes.dir}" name="destdir"/>
23.184 + <sequential>
23.185 + <fail unless="javac.includes">Must set javac.includes</fail>
23.186 + <pathconvert pathsep="," property="javac.includes.binary">
23.187 + <path>
23.188 + <filelist dir="@{destdir}" files="${javac.includes}"/>
23.189 + </path>
23.190 + <globmapper from="*.java" to="*.class"/>
23.191 + </pathconvert>
23.192 + <delete>
23.193 + <files includes="${javac.includes.binary}"/>
23.194 + </delete>
23.195 + </sequential>
23.196 + </macrodef>
23.197 + </target>
23.198 + <target name="-init-macrodef-junit">
23.199 + <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
23.200 + <attribute default="${includes}" name="includes"/>
23.201 + <attribute default="${excludes}" name="excludes"/>
23.202 + <attribute default="**" name="testincludes"/>
23.203 + <sequential>
23.204 + <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
23.205 + <batchtest todir="${build.test.results.dir}">
23.206 + <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
23.207 + <filename name="@{testincludes}"/>
23.208 + </fileset>
23.209 + </batchtest>
23.210 + <classpath>
23.211 + <path path="${run.test.classpath}"/>
23.212 + </classpath>
23.213 + <syspropertyset>
23.214 + <propertyref prefix="test-sys-prop."/>
23.215 + <mapper from="test-sys-prop.*" to="*" type="glob"/>
23.216 + </syspropertyset>
23.217 + <formatter type="brief" usefile="false"/>
23.218 + <formatter type="xml"/>
23.219 + <jvmarg line="${run.jvmargs}"/>
23.220 + </junit>
23.221 + </sequential>
23.222 + </macrodef>
23.223 + </target>
23.224 + <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
23.225 + <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
23.226 + <attribute default="${main.class}" name="name"/>
23.227 + <attribute default="${debug.classpath}" name="classpath"/>
23.228 + <attribute default="" name="stopclassname"/>
23.229 + <sequential>
23.230 + <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
23.231 + <classpath>
23.232 + <path path="@{classpath}"/>
23.233 + </classpath>
23.234 + </nbjpdastart>
23.235 + </sequential>
23.236 + </macrodef>
23.237 + <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
23.238 + <attribute default="${build.classes.dir}" name="dir"/>
23.239 + <sequential>
23.240 + <nbjpdareload>
23.241 + <fileset dir="@{dir}" includes="${fix.classes}">
23.242 + <include name="${fix.includes}*.class"/>
23.243 + </fileset>
23.244 + </nbjpdareload>
23.245 + </sequential>
23.246 + </macrodef>
23.247 + </target>
23.248 + <target name="-init-debug-args">
23.249 + <property name="version-output" value="java version "${ant.java.version}"/>
23.250 + <condition property="have-jdk-older-than-1.4">
23.251 + <or>
23.252 + <contains string="${version-output}" substring="java version "1.0"/>
23.253 + <contains string="${version-output}" substring="java version "1.1"/>
23.254 + <contains string="${version-output}" substring="java version "1.2"/>
23.255 + <contains string="${version-output}" substring="java version "1.3"/>
23.256 + </or>
23.257 + </condition>
23.258 + <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
23.259 + <istrue value="${have-jdk-older-than-1.4}"/>
23.260 + </condition>
23.261 + <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
23.262 + <os family="windows"/>
23.263 + </condition>
23.264 + <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
23.265 + <isset property="debug.transport"/>
23.266 + </condition>
23.267 + </target>
23.268 + <target depends="-init-debug-args" name="-init-macrodef-debug">
23.269 + <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
23.270 + <attribute default="${main.class}" name="classname"/>
23.271 + <attribute default="${debug.classpath}" name="classpath"/>
23.272 + <element name="customize" optional="true"/>
23.273 + <sequential>
23.274 + <java classname="@{classname}" dir="${work.dir}" fork="true">
23.275 + <jvmarg line="${debug-args-line}"/>
23.276 + <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
23.277 + <jvmarg line="${run.jvmargs}"/>
23.278 + <classpath>
23.279 + <path path="@{classpath}"/>
23.280 + </classpath>
23.281 + <syspropertyset>
23.282 + <propertyref prefix="run-sys-prop."/>
23.283 + <mapper from="run-sys-prop.*" to="*" type="glob"/>
23.284 + </syspropertyset>
23.285 + <customize/>
23.286 + </java>
23.287 + </sequential>
23.288 + </macrodef>
23.289 + </target>
23.290 + <target name="-init-macrodef-java">
23.291 + <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
23.292 + <attribute default="${main.class}" name="classname"/>
23.293 + <element name="customize" optional="true"/>
23.294 + <sequential>
23.295 + <java classname="@{classname}" dir="${work.dir}" fork="true">
23.296 + <jvmarg line="${run.jvmargs}"/>
23.297 + <classpath>
23.298 + <path path="${run.classpath}"/>
23.299 + </classpath>
23.300 + <syspropertyset>
23.301 + <propertyref prefix="run-sys-prop."/>
23.302 + <mapper from="run-sys-prop.*" to="*" type="glob"/>
23.303 + </syspropertyset>
23.304 + <customize/>
23.305 + </java>
23.306 + </sequential>
23.307 + </macrodef>
23.308 + </target>
23.309 + <target name="-init-presetdef-jar">
23.310 + <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
23.311 + <jar compress="${jar.compress}" jarfile="${dist.jar}">
23.312 + <j2seproject1:fileset dir="${build.classes.dir}"/>
23.313 + </jar>
23.314 + </presetdef>
23.315 + </target>
23.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"/>
23.317 + <!--
23.318 + ===================
23.319 + COMPILATION SECTION
23.320 + ===================
23.321 + -->
23.322 + <target depends="init" name="deps-jar" unless="no.deps"/>
23.323 + <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
23.324 + <target depends="init" name="-check-automatic-build">
23.325 + <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
23.326 + </target>
23.327 + <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
23.328 + <antcall target="clean"/>
23.329 + </target>
23.330 + <target depends="init,deps-jar" name="-pre-pre-compile">
23.331 + <mkdir dir="${build.classes.dir}"/>
23.332 + </target>
23.333 + <target name="-pre-compile">
23.334 + <!-- Empty placeholder for easier customization. -->
23.335 + <!-- You can override this target in the ../build.xml file. -->
23.336 + </target>
23.337 + <target if="do.depend.true" name="-compile-depend">
23.338 + <j2seproject3:depend/>
23.339 + </target>
23.340 + <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
23.341 + <j2seproject3:javac/>
23.342 + <copy todir="${build.classes.dir}">
23.343 + <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
23.344 + </copy>
23.345 + </target>
23.346 + <target name="-post-compile">
23.347 + <!-- Empty placeholder for easier customization. -->
23.348 + <!-- You can override this target in the ../build.xml file. -->
23.349 + </target>
23.350 + <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
23.351 + <target name="-pre-compile-single">
23.352 + <!-- Empty placeholder for easier customization. -->
23.353 + <!-- You can override this target in the ../build.xml file. -->
23.354 + </target>
23.355 + <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
23.356 + <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
23.357 + <j2seproject3:force-recompile/>
23.358 + <j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
23.359 + </target>
23.360 + <target name="-post-compile-single">
23.361 + <!-- Empty placeholder for easier customization. -->
23.362 + <!-- You can override this target in the ../build.xml file. -->
23.363 + </target>
23.364 + <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
23.365 + <!--
23.366 + ====================
23.367 + JAR BUILDING SECTION
23.368 + ====================
23.369 + -->
23.370 + <target depends="init" name="-pre-pre-jar">
23.371 + <dirname file="${dist.jar}" property="dist.jar.dir"/>
23.372 + <mkdir dir="${dist.jar.dir}"/>
23.373 + </target>
23.374 + <target name="-pre-jar">
23.375 + <!-- Empty placeholder for easier customization. -->
23.376 + <!-- You can override this target in the ../build.xml file. -->
23.377 + </target>
23.378 + <target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
23.379 + <j2seproject1:jar/>
23.380 + </target>
23.381 + <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
23.382 + <j2seproject1:jar manifest="${manifest.file}"/>
23.383 + </target>
23.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">
23.385 + <j2seproject1:jar manifest="${manifest.file}">
23.386 + <j2seproject1:manifest>
23.387 + <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
23.388 + </j2seproject1:manifest>
23.389 + </j2seproject1:jar>
23.390 + <echo>To run this application from the command line without Ant, try:</echo>
23.391 + <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
23.392 + <property location="${dist.jar}" name="dist.jar.resolved"/>
23.393 + <pathconvert property="run.classpath.with.dist.jar">
23.394 + <path path="${run.classpath}"/>
23.395 + <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
23.396 + </pathconvert>
23.397 + <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
23.398 + </target>
23.399 + <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
23.400 + <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
23.401 + <pathconvert property="run.classpath.without.build.classes.dir">
23.402 + <path path="${run.classpath}"/>
23.403 + <map from="${build.classes.dir.resolved}" to=""/>
23.404 + </pathconvert>
23.405 + <pathconvert pathsep=" " property="jar.classpath">
23.406 + <path path="${run.classpath.without.build.classes.dir}"/>
23.407 + <chainedmapper>
23.408 + <flattenmapper/>
23.409 + <globmapper from="*" to="lib/*"/>
23.410 + </chainedmapper>
23.411 + </pathconvert>
23.412 + <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
23.413 + <copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
23.414 + <fileset dir="${build.classes.dir}"/>
23.415 + <manifest>
23.416 + <attribute name="Main-Class" value="${main.class}"/>
23.417 + <attribute name="Class-Path" value="${jar.classpath}"/>
23.418 + </manifest>
23.419 + </copylibs>
23.420 + <echo>To run this application from the command line without Ant, try:</echo>
23.421 + <property location="${dist.jar}" name="dist.jar.resolved"/>
23.422 + <echo>java -jar "${dist.jar.resolved}"</echo>
23.423 + </target>
23.424 + <target name="-post-jar">
23.425 + <!-- Empty placeholder for easier customization. -->
23.426 + <!-- You can override this target in the ../build.xml file. -->
23.427 + </target>
23.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"/>
23.429 + <!--
23.430 + =================
23.431 + EXECUTION SECTION
23.432 + =================
23.433 + -->
23.434 + <target depends="init,compile" description="Run a main class." name="run">
23.435 + <j2seproject1:java>
23.436 + <customize>
23.437 + <arg line="${application.args}"/>
23.438 + </customize>
23.439 + </j2seproject1:java>
23.440 + </target>
23.441 + <target name="-do-not-recompile">
23.442 + <property name="javac.includes.binary" value=""/>
23.443 + </target>
23.444 + <target depends="init,-do-not-recompile,compile-single" name="run-single">
23.445 + <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
23.446 + <j2seproject1:java classname="${run.class}"/>
23.447 + </target>
23.448 + <!--
23.449 + =================
23.450 + DEBUGGING SECTION
23.451 + =================
23.452 + -->
23.453 + <target depends="init" if="netbeans.home" name="-debug-start-debugger">
23.454 + <j2seproject1:nbjpdastart name="${debug.class}"/>
23.455 + </target>
23.456 + <target depends="init,compile" name="-debug-start-debuggee">
23.457 + <j2seproject3:debug>
23.458 + <customize>
23.459 + <arg line="${application.args}"/>
23.460 + </customize>
23.461 + </j2seproject3:debug>
23.462 + </target>
23.463 + <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
23.464 + <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
23.465 + <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
23.466 + </target>
23.467 + <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
23.468 + <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
23.469 + <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
23.470 + <j2seproject3:debug classname="${debug.class}"/>
23.471 + </target>
23.472 + <target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
23.473 + <target depends="init" name="-pre-debug-fix">
23.474 + <fail unless="fix.includes">Must set fix.includes</fail>
23.475 + <property name="javac.includes" value="${fix.includes}.java"/>
23.476 + </target>
23.477 + <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
23.478 + <j2seproject1:nbjpdareload/>
23.479 + </target>
23.480 + <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
23.481 + <!--
23.482 + ===============
23.483 + JAVADOC SECTION
23.484 + ===============
23.485 + -->
23.486 + <target depends="init" name="-javadoc-build">
23.487 + <mkdir dir="${dist.javadoc.dir}"/>
23.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}">
23.489 + <classpath>
23.490 + <path path="${javac.classpath}"/>
23.491 + </classpath>
23.492 + <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
23.493 + <filename name="**/*.java"/>
23.494 + </fileset>
23.495 + </javadoc>
23.496 + </target>
23.497 + <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
23.498 + <nbbrowse file="${dist.javadoc.dir}/index.html"/>
23.499 + </target>
23.500 + <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
23.501 + <!--
23.502 + =========================
23.503 + JUNIT COMPILATION SECTION
23.504 + =========================
23.505 + -->
23.506 + <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
23.507 + <mkdir dir="${build.test.classes.dir}"/>
23.508 + </target>
23.509 + <target name="-pre-compile-test">
23.510 + <!-- Empty placeholder for easier customization. -->
23.511 + <!-- You can override this target in the ../build.xml file. -->
23.512 + </target>
23.513 + <target if="do.depend.true" name="-compile-test-depend">
23.514 + <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
23.515 + </target>
23.516 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
23.517 + <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
23.518 + <copy todir="${build.test.classes.dir}">
23.519 + <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
23.520 + </copy>
23.521 + </target>
23.522 + <target name="-post-compile-test">
23.523 + <!-- Empty placeholder for easier customization. -->
23.524 + <!-- You can override this target in the ../build.xml file. -->
23.525 + </target>
23.526 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
23.527 + <target name="-pre-compile-test-single">
23.528 + <!-- Empty placeholder for easier customization. -->
23.529 + <!-- You can override this target in the ../build.xml file. -->
23.530 + </target>
23.531 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
23.532 + <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
23.533 + <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
23.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}"/>
23.535 + <copy todir="${build.test.classes.dir}">
23.536 + <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
23.537 + </copy>
23.538 + </target>
23.539 + <target name="-post-compile-test-single">
23.540 + <!-- Empty placeholder for easier customization. -->
23.541 + <!-- You can override this target in the ../build.xml file. -->
23.542 + </target>
23.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"/>
23.544 + <!--
23.545 + =======================
23.546 + JUNIT EXECUTION SECTION
23.547 + =======================
23.548 + -->
23.549 + <target depends="init" if="have.tests" name="-pre-test-run">
23.550 + <mkdir dir="${build.test.results.dir}"/>
23.551 + </target>
23.552 + <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
23.553 + <j2seproject3:junit testincludes="**/*Test.java"/>
23.554 + </target>
23.555 + <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
23.556 + <fail if="tests.failed">Some tests failed; see details above.</fail>
23.557 + </target>
23.558 + <target depends="init" if="have.tests" name="test-report"/>
23.559 + <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
23.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"/>
23.561 + <target depends="init" if="have.tests" name="-pre-test-run-single">
23.562 + <mkdir dir="${build.test.results.dir}"/>
23.563 + </target>
23.564 + <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
23.565 + <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
23.566 + <j2seproject3:junit excludes="" includes="${test.includes}"/>
23.567 + </target>
23.568 + <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
23.569 + <fail if="tests.failed">Some tests failed; see details above.</fail>
23.570 + </target>
23.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"/>
23.572 + <!--
23.573 + =======================
23.574 + JUNIT DEBUGGING SECTION
23.575 + =======================
23.576 + -->
23.577 + <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
23.578 + <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
23.579 + <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
23.580 + <delete file="${test.report.file}"/>
23.581 + <mkdir dir="${build.test.results.dir}"/>
23.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}">
23.583 + <customize>
23.584 + <syspropertyset>
23.585 + <propertyref prefix="test-sys-prop."/>
23.586 + <mapper from="test-sys-prop.*" to="*" type="glob"/>
23.587 + </syspropertyset>
23.588 + <arg value="${test.class}"/>
23.589 + <arg value="showoutput=true"/>
23.590 + <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
23.591 + <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
23.592 + </customize>
23.593 + </j2seproject3:debug>
23.594 + </target>
23.595 + <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
23.596 + <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
23.597 + </target>
23.598 + <target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
23.599 + <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
23.600 + <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
23.601 + </target>
23.602 + <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
23.603 + <!--
23.604 + =========================
23.605 + APPLET EXECUTION SECTION
23.606 + =========================
23.607 + -->
23.608 + <target depends="init,compile-single" name="run-applet">
23.609 + <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
23.610 + <j2seproject1:java classname="sun.applet.AppletViewer">
23.611 + <customize>
23.612 + <arg value="${applet.url}"/>
23.613 + </customize>
23.614 + </j2seproject1:java>
23.615 + </target>
23.616 + <!--
23.617 + =========================
23.618 + APPLET DEBUGGING SECTION
23.619 + =========================
23.620 + -->
23.621 + <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
23.622 + <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
23.623 + <j2seproject3:debug classname="sun.applet.AppletViewer">
23.624 + <customize>
23.625 + <arg value="${applet.url}"/>
23.626 + </customize>
23.627 + </j2seproject3:debug>
23.628 + </target>
23.629 + <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
23.630 + <!--
23.631 + ===============
23.632 + CLEANUP SECTION
23.633 + ===============
23.634 + -->
23.635 + <target depends="init" name="deps-clean" unless="no.deps"/>
23.636 + <target depends="init" name="-do-clean">
23.637 + <delete dir="${build.dir}"/>
23.638 + <delete dir="${dist.dir}"/>
23.639 + </target>
23.640 + <target name="-post-clean">
23.641 + <!-- Empty placeholder for easier customization. -->
23.642 + <!-- You can override this target in the ../build.xml file. -->
23.643 + </target>
23.644 + <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
23.645 +</project>
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
24.2 +++ b/task4/solution04/nbproject/genfiles.properties Sat Oct 11 23:38:46 2008 +0200
24.3 @@ -0,0 +1,8 @@
24.4 +build.xml.data.CRC32=2ab820eb
24.5 +build.xml.script.CRC32=58a52595
24.6 +build.xml.stylesheet.CRC32=be360661
24.7 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
24.8 +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
24.9 +nbproject/build-impl.xml.data.CRC32=2fbfa6ce
24.10 +nbproject/build-impl.xml.script.CRC32=c521eea7
24.11 +nbproject/build-impl.xml.stylesheet.CRC32=e55b27f5
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
25.2 +++ b/task4/solution04/nbproject/project.properties Sat Oct 11 23:38:46 2008 +0200
25.3 @@ -0,0 +1,68 @@
25.4 +application.title=currency
25.5 +application.vendor=apidesign.org
25.6 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
25.7 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
25.8 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=default
25.9 +build.classes.dir=${build.dir}/classes
25.10 +build.classes.excludes=**/*.java,**/*.form
25.11 +# This directory is removed when the project is cleaned:
25.12 +build.dir=build
25.13 +build.generated.dir=${build.dir}/generated
25.14 +# Only compile against the classpath explicitly listed here:
25.15 +build.sysclasspath=ignore
25.16 +build.test.classes.dir=${build.dir}/test/classes
25.17 +build.test.results.dir=${build.dir}/test/results
25.18 +debug.classpath=\
25.19 + ${run.classpath}
25.20 +debug.test.classpath=\
25.21 + ${run.test.classpath}
25.22 +# This directory is removed when the project is cleaned:
25.23 +dist.dir=dist
25.24 +dist.jar=${dist.dir}/currency.jar
25.25 +dist.javadoc.dir=${dist.dir}/javadoc
25.26 +excludes=
25.27 +file.reference.junit-4.4.jar=../../libs/junit-4.4.jar
25.28 +file.reference.src-apifest08=..
25.29 +includes=**
25.30 +jar.compress=false
25.31 +javac.classpath=
25.32 +# Space-separated list of extra javac options
25.33 +javac.compilerargs=
25.34 +javac.deprecation=false
25.35 +javac.source=1.5
25.36 +javac.target=1.5
25.37 +javac.test.classpath=\
25.38 + ${javac.classpath}:\
25.39 + ${build.classes.dir}:\
25.40 + ${file.reference.junit-4.4.jar}
25.41 +javadoc.additionalparam=
25.42 +javadoc.author=false
25.43 +javadoc.encoding=
25.44 +javadoc.noindex=false
25.45 +javadoc.nonavbar=false
25.46 +javadoc.notree=false
25.47 +javadoc.private=false
25.48 +javadoc.splitindex=true
25.49 +javadoc.use=true
25.50 +javadoc.version=false
25.51 +javadoc.windowtitle=
25.52 +jnlp.codebase.type=local
25.53 +jnlp.codebase.url=file:/home/jarda/src/apifest08/currency/dist
25.54 +jnlp.descriptor=application
25.55 +jnlp.enabled=false
25.56 +jnlp.offline-allowed=false
25.57 +jnlp.signed=false
25.58 +meta.inf.dir=${src.dir}/META-INF
25.59 +platform.active=default_platform
25.60 +run.classpath=\
25.61 + ${javac.classpath}:\
25.62 + ${build.classes.dir}
25.63 +# Space-separated list of JVM arguments used when running the project
25.64 +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
25.65 +# or test-sys-prop.name=value to set system properties for unit tests):
25.66 +run.jvmargs=
25.67 +run.test.classpath=\
25.68 + ${javac.test.classpath}:\
25.69 + ${build.test.classes.dir}
25.70 +src.dir=src
25.71 +test.src.dir=test
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
26.2 +++ b/task4/solution04/nbproject/project.xml Sat Oct 11 23:38:46 2008 +0200
26.3 @@ -0,0 +1,16 @@
26.4 +<?xml version="1.0" encoding="UTF-8"?>
26.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
26.6 + <type>org.netbeans.modules.java.j2seproject</type>
26.7 + <configuration>
26.8 + <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
26.9 + <name>Currency Convertor Solution 04</name>
26.10 + <minimum-ant-version>1.6.5</minimum-ant-version>
26.11 + <source-roots>
26.12 + <root id="src.dir"/>
26.13 + </source-roots>
26.14 + <test-roots>
26.15 + <root id="test.src.dir"/>
26.16 + </test-roots>
26.17 + </data>
26.18 + </configuration>
26.19 +</project>
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
27.2 +++ b/task4/solution04/src/org/apidesign/apifest08/currency/CompositeConvertorImpl.java Sat Oct 11 23:38:46 2008 +0200
27.3 @@ -0,0 +1,350 @@
27.4 +package org.apidesign.apifest08.currency;
27.5 +
27.6 +
27.7 +import java.math.BigDecimal;
27.8 +import java.math.RoundingMode;
27.9 +import java.util.Collections;
27.10 +import java.util.Currency;
27.11 +import java.util.HashMap;
27.12 +import java.util.HashSet;
27.13 +import java.util.Map;
27.14 +import java.util.Set;
27.15 +
27.16 +
27.17 +/**
27.18 + * A composite convertor allows conversions between many currencies by forwarding conversion requests to stored convertors.
27.19 + * A composite convertor will build all possible conversions that are allowed by the underlying set of convertors.
27.20 + *
27.21 + * @author D'Arcy Smith
27.22 + * @verson 1.1
27.23 + */
27.24 +final class CompositeConvertorImpl
27.25 + implements Convertor
27.26 +{
27.27 + /**
27.28 + * The convertors that are supported.
27.29 + */
27.30 + private final Convertor[] convertors;
27.31 +
27.32 + /**
27.33 + * Keeps track of what convertors to use to convert between currencies.
27.34 + */
27.35 + private final Map<Currency, Map<Currency, Convertor>> possibleConversions;
27.36 +
27.37 + {
27.38 + possibleConversions = new HashMap<Currency, Map<Currency, Convertor>>();
27.39 + }
27.40 +
27.41 + /**
27.42 + * Construct a ComositeConvertorImpl with the specified convertors.
27.43 + * This will result in all possible conversions between the supplied currencies being made.
27.44 + *
27.45 + * @param cs the convertors to use.
27.46 + * @throws IllegalArgumentException if any of the items in cs are null.
27.47 + */
27.48 + CompositeConvertorImpl(Convertor ... cs)
27.49 + {
27.50 + int newConvertors;
27.51 +
27.52 + convertors = cs;
27.53 +
27.54 + // track all of the known conversion
27.55 + for(final Convertor convertor : convertors)
27.56 + {
27.57 + final Set<Currency> currencies;
27.58 + Map<Currency, Convertor> possible;
27.59 +
27.60 + if(convertor == null)
27.61 + {
27.62 + throw new IllegalArgumentException("cs cannot contain null");
27.63 + }
27.64 +
27.65 + currencies = convertor.getCurrencies();
27.66 +
27.67 + for(final Currency currency : currencies)
27.68 + {
27.69 + possible = possibleConversions.get(currency);
27.70 +
27.71 + if(possible == null)
27.72 + {
27.73 + possible = new HashMap<Currency, Convertor>();
27.74 + possibleConversions.put(currency, possible);
27.75 + }
27.76 +
27.77 + for(final Currency c : currencies)
27.78 + {
27.79 + possible.put(c, convertor);
27.80 + }
27.81 + }
27.82 + }
27.83 +
27.84 + // make up conversions that can be derived... eg:
27.85 + // we have:
27.86 + // USD <-> CAD
27.87 + // CAD <-> CZK
27.88 + // SSK <-> GBP
27.89 + // we can derive:
27.90 + // USD <-> CZK
27.91 + // we cannot derive:
27.92 + // USD <-> GBP
27.93 + // CAD <-> GBP
27.94 + // CZK <-> GBP
27.95 + do
27.96 + {
27.97 + newConvertors = 0;
27.98 +
27.99 + // todo... need to loop this until all the ones that can be handled are done.
27.100 + for(final Currency from : getCurrencies())
27.101 + {
27.102 + for(final Currency to : getCurrencies())
27.103 + {
27.104 + if(!(canConvert(from, to)))
27.105 + {
27.106 + final Set<Currency> fromCurrencies;
27.107 + final Set<Currency> toCurrencies;
27.108 + final Set<Currency> common;
27.109 +
27.110 + fromCurrencies = possibleConversions.get(from).keySet();
27.111 + toCurrencies = possibleConversions.get(to).keySet();
27.112 + common = new HashSet<Currency>();
27.113 +
27.114 + for(final Currency currency : fromCurrencies)
27.115 + {
27.116 + if(toCurrencies.contains(currency))
27.117 + {
27.118 + common.add(currency);
27.119 + }
27.120 + }
27.121 +
27.122 + for(final Currency currency : common)
27.123 + {
27.124 + final Convertor convertor;
27.125 +
27.126 + convertor = createConvertor(from, to, currency);
27.127 + possibleConversions.get(from).put(to, convertor);
27.128 + possibleConversions.get(to).put(from, convertor);
27.129 + newConvertors++;
27.130 + }
27.131 + }
27.132 + }
27.133 + }
27.134 + }
27.135 + while(newConvertors > 0);
27.136 + }
27.137 +
27.138 + /**
27.139 + * Check to see if converting between the two currencies is possible.
27.140 + *
27.141 + * @param from the currency to convert from.
27.142 + * @param to the currency to convert to.
27.143 + * @return true if the conversion is possible.
27.144 + * @throws IllegalArgumentException if either from or to are null.
27.145 + */
27.146 + public boolean canConvert(final Currency from, final Currency to)
27.147 + {
27.148 + final Map<Currency, Convertor> possible;
27.149 +
27.150 + if(from == null)
27.151 + {
27.152 + throw new IllegalArgumentException("from cannot be null");
27.153 + }
27.154 +
27.155 + if(to == null)
27.156 + {
27.157 + throw new IllegalArgumentException("to cannot be null");
27.158 + }
27.159 +
27.160 + possible = possibleConversions.get(from);
27.161 +
27.162 + if(possible.containsKey(to))
27.163 + {
27.164 + return (true);
27.165 + }
27.166 +
27.167 + return (false);
27.168 + }
27.169 +
27.170 + /**
27.171 + * Get the currencies that the convertor supports. Just because a currency is
27.172 + * supported does not mean that canConvert will return true.
27.173 + *
27.174 + * @return the supported currencies.
27.175 + */
27.176 + public Set<Currency> getCurrencies()
27.177 + {
27.178 + final Set<Currency> currencies;
27.179 +
27.180 + currencies = possibleConversions.keySet();
27.181 +
27.182 + return (Collections.unmodifiableSet(currencies));
27.183 + }
27.184 +
27.185 + /**
27.186 + * Get the conversion rate between two currencies.
27.187 + *
27.188 + * @param from the currency to convert from.
27.189 + * @param to the currency to convert to.
27.190 + * @return the conversion rate between the two currencies.
27.191 + * @throws IllegalArgumentException if either from or to is null.
27.192 + * @throws InvalidConversionException if canConvert would return false.
27.193 + */
27.194 + public BigDecimal getConversionRate(final Currency from, final Currency to)
27.195 + throws InvalidConversionException
27.196 + {
27.197 + final Map<Currency, Convertor> possible;
27.198 + Convertor convertor;
27.199 +
27.200 + if(from == null)
27.201 + {
27.202 + throw new IllegalArgumentException("from cannot be null");
27.203 + }
27.204 +
27.205 + if(to == null)
27.206 + {
27.207 + throw new IllegalArgumentException("to cannot be null");
27.208 + }
27.209 +
27.210 + if(!(canConvert(from, to)))
27.211 + {
27.212 + throw new InvalidConversionException("cannot convert", to);
27.213 + }
27.214 +
27.215 + possible = possibleConversions.get(from);
27.216 + convertor = possible.get(to);
27.217 +
27.218 + if(convertor == null)
27.219 + {
27.220 + throw new Error();
27.221 + }
27.222 +
27.223 + return (convertor.getConversionRate(from, to));
27.224 + }
27.225 +
27.226 + private Convertor getConvertor(final Currency from, final Currency to)
27.227 + throws InvalidConversionException
27.228 + {
27.229 + final Map<Currency, Convertor> possible;
27.230 + Convertor convertor;
27.231 +
27.232 + if(from == null)
27.233 + {
27.234 + throw new IllegalArgumentException("from cannot be null");
27.235 + }
27.236 +
27.237 + if(to == null)
27.238 + {
27.239 + throw new IllegalArgumentException("to cannot be null");
27.240 + }
27.241 +
27.242 + if(!(canConvert(from, to)))
27.243 + {
27.244 + throw new InvalidConversionException("cannot convert", to);
27.245 + }
27.246 +
27.247 + possible = possibleConversions.get(from);
27.248 + convertor = possible.get(to);
27.249 +
27.250 + if(convertor == null)
27.251 + {
27.252 + throw new Error();
27.253 + }
27.254 +
27.255 + return (convertor);
27.256 + }
27.257 +
27.258 + /**
27.259 + * Convert an amount from one currency to another.
27.260 + *
27.261 + * @param from the currency to convert from.
27.262 + * @param to the currency to convert to.
27.263 + * @param amount the amount to convert.
27.264 + * @return the converted amount.
27.265 + * @throws IllegalArgumentException if any of the arguments are null.
27.266 + * @throws InvalidConversionException if either from or to are not valid for the convertor.
27.267 + */
27.268 + public BigDecimal convert(final Currency from,
27.269 + final Currency to,
27.270 + final BigDecimal amount)
27.271 + throws InvalidConversionException
27.272 + {
27.273 + final BigDecimal result;
27.274 + final Convertor convertor;
27.275 +
27.276 + if(amount == null)
27.277 + {
27.278 + throw new IllegalArgumentException("amount cannot be null");
27.279 + }
27.280 +
27.281 + if(from == null)
27.282 + {
27.283 + throw new IllegalArgumentException("from cannot be null");
27.284 + }
27.285 +
27.286 + if(to == null)
27.287 + {
27.288 + throw new IllegalArgumentException("to cannot be null");
27.289 + }
27.290 +
27.291 + // fixed a bug from Task2 that showed up in Task3... before we did the conversion here,
27.292 + // but that meant that the underlying covnerter convert method never got called... which
27.293 + // meant that in Task3 the exchange rate never changed.
27.294 + convertor = getConvertor(from, to);
27.295 + result = convertor.convert(from, to, amount);
27.296 +
27.297 + return (result.setScale(2, RoundingMode.HALF_DOWN));
27.298 + }
27.299 +
27.300 + /**
27.301 + * Create a convertor between two currencies using another currency that is able to convert between both.
27.302 + *
27.303 + * @param from the currency to convert from.
27.304 + * @param to the currency to convert to.
27.305 + * @param intermediary the currency to use as a go-between.
27.306 + * @return a Convertor that is able to convert between from an to.
27.307 + * @throws IllegalArgumentException if any of the arguments are null.
27.308 + */
27.309 + private Convertor createConvertor(final Currency from,
27.310 + final Currency to,
27.311 + final Currency intermediary)
27.312 + {
27.313 + final Convertor fromIntermediary;
27.314 + final Convertor toIntermediary;
27.315 +
27.316 + if(from == null)
27.317 + {
27.318 + throw new IllegalArgumentException("from cannot be null");
27.319 + }
27.320 +
27.321 + if(to == null)
27.322 + {
27.323 + throw new IllegalArgumentException("to cannot be null");
27.324 + }
27.325 +
27.326 + if(intermediary == null)
27.327 + {
27.328 + throw new IllegalArgumentException("intermediary cannot be null");
27.329 + }
27.330 +
27.331 + fromIntermediary = possibleConversions.get(from).get(intermediary);
27.332 + toIntermediary = possibleConversions.get(to).get(intermediary);
27.333 +
27.334 + try
27.335 + {
27.336 + final BigDecimal fromRate;
27.337 + final BigDecimal toRate;
27.338 + final BigDecimal rate;
27.339 + final Convertor convertor;
27.340 +
27.341 + fromRate = fromIntermediary.getConversionRate(from, intermediary);
27.342 + toRate = toIntermediary.getConversionRate(intermediary, to);
27.343 + rate = fromRate.multiply(toRate);
27.344 + convertor = ConvertorFactory.getConvertor(from, BigDecimal.ONE, to, rate);
27.345 +
27.346 + return (convertor);
27.347 + }
27.348 + catch (InvalidConversionException ex)
27.349 + {
27.350 + throw new Error();
27.351 + }
27.352 + }
27.353 +}
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
28.2 +++ b/task4/solution04/src/org/apidesign/apifest08/currency/ConverterImpl.java Sat Oct 11 23:38:46 2008 +0200
28.3 @@ -0,0 +1,304 @@
28.4 +package org.apidesign.apifest08.currency;
28.5 +
28.6 +
28.7 +import java.math.BigDecimal;
28.8 +import java.math.MathContext;
28.9 +import java.math.RoundingMode;
28.10 +import java.util.Collections;
28.11 +import java.util.Currency;
28.12 +import java.util.HashSet;
28.13 +import java.util.Set;
28.14 +
28.15 +
28.16 +/**
28.17 + * Convert between two currencies.
28.18 + *
28.19 + * @author D'Arcy Smith
28.20 + * @version 1.0
28.21 + */
28.22 +final class ConvertorImpl
28.23 + implements Convertor
28.24 +{
28.25 + /**
28.26 + * The currency to convert from.
28.27 + */
28.28 + private final Currency currencyA;
28.29 +
28.30 + /**
28.31 + * The currency to convert to.
28.32 + */
28.33 + private final Currency currencyB;
28.34 +
28.35 + /**
28.36 + * The echange rate between a and b.
28.37 + */
28.38 + private final BigDecimal currencyARate;
28.39 +
28.40 + /**
28.41 + * The echange rate between b and a.
28.42 + */
28.43 + private final BigDecimal currencyBRate;
28.44 +
28.45 + /**
28.46 + * Constructs a convertor with the specified currencies.
28.47 + *
28.48 + * @param a the currency to convert from.
28.49 + * @param aRate the exchage rage between from and to.
28.50 + * @param b the currency to convert to.
28.51 + * @param bRate the exchage rage between to and from.
28.52 + * @throws IllegalArgumentException if either any of the arguments are null or if either rate <= 0.
28.53 + */
28.54 + public ConvertorImpl(final Currency a,
28.55 + final BigDecimal aRate,
28.56 + final Currency b,
28.57 + final BigDecimal bRate)
28.58 + {
28.59 + if(a == null)
28.60 + {
28.61 + throw new IllegalArgumentException("a cannot be null");
28.62 + }
28.63 +
28.64 + if(b == null)
28.65 + {
28.66 + throw new IllegalArgumentException("b cannot be null");
28.67 + }
28.68 +
28.69 + if(aRate == null)
28.70 + {
28.71 + throw new IllegalArgumentException("aRate cannot be null");
28.72 + }
28.73 +
28.74 + if(bRate == null)
28.75 + {
28.76 + throw new IllegalArgumentException("bRate cannot be null");
28.77 + }
28.78 +
28.79 + if(aRate.compareTo(BigDecimal.ZERO) <= 0)
28.80 + {
28.81 + throw new IllegalArgumentException("aRate must be > 0, was: " + aRate);
28.82 + }
28.83 +
28.84 + if(bRate.compareTo(BigDecimal.ZERO) <= 0)
28.85 + {
28.86 + throw new IllegalArgumentException("bRate must be > 0, was: " + bRate);
28.87 + }
28.88 +
28.89 + currencyA = a;
28.90 + currencyB = b;
28.91 + currencyARate = aRate;
28.92 + currencyBRate = bRate;
28.93 + }
28.94 +
28.95 + /**
28.96 + * Convert an amount from one currency to another.
28.97 + *
28.98 + * @param from the currency to convert from.
28.99 + * @param to the currency to convert to.
28.100 + * @param amount the amount to convert.
28.101 + * @return the converted amount.
28.102 + * @throws IllegalArgumentException if any of the arguments are null.
28.103 + * @throws InvalidConversionException if either from or to are not equal to the currencies passed to the constructor.
28.104 + */
28.105 + public BigDecimal convert(final Currency from,
28.106 + final Currency to,
28.107 + final BigDecimal amount)
28.108 + throws InvalidConversionException
28.109 + {
28.110 + final BigDecimal result;
28.111 +
28.112 + if(amount == null)
28.113 + {
28.114 + throw new IllegalArgumentException("amount cannot be null");
28.115 + }
28.116 +
28.117 + if(from == null)
28.118 + {
28.119 + throw new IllegalArgumentException("from cannot be null");
28.120 + }
28.121 +
28.122 + if(to == null)
28.123 + {
28.124 + throw new IllegalArgumentException("to cannot be null");
28.125 + }
28.126 +
28.127 + if(!(from.equals(currencyA)) && (!(from.equals(currencyB))))
28.128 + {
28.129 + throw new InvalidConversionException("cannot convert from: " + from.getCurrencyCode(), from, currencyA, currencyB);
28.130 + }
28.131 +
28.132 + if(!(to.equals(currencyA)) && (!(to.equals(currencyB))))
28.133 + {
28.134 + throw new InvalidConversionException("cannot convert to: " + to.getCurrencyCode(), to, currencyA, currencyB);
28.135 + }
28.136 +
28.137 + result = amount.multiply(getConversionRate(from, to));
28.138 +
28.139 + return (result.setScale(2, RoundingMode.HALF_DOWN));
28.140 + }
28.141 +
28.142 + /**
28.143 + * Check to see if converting between the two currencies is possible.
28.144 + *
28.145 + * @param from the currency to convert from.
28.146 + * @param to the currency to convert to.
28.147 + * @return true if the conversion is possible.
28.148 + * @throws IllegalArgumentException if either from or to are null.
28.149 + */
28.150 + public boolean canConvert(final Currency from, final Currency to)
28.151 + {
28.152 + if(from == null)
28.153 + {
28.154 + throw new IllegalArgumentException("from cannot be null");
28.155 + }
28.156 +
28.157 + if(to == null)
28.158 + {
28.159 + throw new IllegalArgumentException("to cannot be null");
28.160 + }
28.161 +
28.162 + return ((from.equals(currencyA) || from.equals(currencyB)) &&
28.163 + (to.equals(currencyA) || to.equals(currencyB)));
28.164 + }
28.165 +
28.166 + /**
28.167 + * Get the currencies that the convertor supports.
28.168 + *
28.169 + * @return the supported currencies.
28.170 + */
28.171 + public Set<Currency> getCurrencies()
28.172 + {
28.173 + final Set<Currency> currencies;
28.174 +
28.175 + currencies = new HashSet<Currency>();
28.176 + currencies.add(currencyA);
28.177 + currencies.add(currencyB);
28.178 +
28.179 + return (Collections.unmodifiableSet(currencies));
28.180 + }
28.181 +
28.182 + /**
28.183 + * Get the conversion rate between two currencies.
28.184 + *
28.185 + * @param from the currency to convert from.
28.186 + * @param to the currency to convert to.
28.187 + * @return the conversion rate between the two currencies.
28.188 + * @throws InvalidConversionException if canConvert would return false.
28.189 + * @throws IllegalArgumentException if either from or to are null.
28.190 + */
28.191 + public BigDecimal getConversionRate(final Currency from,
28.192 + final Currency to)
28.193 + throws InvalidConversionException
28.194 + {
28.195 + final BigDecimal rate;
28.196 +
28.197 + if(from == null)
28.198 + {
28.199 + throw new IllegalArgumentException("from cannot be null");
28.200 + }
28.201 +
28.202 + if(to == null)
28.203 + {
28.204 + throw new IllegalArgumentException("to cannot be null");
28.205 + }
28.206 +
28.207 + if(from.equals(to))
28.208 + {
28.209 + rate = BigDecimal.ONE;
28.210 + }
28.211 + else
28.212 + {
28.213 + final BigDecimal rateX;
28.214 + final BigDecimal rateY;
28.215 + final BigDecimal temp;
28.216 +
28.217 + if(from.equals(currencyA))
28.218 + {
28.219 + rateX = currencyARate;
28.220 + rateY = currencyBRate;
28.221 + }
28.222 + else
28.223 + {
28.224 + rateX = currencyBRate;
28.225 + rateY = currencyARate;
28.226 + }
28.227 +
28.228 + temp = BigDecimal.ONE.divide(rateX, MathContext.DECIMAL64);
28.229 + rate = temp.multiply(rateY);
28.230 + }
28.231 +
28.232 + return (rate.setScale(20, RoundingMode.HALF_EVEN));
28.233 + }
28.234 +
28.235 + /**
28.236 + * Check to see if two ConvertorImpls are equal.
28.237 + *
28.238 + * @param obj the object to check
28.239 + * @return if the ConvertorImpls are not the same (cuyrrencies and rates).
28.240 + */
28.241 + @Override
28.242 + public boolean equals(Object obj)
28.243 + {
28.244 + if (obj == null)
28.245 + {
28.246 + return false;
28.247 + }
28.248 +
28.249 + if (getClass() != obj.getClass())
28.250 + {
28.251 + return false;
28.252 + }
28.253 +
28.254 + final ConvertorImpl other = (ConvertorImpl) obj;
28.255 +
28.256 + // it would be nice if NetBeans could chck to see if the variable is final and guaranteed not to be null... but that
28.257 + // would likely be tricky... but in a NetBeans engineer reads that see if you can do it :-)
28.258 + if (this.currencyA != other.currencyA && (this.currencyA == null || !this.currencyA.equals(other.currencyA)))
28.259 + {
28.260 + return false;
28.261 + }
28.262 +
28.263 + if (this.currencyB != other.currencyB && (this.currencyB == null || !this.currencyB.equals(other.currencyB)))
28.264 + {
28.265 + return false;
28.266 + }
28.267 +
28.268 + if (this.currencyARate != other.currencyARate && (this.currencyARate == null || !this.currencyARate.equals(other.currencyARate)))
28.269 + {
28.270 + return false;
28.271 + }
28.272 +
28.273 + if (this.currencyBRate != other.currencyBRate && (this.currencyBRate == null || !this.currencyBRate.equals(other.currencyBRate)))
28.274 + {
28.275 + return false;
28.276 + }
28.277 +
28.278 + return true;
28.279 + }
28.280 +
28.281 + /**
28.282 + * Get the hashCode of the Convertor.
28.283 + *
28.284 + * @return the hashCode of the convertor.
28.285 + */
28.286 + @Override
28.287 + public int hashCode()
28.288 + {
28.289 + int hash = 7;
28.290 + hash = 37 * hash + (this.currencyA != null ? this.currencyA.hashCode() : 0);
28.291 + hash = 37 * hash + (this.currencyB != null ? this.currencyB.hashCode() : 0);
28.292 + hash = 37 * hash + (this.currencyARate != null ? this.currencyARate.hashCode() : 0);
28.293 + hash = 37 * hash + (this.currencyBRate != null ? this.currencyBRate.hashCode() : 0);
28.294 + return hash;
28.295 + }
28.296 +
28.297 + /**
28.298 + * Get the currencyCode of both currencies.
28.299 + *
28.300 + * @return the currency codes of both currencies.
28.301 + */
28.302 + @Override
28.303 + public String toString()
28.304 + {
28.305 + return (currencyA.getCurrencyCode() + " to " + currencyB.getCurrencyCode());
28.306 + }
28.307 +}
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
29.2 +++ b/task4/solution04/src/org/apidesign/apifest08/currency/Convertor.java Sat Oct 11 23:38:46 2008 +0200
29.3 @@ -0,0 +1,59 @@
29.4 +package org.apidesign.apifest08.currency;
29.5 +
29.6 +
29.7 +import java.math.BigDecimal;
29.8 +import java.util.Currency;
29.9 +import java.util.Set;
29.10 +
29.11 +
29.12 +/**
29.13 + * Convert between two currencies.
29.14 + *
29.15 + * @author D'Arcy Smith
29.16 + * @version 1.0
29.17 + */
29.18 +public interface Convertor
29.19 +{
29.20 + /**
29.21 + * Convert an amount from one currency to another.
29.22 + *
29.23 + * @param from the currency to convert from.
29.24 + * @param to the currency to convert to.
29.25 + * @param amount the amount to convert.
29.26 + * @return the converted amount.
29.27 + * @throws IllegalArgumentException if any of the arguments are null.
29.28 + * @throws InvalidConversionException if either from or to are not valid for the convertor.
29.29 + */
29.30 + BigDecimal convert(Currency from,
29.31 + Currency to,
29.32 + BigDecimal amount)
29.33 + throws InvalidConversionException;
29.34 +
29.35 + /**
29.36 + * Check to see if converting between the two currencies is possible.
29.37 + *
29.38 + * @param from the currency to convert from.
29.39 + * @param to the currency to convert to.
29.40 + * @return true if the conversion is possible.
29.41 + */
29.42 + boolean canConvert(Currency from, Currency to);
29.43 +
29.44 + /**
29.45 + * Get the currencies that the convertor supports. Just because a currency is
29.46 + * supported does not mean that canConvert will return true.
29.47 + *
29.48 + * @return the supported currencies.
29.49 + */
29.50 + Set<Currency> getCurrencies();
29.51 +
29.52 + /**
29.53 + * Get the conversion rate between two currencies.
29.54 + *
29.55 + * @param from the currency to convert from.
29.56 + * @param to the currency to convert to.
29.57 + * @return the conversion rate between the two currencies.
29.58 + * @throws InvalidConversionException if canConvert would return false.
29.59 + */
29.60 + BigDecimal getConversionRate(final Currency from, final Currency to)
29.61 + throws InvalidConversionException;
29.62 +}
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
30.2 +++ b/task4/solution04/src/org/apidesign/apifest08/currency/ConvertorFactory.java Sat Oct 11 23:38:46 2008 +0200
30.3 @@ -0,0 +1,177 @@
30.4 +package org.apidesign.apifest08.currency;
30.5 +
30.6 +import java.math.BigDecimal;
30.7 +import java.util.Currency;
30.8 +
30.9 +
30.10 +/**
30.11 + * Create convertors using a flyweight to reduce the number of repetative creations of the same convertor.
30.12 + *
30.13 + * @author D'Arcy Smith
30.14 + * @version 1.0
30.15 + */
30.16 +public final class ConvertorFactory
30.17 +{
30.18 + /*
30.19 + * flyweight so that only one vestion of each converter is created at a time.
30.20 + private final static Map<String, WeakReference<Convertor>> convertors;
30.21 +
30.22 + static
30.23 + {
30.24 + convertors = new WeakHashMap<String, WeakReference<Convertor>>();
30.25 + }
30.26 + */
30.27 +
30.28 + /**
30.29 + * Prevent accidental construction.
30.30 + */
30.31 + private ConvertorFactory()
30.32 + {
30.33 + }
30.34 +
30.35 + /**
30.36 + * Get the convertor for the specified currencies. The currency name format
30.37 + * must be acceptable to java.util.Currency.getInstance(String)
30.38 + *
30.39 + * @param a the currency to convert from.
30.40 + * @param aRate the exchange rate for a to b.
30.41 + * @param b the currency to convert to.
30.42 + * @param bRate the echante rate for b to a.
30.43 + * @return the convertor for the specified currencies.
30.44 + * @throws IllegalArgumentException if any of the arguments are null.
30.45 + */
30.46 + public static Convertor getConvertor(final String a,
30.47 + final BigDecimal aRate,
30.48 + final String b,
30.49 + final BigDecimal bRate)
30.50 + {
30.51 + final Currency currencyA;
30.52 + final Currency currencyB;
30.53 + final Convertor convertor;
30.54 +
30.55 + currencyA = Currency.getInstance(a);
30.56 + currencyB = Currency.getInstance(b);
30.57 + convertor = getConvertor(currencyA, aRate, currencyB, bRate);
30.58 +
30.59 + return (convertor);
30.60 + }
30.61 +
30.62 + /**
30.63 + * Get the convertor for the specified currencies.
30.64 + *
30.65 + * @param a the currency to convert from.
30.66 + * @param aRate the exchange rate for a to b.
30.67 + * @param b the currency to convert to.
30.68 + * @param bRate the echante rate for b to a.
30.69 + * @return the convertor for the specified currencies.
30.70 + * @throws IllegalArgumentException if either any of the arguments are null or if either rate <= 0.
30.71 + */
30.72 + public static Convertor getConvertor(final Currency a,
30.73 + final BigDecimal aRate,
30.74 + final Currency b,
30.75 + final BigDecimal bRate)
30.76 + {
30.77 + // final String key;
30.78 + Convertor convertor;
30.79 +
30.80 + if(a == null)
30.81 + {
30.82 + throw new IllegalArgumentException("a cannot be null");
30.83 + }
30.84 +
30.85 + if(b == null)
30.86 + {
30.87 + throw new IllegalArgumentException("b cannot be null");
30.88 + }
30.89 +
30.90 + if(aRate == null)
30.91 + {
30.92 + throw new IllegalArgumentException("aRate cannot be null");
30.93 + }
30.94 +
30.95 + if(bRate == null)
30.96 + {
30.97 + throw new IllegalArgumentException("bRate cannot be null");
30.98 + }
30.99 +
30.100 + /*
30.101 + key = a.getCurrencyCode() + aRate + b.getCurrencyCode() + bRate;
30.102 +
30.103 + // make sure that we don't try to overwrite one
30.104 + synchronized(convertors)
30.105 + {
30.106 + if(!(convertors.containsKey(key)))
30.107 + {
30.108 + convertor = new ConvertorImpl(a, aRate, b, bRate);
30.109 + convertors.put(key, new WeakReference(convertor));
30.110 + }
30.111 +
30.112 + convertor = convertors.get(key).get();
30.113 + }
30.114 + */
30.115 +
30.116 + convertor = new ConvertorImpl(a, aRate, b, bRate);
30.117 +
30.118 + return (convertor);
30.119 + }
30.120 +
30.121 + /**
30.122 + *
30.123 + * @param cs
30.124 + * @return
30.125 + */
30.126 + public static Convertor mergeConvertors(final Convertor ... cs)
30.127 + {
30.128 + Convertor convertor;
30.129 +
30.130 + /*
30.131 + final String key;
30.132 +
30.133 + // ISSUE: only takes into account the names... not the rates...
30.134 + key = getKey(cs);
30.135 +
30.136 + // make sure that we don't try to overwrite one
30.137 + synchronized(convertors)
30.138 + {
30.139 + if(!(convertors.containsKey(key)))
30.140 + {
30.141 + convertor = new CompositeConvertorImpl(cs);
30.142 + convertors.put(key, new WeakReference(convertor));
30.143 + }
30.144 +
30.145 + convertor = convertors.get(key).get();
30.146 + }
30.147 + */
30.148 +
30.149 + convertor = new CompositeConvertorImpl(cs);
30.150 +
30.151 + return (convertor);
30.152 + }
30.153 +
30.154 + /*
30.155 + private static String getKey(final Convertor ... cs)
30.156 + {
30.157 + final Set<Currency> currencies;
30.158 + final StringBuilder builder;
30.159 +
30.160 + currencies = new HashSet<Currency>();
30.161 +
30.162 + for(final Convertor convertor : cs)
30.163 + {
30.164 + final Set<Currency> c;
30.165 +
30.166 + c = convertor.getCurrencies();
30.167 + currencies.addAll(c);
30.168 + }
30.169 +
30.170 + builder = new StringBuilder();
30.171 +
30.172 + for(final Currency currency : currencies)
30.173 + {
30.174 + builder.append(currency.getCurrencyCode());
30.175 + }
30.176 +
30.177 + return (builder.toString());
30.178 + }
30.179 + */
30.180 +}
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
31.2 +++ b/task4/solution04/src/org/apidesign/apifest08/currency/ExchangeRate.java Sat Oct 11 23:38:46 2008 +0200
31.3 @@ -0,0 +1,125 @@
31.4 +package org.apidesign.apifest08.currency;
31.5 +
31.6 +
31.7 +import java.math.BigDecimal;
31.8 +import java.util.Currency;
31.9 +
31.10 +
31.11 +/**
31.12 + * The exchange rate between two currencies.
31.13 + *
31.14 + * @author D'Arcy Smith
31.15 + * @version 1.0
31.16 + */
31.17 +public final class ExchangeRate
31.18 +{
31.19 + /**
31.20 + *
31.21 + */
31.22 + private final Currency currencyA;
31.23 +
31.24 + /**
31.25 + *
31.26 + */
31.27 + private final Currency currencyB;
31.28 +
31.29 + /**
31.30 + *
31.31 + */
31.32 + private final BigDecimal rateAtoB;
31.33 +
31.34 + /**
31.35 + *
31.36 + */
31.37 + private final BigDecimal rateBtoA;
31.38 +
31.39 + /**
31.40 + * Construct an ExchangeRate with the specified values.
31.41 + *
31.42 + * @param a the first currency
31.43 + * @param b the second currency
31.44 + * @param ra the rate to convert a to b
31.45 + * @param rb the rate to covertt b to a
31.46 + * @throws IllegalArgumentException if any parameter is null.
31.47 + */
31.48 + public ExchangeRate(final Currency a,
31.49 + final Currency b,
31.50 + final BigDecimal ra,
31.51 + final BigDecimal rb)
31.52 + {
31.53 + if(a == null)
31.54 + {
31.55 + throw new IllegalArgumentException("a cannot be null");
31.56 + }
31.57 +
31.58 + if(b == null)
31.59 + {
31.60 + throw new IllegalArgumentException("b cannot be null");
31.61 + }
31.62 +
31.63 + if(ra == null)
31.64 + {
31.65 + throw new IllegalArgumentException("ra cannot be null");
31.66 + }
31.67 +
31.68 + if(rb == null)
31.69 + {
31.70 + throw new IllegalArgumentException("rb cannot be null");
31.71 + }
31.72 +
31.73 + if(ra.compareTo(BigDecimal.ZERO) <= 0)
31.74 + {
31.75 + throw new IllegalArgumentException("ra cannot be <= 0, was: " + ra);
31.76 + }
31.77 +
31.78 + if(rb.compareTo(BigDecimal.ZERO) <= 0)
31.79 + {
31.80 + throw new IllegalArgumentException("rb cannot be <= 0, was: " + ra);
31.81 + }
31.82 +
31.83 + currencyA = a;
31.84 + currencyB = b;
31.85 + rateAtoB = ra;
31.86 + rateBtoA = rb;
31.87 + }
31.88 +
31.89 + /**
31.90 + * Get the first currency.
31.91 + *
31.92 + * @return the first currency.
31.93 + */
31.94 + public Currency getCurrencyA()
31.95 + {
31.96 + return currencyA;
31.97 + }
31.98 +
31.99 + /**
31.100 + * Get the second currency.
31.101 + *
31.102 + * @return the second currency.
31.103 + */
31.104 + public Currency getCurrencyB()
31.105 + {
31.106 + return currencyB;
31.107 + }
31.108 +
31.109 + /**
31.110 + * Get the conversion rate from currencyA to currencyB.
31.111 + *
31.112 + * @return the conversion rate from currencyA to currencyB.
31.113 + */
31.114 + public BigDecimal getRateAtoB()
31.115 + {
31.116 + return rateAtoB;
31.117 + }
31.118 +
31.119 + /**
31.120 + * Get the conversion rate from currencyB to currencyA.
31.121 + *
31.122 + * @return the conversion rate from currencyB to currencyA.
31.123 + */
31.124 + public BigDecimal getRateBtoA()
31.125 + {
31.126 + return rateBtoA;
31.127 + }
31.128 +}
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
32.2 +++ b/task4/solution04/src/org/apidesign/apifest08/currency/ExchangeRateFinder.java Sat Oct 11 23:38:46 2008 +0200
32.3 @@ -0,0 +1,22 @@
32.4 +package org.apidesign.apifest08.currency;
32.5 +
32.6 +import java.util.Currency;
32.7 +
32.8 +
32.9 +/**
32.10 + * Used to look up the exchange rate between two currencies.
32.11 + *
32.12 + * @author D'Arcy Smith
32.13 + * @version 1.0
32.14 + */
32.15 +public interface ExchangeRateFinder
32.16 +{
32.17 + /**
32.18 + * Find the exchange rate between two currencies.
32.19 + *
32.20 + * @param a the currency to convert from.
32.21 + * @param b the currency to convert to.
32.22 + * @return the exchange rate for conversions between the two currencies.
32.23 + */
32.24 + ExchangeRate findRate(Currency a, Currency b);
32.25 +}
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
33.2 +++ b/task4/solution04/src/org/apidesign/apifest08/currency/InvalidConversionException.java Sat Oct 11 23:38:46 2008 +0200
33.3 @@ -0,0 +1,95 @@
33.4 +package org.apidesign.apifest08.currency;
33.5 +
33.6 +
33.7 +import java.util.Currency;
33.8 +
33.9 +
33.10 +/**
33.11 + * Thrown when a currency is invalid for a given Convertor.
33.12 + *
33.13 + * @author D'Arcy Smith
33.14 + * @version 1.0
33.15 + */
33.16 +public class InvalidConversionException
33.17 + extends Exception
33.18 +{
33.19 + /**
33.20 + * The currency that was tried.
33.21 + */
33.22 + private final Currency badCurrency;
33.23 +
33.24 + /**
33.25 + * A currency that is valid for the Convertor.
33.26 + */
33.27 + private final Currency currencyA;
33.28 +
33.29 + /**
33.30 + * A currency that is valid for the Convertor.
33.31 + */
33.32 + private final Currency currencyB;
33.33 +
33.34 +
33.35 + /**
33.36 + * Construct a new InvalidConversionException with the specified message.
33.37 + *
33.38 + * @param msg the message for getMessage.
33.39 + * @param bad the currency that is not valid.
33.40 + */
33.41 + public InvalidConversionException(final String msg,
33.42 + final Currency bad)
33.43 + {
33.44 + this(msg, bad, null, null);
33.45 + }
33.46 +
33.47 + /**
33.48 + * Construct a new InvalidConversionException with the specified message.
33.49 + *
33.50 + * @param msg the message for getMessage.
33.51 + * @param bad the currency that is not valid.
33.52 + * @param a a valid currency.
33.53 + * @param b a valid currency.
33.54 + */
33.55 + public InvalidConversionException(final String msg,
33.56 + final Currency bad,
33.57 + final Currency a,
33.58 + final Currency b)
33.59 + {
33.60 + super(msg);
33.61 +
33.62 + badCurrency = bad;
33.63 + currencyA = a;
33.64 + currencyB = b;
33.65 + }
33.66 +
33.67 + /**
33.68 + * Get the currency that is not valid.
33.69 + *
33.70 + * @return the badCurrency
33.71 + */
33.72 + public Currency getBadCurrency()
33.73 + {
33.74 + return (badCurrency);
33.75 + }
33.76 +
33.77 + /**
33.78 + * Get a currency that is valid.
33.79 + *
33.80 + * @return the currencyA passed to the constructor.
33.81 + */
33.82 + public Currency getCurrencyA()
33.83 + {
33.84 + return (currencyA);
33.85 + }
33.86 +
33.87 + /**
33.88 + * Get a currency that is valid.
33.89 + *
33.90 + * @return the currencyB passed to the constructor.
33.91 + */
33.92 + public Currency getCurrencyB()
33.93 + {
33.94 + return (currencyB);
33.95 + }
33.96 +
33.97 +
33.98 +}
33.99 \ No newline at end of file
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
34.2 +++ b/task4/solution04/src/org/apidesign/apifest08/currency/OnlineConvertor.java Sat Oct 11 23:38:46 2008 +0200
34.3 @@ -0,0 +1,175 @@
34.4 +package org.apidesign.apifest08.currency;
34.5 +
34.6 +
34.7 +import java.math.BigDecimal;
34.8 +import java.util.Currency;
34.9 +import java.util.Set;
34.10 +
34.11 +
34.12 +/**
34.13 + * A Convertor that looks up the exchange rate with each call to "convert".
34.14 + *
34.15 + * @author D'Arcy Smith
34.16 + * @version 1.0
34.17 + */
34.18 +public class OnlineConvertor
34.19 + implements Convertor
34.20 +{
34.21 + /**
34.22 + * The currency to convert from.
34.23 + */
34.24 + private final Currency currencyA;
34.25 +
34.26 + /**
34.27 + * The currency to convert to.
34.28 + */
34.29 + private final Currency currencyB;
34.30 +
34.31 + /**
34.32 + * Used to find the current exchange rate.
34.33 + */
34.34 + private final ExchangeRateFinder finder;
34.35 +
34.36 + /**
34.37 + * The convertor to perform the conversion.
34.38 + */
34.39 + private Convertor realConvertor;
34.40 +
34.41 + /**
34.42 + * Constructs an OnlinConvertor with the specified currencies.
34.43 + *
34.44 + * @param a the currency to convert from.
34.45 + * @param b the currency to convert to.
34.46 + * @param f the finder used to obtanin the current exchange rate.
34.47 + * @throws IllegalArgumentException if either a or b are null.
34.48 + */
34.49 + public OnlineConvertor(final Currency a,
34.50 + final Currency b,
34.51 + final ExchangeRateFinder f)
34.52 + {
34.53 + if(a == null)
34.54 + {
34.55 + throw new IllegalArgumentException("a cannot be null");
34.56 + }
34.57 +
34.58 + if(b == null)
34.59 + {
34.60 + throw new IllegalArgumentException("b cannot be null");
34.61 + }
34.62 +
34.63 + if(f == null)
34.64 + {
34.65 + throw new IllegalArgumentException("f cannot be null");
34.66 + }
34.67 +
34.68 + currencyA = a;
34.69 + currencyB = b;
34.70 + finder = f;
34.71 + realConvertor = lookupRate();
34.72 + }
34.73 +
34.74 + /**
34.75 + * Convert an amount from one currency to another. Before the conversion takes place
34.76 + * the current exchange rate is looked up.
34.77 + *
34.78 + * @param from the currency to convert from.
34.79 + * @param to the currency to convert to.
34.80 + * @param amount the amount to convert.
34.81 + * @return the converted amount.
34.82 + * @throws IllegalArgumentException if any of the arguments are null.
34.83 + * @throws InvalidConversionException if either from or to are not equal to the currencies passed to the constructor.
34.84 + */
34.85 + public BigDecimal convert(final Currency from,
34.86 + final Currency to,
34.87 + final BigDecimal amount)
34.88 + throws InvalidConversionException
34.89 + {
34.90 + final BigDecimal value;
34.91 +
34.92 + synchronized(this)
34.93 + {
34.94 + realConvertor = lookupRate();
34.95 + value = realConvertor.convert(from, to, amount);
34.96 + }
34.97 +
34.98 + return (value);
34.99 + }
34.100 +
34.101 + /**
34.102 + * Lookup the current exchange rate.
34.103 + *
34.104 + * @return
34.105 + */
34.106 + private final Convertor lookupRate()
34.107 + {
34.108 + final Convertor convertor;
34.109 + final ExchangeRate rate;
34.110 +
34.111 + rate = finder.findRate(currencyA, currencyB);
34.112 + convertor = ConvertorFactory.getConvertor(rate.getCurrencyA(), rate.getRateAtoB(), rate.getCurrencyB(), rate.getRateBtoA());
34.113 +
34.114 + return (convertor);
34.115 + }
34.116 +
34.117 + /**
34.118 + * Check to see if converting between the two currencies is possible.
34.119 + *
34.120 + * @param from the currency to convert from.
34.121 + * @param to the currency to convert to.
34.122 + * @return true if the conversion is possible.
34.123 + * @throws IllegalArgumentException if either from or to are null.
34.124 + */
34.125 + public boolean canConvert(final Currency from,
34.126 + final Currency to)
34.127 + {
34.128 + if(from == null)
34.129 + {
34.130 + throw new IllegalArgumentException("from cannot be null");
34.131 + }
34.132 +
34.133 + if(to == null)
34.134 + {
34.135 + throw new IllegalArgumentException("to cannot be null");
34.136 + }
34.137 +
34.138 + return (realConvertor.canConvert(from, to));
34.139 + }
34.140 +
34.141 + /**
34.142 + * Get the currencies that the convertor supports.
34.143 + *
34.144 + * @return the supported currencies.
34.145 + */
34.146 + public Set<Currency> getCurrencies()
34.147 + {
34.148 + return (realConvertor.getCurrencies());
34.149 + }
34.150 +
34.151 + /**
34.152 + * Get the conversion rate between two currencies. This does not lookup the current
34.153 + * conversion rate (it probably should, but given the way the contest works that might
34.154 + * not be a good idea - if it were the real world way it might be a good idea).
34.155 + *
34.156 + * @param from the currency to convert from.
34.157 + * @param to the currency to convert to.
34.158 + * @return the conversion rate between the two currencies.
34.159 + * @throws InvalidConversionException if canConvert would return false.
34.160 + * @throws IllegalArgumentException if either from or to are null.
34.161 + */
34.162 + public BigDecimal getConversionRate(final Currency from,
34.163 + final Currency to)
34.164 + throws InvalidConversionException
34.165 + {
34.166 + if(from == null)
34.167 + {
34.168 + throw new IllegalArgumentException("from cannot be null");
34.169 + }
34.170 +
34.171 + if(to == null)
34.172 + {
34.173 + throw new IllegalArgumentException("to cannot be null");
34.174 + }
34.175 +
34.176 + return (realConvertor.getConversionRate(from, to));
34.177 + }
34.178 +}
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
35.2 +++ b/task4/solution04/test/org/apidesign/apifest08/test/Task1Test.java Sat Oct 11 23:38:46 2008 +0200
35.3 @@ -0,0 +1,223 @@
35.4 +package org.apidesign.apifest08.test;
35.5 +
35.6 +
35.7 +import java.math.BigDecimal;
35.8 +import java.util.Currency;
35.9 +import java.util.Set;
35.10 +import junit.framework.TestCase;
35.11 +import org.apidesign.apifest08.currency.Convertor;
35.12 +import org.apidesign.apifest08.currency.ConvertorFactory;
35.13 +import org.apidesign.apifest08.currency.InvalidConversionException;
35.14 +
35.15 +
35.16 +/** Finish the Convertor API, and then write bodies of methods inside
35.17 + * of this class to match the given tasks. To fullfil your task, use the
35.18 + * API define in the <code>org.apidesign.apifest08.currency</code> package.
35.19 + * Do not you reflection, or other hacks as your code
35.20 + * shall run without any runtime permissions.
35.21 + */
35.22 +public class Task1Test extends TestCase {
35.23 +
35.24 + private final static Currency CZK;
35.25 + private final static Currency SKK;
35.26 + private final static Currency USD;
35.27 +
35.28 + static
35.29 + {
35.30 + CZK = Currency.getInstance("CZK");
35.31 + SKK = Currency.getInstance("SKK");
35.32 + USD = Currency.getInstance("USD");
35.33 + }
35.34 +
35.35 + public Task1Test(String testName) {
35.36 + super(testName);
35.37 + }
35.38 +
35.39 + @Override
35.40 + protected void setUp() throws Exception {
35.41 + }
35.42 +
35.43 + @Override
35.44 + protected void tearDown() throws Exception {
35.45 + }
35.46 +
35.47 + /** Create convertor that understands two currencies, CZK and
35.48 + * USD. Make 1 USD == 17 CZK.
35.49 + *
35.50 + * Creation of the convertor shall not require subclassing of any class
35.51 + * or interface on the client side.
35.52 + *
35.53 + * @return prepared convertor ready for converting USD to CZK and CZK to USD
35.54 + */
35.55 + public static Convertor createCZKtoUSD()
35.56 + {
35.57 + return (ConvertorFactory.getConvertor("CZK", BigDecimal.valueOf(17.0),
35.58 + "USD", BigDecimal.valueOf(1)));
35.59 + }
35.60 +
35.61 + /** Create convertor that understands two currencies, CZK and
35.62 + * SKK. Make 100 SKK == 80 CZK.
35.63 + *
35.64 + * Creation of the convertor shall not require subclassing of any class
35.65 + * or interface on the client side.
35.66 + *
35.67 + * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
35.68 + */
35.69 + public static Convertor createSKKtoCZK()
35.70 + {
35.71 + return (ConvertorFactory.getConvertor(Currency.getInstance("SKK"), BigDecimal.valueOf(100),
35.72 + Currency.getInstance("CZK"), BigDecimal.valueOf(80)));
35.73 + }
35.74 +
35.75 + /** Use the convertor from <code>createCZKtoUSD</code> method and do few conversions
35.76 + * with it.
35.77 + */
35.78 + public void testCurrencyCZKUSD() throws Exception {
35.79 + Convertor c = createCZKtoUSD();
35.80 + BigDecimal result;
35.81 +
35.82 + // convert $5 to CZK using c:
35.83 + // assertEquals("Result is 85 CZK");
35.84 + result = c.convert(USD, CZK, BigDecimal.valueOf(5));
35.85 + assertEquals(new BigDecimal("85.00"), result);
35.86 +
35.87 + // convert $8 to CZK
35.88 + // assertEquals("Result is 136 CZK");
35.89 + result = c.convert(USD, CZK, BigDecimal.valueOf(8));
35.90 + assertEquals(new BigDecimal("136.00"), result);
35.91 +
35.92 + // convert 1003CZK to USD
35.93 + // assertEquals("Result is 59 USD");
35.94 + result = c.convert(CZK, USD, BigDecimal.valueOf(1003));
35.95 + assertEquals(new BigDecimal("59.00"), result);
35.96 + }
35.97 +
35.98 + /** Use the convertor from <code>createSKKtoCZK</code> method and do few conversions
35.99 + * with it.
35.100 + */
35.101 + public void testCurrencySKKCZK() throws Exception {
35.102 + Convertor c = createSKKtoCZK();
35.103 + BigDecimal result;
35.104 +
35.105 + // convert 16CZK using c:
35.106 + // assertEquals("Result is 20 SKK");
35.107 + result = c.convert(CZK, SKK, BigDecimal.valueOf(16));
35.108 + assertEquals(new BigDecimal("20.00"), result);
35.109 +
35.110 + // convert 500SKK to CZK
35.111 + // assertEquals("Result is 400 CZK");
35.112 + result = c.convert(SKK, CZK, BigDecimal.valueOf(500));
35.113 + assertEquals(new BigDecimal("400.00"), result);
35.114 + }
35.115 +
35.116 + /**
35.117 + * Verify that the CZK to USD convertor knows nothing about SKK.
35.118 + */
35.119 + public void testCannotConvertToSKKwithCZKUSDConvertor()
35.120 + throws Exception
35.121 + {
35.122 + Convertor c = createCZKtoUSD();
35.123 +
35.124 + try
35.125 + {
35.126 + // convert $5 to SKK, the API shall say this is not possible
35.127 + c.convert(USD, SKK, BigDecimal.valueOf(5));
35.128 + fail("cannot use the CZKtoUSD converter to convert to SKK");
35.129 + }
35.130 + catch(InvalidConversionException ex)
35.131 + {
35.132 + assertEquals("cannot convert to: SKK", ex.getMessage());
35.133 + assertEquals(SKK, ex.getBadCurrency());
35.134 + assertEquals(CZK, ex.getCurrencyA());
35.135 + assertEquals(USD, ex.getCurrencyB());
35.136 + }
35.137 +
35.138 + try
35.139 + {
35.140 + // convert 500 SKK to CZK, the API shall say this is not possible
35.141 + c.convert(SKK, CZK, BigDecimal.valueOf(5));
35.142 + fail("cannot use the CZKtoUSD converter to convert from SKK");
35.143 + }
35.144 + catch(InvalidConversionException ex)
35.145 + {
35.146 + assertEquals("cannot convert from: SKK", ex.getMessage());
35.147 + assertEquals(SKK, ex.getBadCurrency());
35.148 + assertEquals(CZK, ex.getCurrencyA());
35.149 + assertEquals(USD, ex.getCurrencyB());
35.150 + }
35.151 + }
35.152 +
35.153 + /**
35.154 + * Verify that the CZK to SKK convertor knows nothing about USD.
35.155 + */
35.156 + public void testCannotConvertToUSDwithSKKCZKConvertor()
35.157 + throws Exception
35.158 + {
35.159 + Convertor c = createSKKtoCZK();
35.160 +
35.161 + try
35.162 + {
35.163 + // convert $5 to SKK, the API shall say this is not possible
35.164 + c.convert(USD, SKK, BigDecimal.valueOf(5));
35.165 + fail("cannot use the CZKtoUSD converter to convert to SKK");
35.166 + }
35.167 + catch(InvalidConversionException ex)
35.168 + {
35.169 + assertEquals("cannot convert from: USD", ex.getMessage());
35.170 + assertEquals(USD, ex.getBadCurrency());
35.171 + assertEquals(SKK, ex.getCurrencyA());
35.172 + assertEquals(CZK, ex.getCurrencyB());
35.173 + }
35.174 +
35.175 + try
35.176 + {
35.177 + // convert 500 CZK to USD, the API shall say this is not possible
35.178 + c.convert(CZK, USD, BigDecimal.valueOf(500));
35.179 + fail("cannot use the CZKtoUSD converter to convert from SKK");
35.180 + }
35.181 + catch(InvalidConversionException ex)
35.182 + {
35.183 + assertEquals("cannot convert to: USD", ex.getMessage());
35.184 + assertEquals(USD, ex.getBadCurrency());
35.185 + assertEquals(SKK, ex.getCurrencyA());
35.186 + assertEquals(CZK, ex.getCurrencyB());
35.187 + }
35.188 + }
35.189 +
35.190 + public void testGetCurrencies()
35.191 + {
35.192 + Convertor c;
35.193 + Set<Currency> currencies;
35.194 +
35.195 + c = createSKKtoCZK();
35.196 + currencies = c.getCurrencies();
35.197 + assertEquals(2, currencies.size());
35.198 + assertTrue(currencies.contains(Currency.getInstance("SKK")));
35.199 + assertTrue(currencies.contains(Currency.getInstance("CZK")));
35.200 +
35.201 + c = createCZKtoUSD();
35.202 + currencies = c.getCurrencies();
35.203 + assertEquals(2, currencies.size());
35.204 + assertTrue(currencies.contains(Currency.getInstance("USD")));
35.205 + assertTrue(currencies.contains(Currency.getInstance("CZK")));
35.206 + }
35.207 +
35.208 + public void testGetConverstionRate()
35.209 + throws InvalidConversionException
35.210 + {
35.211 + Convertor c;
35.212 +
35.213 + c = createSKKtoCZK();
35.214 + assertEquals(1.0, c.getConversionRate(Currency.getInstance("CZK"), Currency.getInstance("CZK")).doubleValue());
35.215 + assertEquals(1.0, c.getConversionRate(Currency.getInstance("SKK"), Currency.getInstance("SKK")).doubleValue());
35.216 + assertEquals(0.80, c.getConversionRate(Currency.getInstance("SKK"), Currency.getInstance("CZK")).doubleValue());
35.217 + assertEquals(1.25, c.getConversionRate(Currency.getInstance("CZK"), Currency.getInstance("SKK")).doubleValue());
35.218 +
35.219 + c = createCZKtoUSD();
35.220 + assertEquals(1.0, c.getConversionRate(Currency.getInstance("CZK"), Currency.getInstance("CZK")).doubleValue());
35.221 + assertEquals(1.0, c.getConversionRate(Currency.getInstance("USD"), Currency.getInstance("USD")).doubleValue());
35.222 + assertEquals(1.0/17.0, c.getConversionRate(Currency.getInstance("CZK"), Currency.getInstance("USD")).doubleValue(), 0.00000000000000001);
35.223 + assertEquals(17.0, c.getConversionRate(Currency.getInstance("USD"), Currency.getInstance("CZK")).doubleValue(), 0.00000000000000001);
35.224 + }
35.225 +}
35.226 +
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
36.2 +++ b/task4/solution04/test/org/apidesign/apifest08/test/Task2Test.java Sat Oct 11 23:38:46 2008 +0200
36.3 @@ -0,0 +1,179 @@
36.4 +package org.apidesign.apifest08.test;
36.5 +
36.6 +import java.math.BigDecimal;
36.7 +import java.util.Currency;
36.8 +import java.util.Set;
36.9 +import junit.framework.TestCase;
36.10 +import org.apidesign.apifest08.currency.Convertor;
36.11 +import org.apidesign.apifest08.currency.ConvertorFactory;
36.12 +import org.apidesign.apifest08.currency.InvalidConversionException;
36.13 +
36.14 +
36.15 +/** There are many currencies around the world and many banks manipulate
36.16 + * with more than one or two at the same time. As banks are usually the
36.17 + * best paying clients, which is true even in case of your Convertor API,
36.18 + * it is reasonable to listen to their requests.
36.19 + * <p>
36.20 + * The quest for today is to enhance your existing convertor API to hold
36.21 + * information about many currencies and allow conversions between any of them.
36.22 + * Also, as conversion rates for diferent currencies usually arise from various
36.23 + * bank departments, there is another important need. There is a need to
36.24 + * compose two convertors into one by merging all the information about
36.25 + * currencies they know about.
36.26 + */
36.27 +public class Task2Test extends TestCase
36.28 +{
36.29 + private final static Currency CZK;
36.30 + private final static Currency SKK;
36.31 + private final static Currency USD;
36.32 +
36.33 + static
36.34 + {
36.35 + CZK = Currency.getInstance("CZK");
36.36 + SKK = Currency.getInstance("SKK");
36.37 + USD = Currency.getInstance("USD");
36.38 + }
36.39 +
36.40 + public Task2Test(String testName)
36.41 + {
36.42 + super(testName);
36.43 + }
36.44 +
36.45 + @Override
36.46 + protected void setUp()
36.47 + throws Exception
36.48 + {
36.49 + }
36.50 +
36.51 + @Override
36.52 + protected void tearDown()
36.53 + throws Exception
36.54 + {
36.55 + }
36.56 +
36.57 + // As in Task1Test, keep in mind, that there are three parts
36.58 + // of the whole system:
36.59 + // 1. there is someone who knows the current exchange rate
36.60 + // 2. there is someone who wants to do the conversion
36.61 + // 3. there is the API between 1. and 2. which allows them to communicate
36.62 + //
36.63 + // Please backward compatibly enhance your existing API to support following
36.64 + // usecases:
36.65 + //
36.66 +
36.67 + /** Create convertor that understands two currencies, CZK and
36.68 + * SKK. Make 100 SKK == 75 CZK. This is method for the group of users that
36.69 + * knows the exchange rate, and needs to use the API to create objects
36.70 + * with the exchange rate. Anyone shall be ready to call this method without
36.71 + * any other method being called previously. The API itself shall know
36.72 + * nothing about any rates, before this method is called.
36.73 + */
36.74 + public static Convertor createTripleConvertor() {
36.75 + // Rates: 1USD = 15CZK
36.76 + // Rates: 1USD = 20SKK
36.77 + // Rates: 75CZK = 100SKK
36.78 + Convertor c = ConvertorFactory.mergeConvertors(
36.79 + ConvertorFactory.getConvertor(USD, BigDecimal.ONE, CZK, BigDecimal.valueOf(15.00)),
36.80 + ConvertorFactory.getConvertor(USD, BigDecimal.ONE, SKK, BigDecimal.valueOf(20.00))
36.81 + );
36.82 +
36.83 + return c;
36.84 + }
36.85 +
36.86 + /** Define convertor that understands three currencies. Use it.
36.87 + */
36.88 + public void testConvertorForUSDandCZKandSKK() throws Exception {
36.89 + Convertor c = createTripleConvertor();
36.90 +
36.91 + // convert $5 to CZK using c:
36.92 + // assertEquals("Result is 75 CZK");
36.93 + assertEquals(new BigDecimal("75.00"), c.convert(USD, CZK, BigDecimal.valueOf(5.00)));
36.94 +
36.95 + // convert $5 to SKK using c:
36.96 + // assertEquals("Result is 100 SKK");
36.97 + assertEquals(new BigDecimal("100.00"), c.convert(USD, SKK, BigDecimal.valueOf(5.00)));
36.98 +
36.99 + // convert 200SKK to CZK using c:
36.100 + // assertEquals("Result is 150 CZK");
36.101 + assertEquals(new BigDecimal("150.00"), c.convert(SKK, CZK, BigDecimal.valueOf(200.00)));
36.102 +
36.103 + // convert 200SKK to USK using c:
36.104 + // assertEquals("Result is 10 USD");
36.105 + assertEquals(new BigDecimal("10.00"), c.convert(SKK, USD, BigDecimal.valueOf(200.00)));
36.106 + }
36.107 +
36.108 + /** Merge all currency rates of convertor 1 with convertor 2.
36.109 + * Implement this using your API, preferably this method just delegates
36.110 + * into some API method which does the actual work, without requiring
36.111 + * API clients to code anything complex.
36.112 + */
36.113 + public static Convertor merge(Convertor one, Convertor two) {
36.114 + return ConvertorFactory.mergeConvertors(one, two);
36.115 + }
36.116 +
36.117 + /** Join the convertors from previous task, Task1Test and show that it
36.118 + * can be used to do reasonable conversions.
36.119 + */
36.120 + public void testConvertorComposition() throws Exception {
36.121 + Convertor c = merge(
36.122 + Task1Test.createCZKtoUSD(),
36.123 + Task1Test.createSKKtoCZK()
36.124 + );
36.125 +
36.126 + // convert $5 to CZK using c:
36.127 + // assertEquals("Result is 85 CZK");
36.128 + assertEquals(new BigDecimal("85.00"), c.convert(USD, CZK, BigDecimal.valueOf(5.00)));
36.129 +
36.130 + // convert $8 to CZK using c:
36.131 + // assertEquals("Result is 136 CZK");
36.132 + assertEquals(new BigDecimal("136.00"), c.convert(USD, CZK, BigDecimal.valueOf(8.00)));
36.133 +
36.134 + // convert 1003CZK to USD using c:
36.135 + // assertEquals("Result is 59 USD");
36.136 + assertEquals(new BigDecimal("59.00"), c.convert(CZK, USD, BigDecimal.valueOf(1003.00)));
36.137 +
36.138 + // convert 16CZK using c:
36.139 + // assertEquals("Result is 20 SKK");
36.140 + assertEquals(new BigDecimal("20.00"), c.convert(CZK, SKK, BigDecimal.valueOf(16.00)));
36.141 +
36.142 + // convert 500SKK to CZK using c:
36.143 + // assertEquals("Result is 400 CZK");
36.144 + assertEquals(new BigDecimal("400.00"), c.convert(SKK, CZK, BigDecimal.valueOf(500.00)));
36.145 + }
36.146 +
36.147 + public void testGetCurrencies()
36.148 + {
36.149 + Convertor c = merge(
36.150 + Task1Test.createCZKtoUSD(),
36.151 + Task1Test.createSKKtoCZK()
36.152 + );
36.153 + Set<Currency> currencies;
36.154 +
36.155 + currencies = c.getCurrencies();
36.156 + assertEquals(3, currencies.size());
36.157 + assertTrue(currencies.contains(Currency.getInstance("SKK")));
36.158 + assertTrue(currencies.contains(Currency.getInstance("CZK")));
36.159 + assertTrue(currencies.contains(Currency.getInstance("USD")));
36.160 + }
36.161 +
36.162 + public void testGetConverstionRate()
36.163 + throws InvalidConversionException
36.164 + {
36.165 + Convertor c = merge(
36.166 + Task1Test.createCZKtoUSD(),
36.167 + Task1Test.createSKKtoCZK()
36.168 + );
36.169 +
36.170 + assertEquals(1.0, c.getConversionRate(USD, USD).doubleValue(), 0.0000000000000001);
36.171 + assertEquals(17.0, c.getConversionRate(USD, CZK).doubleValue(), 0.0000000000000001);
36.172 + assertEquals(21.25, c.getConversionRate(USD, SKK).doubleValue(), 0.0000000000000001);
36.173 +
36.174 + assertEquals(1.0 / 17.0, c.getConversionRate(CZK, USD).doubleValue(), 0.0000000000000001);
36.175 + assertEquals(1.0, c.getConversionRate(CZK, CZK).doubleValue(), 0.0000000000000001);
36.176 + assertEquals(1.25, c.getConversionRate(CZK, SKK).doubleValue(), 0.0000000000000001);
36.177 +
36.178 + assertEquals(0.04705882352941176, c.getConversionRate(SKK, USD).doubleValue(), 0.0000000000000001);
36.179 + assertEquals(0.8, c.getConversionRate(SKK, CZK).doubleValue(), 0.0000000000000001);
36.180 + assertEquals(1.0, c.getConversionRate(SKK, SKK).doubleValue(), 0.0000000000000001);
36.181 + }
36.182 +}
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
37.2 +++ b/task4/solution04/test/org/apidesign/apifest08/test/Task3Test.java Sat Oct 11 23:38:46 2008 +0200
37.3 @@ -0,0 +1,145 @@
37.4 +package org.apidesign.apifest08.test;
37.5 +
37.6 +import java.math.BigDecimal;
37.7 +import java.util.Currency;
37.8 +import junit.framework.TestCase;
37.9 +import org.apidesign.apifest08.currency.Convertor;
37.10 +import org.apidesign.apifest08.currency.InvalidConversionException;
37.11 +import org.apidesign.apifest08.currency.OnlineConvertor;
37.12 +
37.13 +/** The exchange rates are not always the same. They are changing. Day by day,
37.14 + * hour by hour, minute by minute. For every bank it is important to always
37.15 + * have the actual exchange rate available in the system. That is why let's
37.16 + * create a pluggable convertor that will always have up to date value of its
37.17 + * exchange rate.
37.18 + * <p>
37.19 + * The quest for today is to allow 3rd party developer to write a convertor
37.20 + * that adjusts its exchange rate everytime it is queried. This convertor is
37.21 + * written by independent vendor, the vendor knows only your Convertor API,
37.22 + * he does not know how the whole system looks and how the convertor is supposed
37.23 + * to be used.
37.24 + */
37.25 +public class Task3Test
37.26 + extends TestCase
37.27 +{
37.28 + private final static Currency CZK;
37.29 + private final static Currency SKK;
37.30 + private final static Currency USD;
37.31 +
37.32 + static
37.33 + {
37.34 + CZK = Currency.getInstance("CZK");
37.35 + SKK = Currency.getInstance("SKK");
37.36 + USD = Currency.getInstance("USD");
37.37 + }
37.38 +
37.39 + public Task3Test(String testName)
37.40 + {
37.41 + super(testName);
37.42 + }
37.43 +
37.44 + @Override
37.45 + protected void setUp() throws Exception
37.46 + {
37.47 + }
37.48 +
37.49 + @Override
37.50 + protected void tearDown() throws Exception
37.51 + {
37.52 + }
37.53 +
37.54 + // Backward compatibly enhance your existing API to support following
37.55 + // usecases:
37.56 + //
37.57 +
37.58 +
37.59 + /** Without knowing anything about the surrounding system, write an
37.60 + * implementation of convertor that will return different rates everytime
37.61 + * it is queried. Convert USD to CZK and vice versa. Start with the rate of
37.62 + * 1USD = 16CZK and adjust it in favor of CZK by 0.01 CZK with every query.
37.63 + * As soon as you reach 1USD = 15CZK adjust it by 0.01 CZK in favor of USD
37.64 + * until you reach 1USD = 16CZK
37.65 + *
37.66 + * @return new instance of "online" USD and CZK convertor starting with rate 1USD = 16CZK
37.67 + * @throws InvalidConversionException
37.68 + */
37.69 + public static Convertor createOnlineCZKUSDConvertor()
37.70 + throws InvalidConversionException
37.71 + {
37.72 + final Convertor convertor;
37.73 +
37.74 + convertor = new OnlineConvertor(USD,
37.75 + CZK,
37.76 + new TestExchangeRateFinder(new BigDecimal("15.00"),
37.77 + new BigDecimal("16.00"),
37.78 + new BigDecimal("16.00"),
37.79 + new BigDecimal("0.01"),
37.80 + new BigDecimal("-0.01")));
37.81 +
37.82 + // initial rate: 1USD = 16CZK
37.83 + // 2nd query 1USD = 15.99CZK
37.84 + // 3rd query 1USD = 15.98CZK
37.85 + // until 1USD = 15.00CZK
37.86 + // then 1USD = 15.01CZK
37.87 + // then 1USD = 15.02CZK
37.88 + // and so on and on up to 1USD = 16CZK
37.89 + // and then another round to 15, etc.
37.90 + return convertor;
37.91 + }
37.92 +
37.93 + public void testFewQueriesForOnlineConvertor()
37.94 + throws InvalidConversionException
37.95 + {
37.96 + Convertor c = createOnlineCZKUSDConvertor();
37.97 + doFewQueriesForOnlineConvertor(c);
37.98 + }
37.99 +
37.100 + static void doFewQueriesForOnlineConvertor(Convertor c)
37.101 + throws InvalidConversionException
37.102 + {
37.103 + BigDecimal amount;
37.104 +
37.105 + // convert $5 to CZK using c:
37.106 + //assertEquals("Result is 80 CZK");
37.107 + amount = c.convert(USD, CZK, new BigDecimal("5.00"));
37.108 + assertEquals(new BigDecimal("80.00"), amount);
37.109 +
37.110 + // convert $8 to CZK using c:
37.111 + //assertEquals("Result is 127.92 CZK");
37.112 + amount = c.convert(USD, CZK, new BigDecimal("8.00"));
37.113 + assertEquals(new BigDecimal("127.92"), amount);
37.114 +
37.115 + // convert $1 to CZK using c:
37.116 + //assertEquals("Result is 15.98 CZK");
37.117 + amount = c.convert(USD, CZK, new BigDecimal("1.00"));
37.118 + assertEquals(new BigDecimal("15.98"), amount);
37.119 +
37.120 + // convert 15.97CZK to USD using c:
37.121 + //assertEquals("Result is 1$");
37.122 + amount = c.convert(CZK, USD, new BigDecimal("15.97"));
37.123 + assertEquals(new BigDecimal("1.00"), amount);
37.124 + }
37.125 +
37.126 + /** Join the convertors and show they behave sane.
37.127 + */
37.128 + public void testOnlineConvertorComposition() throws Exception {
37.129 + BigDecimal amount;
37.130 +
37.131 + Convertor c = Task2Test.merge(
37.132 + createOnlineCZKUSDConvertor(),
37.133 + Task1Test.createSKKtoCZK()
37.134 + );
37.135 +
37.136 + // convert 16CZK to SKK using c:
37.137 + // assertEquals("Result is 20 SKK");
37.138 + amount = c.convert(CZK, SKK, new BigDecimal("16.00"));
37.139 + assertEquals(new BigDecimal("20.00"), amount);
37.140 +
37.141 + // convert 500SKK to CZK using c:
37.142 + // assertEquals("Result is 400 CZK");
37.143 + amount = c.convert(SKK, CZK, new BigDecimal("500.00"));
37.144 + assertEquals(new BigDecimal("400.00"), amount);
37.145 +
37.146 + doFewQueriesForOnlineConvertor(c);
37.147 + }
37.148 +}
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
38.2 +++ b/task4/solution04/test/org/apidesign/apifest08/test/TestExchangeRateFinder.java Sat Oct 11 23:38:46 2008 +0200
38.3 @@ -0,0 +1,61 @@
38.4 +package org.apidesign.apifest08.test;
38.5 +
38.6 +
38.7 +import java.math.BigDecimal;
38.8 +import java.util.Currency;
38.9 +import org.apidesign.apifest08.currency.ExchangeRate;
38.10 +import org.apidesign.apifest08.currency.ExchangeRateFinder;
38.11 +
38.12 +
38.13 +class TestExchangeRateFinder
38.14 + implements ExchangeRateFinder
38.15 +{
38.16 + private final BigDecimal min;
38.17 + private final BigDecimal max;
38.18 + private final BigDecimal stepUp;
38.19 + private final BigDecimal stepDown;
38.20 + private BigDecimal step;
38.21 + private BigDecimal rate;
38.22 + private boolean firstCall;
38.23 +
38.24 + TestExchangeRateFinder(final BigDecimal mn,
38.25 + final BigDecimal mx,
38.26 + final BigDecimal start,
38.27 + final BigDecimal up,
38.28 + final BigDecimal down)
38.29 + {
38.30 + min = mn;
38.31 + max = mx;
38.32 + rate = start;
38.33 + stepUp = up;
38.34 + stepDown = down;
38.35 + firstCall = true;
38.36 + }
38.37 +
38.38 + public ExchangeRate findRate(Currency a, Currency b)
38.39 + {
38.40 + final ExchangeRate value;
38.41 +
38.42 + if(rate.equals(max))
38.43 + {
38.44 + step = stepDown;
38.45 + }
38.46 + else if(rate.equals(min))
38.47 + {
38.48 + step = stepUp;
38.49 + }
38.50 +
38.51 + value = new ExchangeRate(a, b, BigDecimal.ONE, rate);
38.52 +
38.53 + if(firstCall)
38.54 + {
38.55 + firstCall = false;
38.56 + }
38.57 + else
38.58 + {
38.59 + rate = rate.add(step);
38.60 + }
38.61 +
38.62 + return (value);
38.63 + }
38.64 +}
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
39.2 +++ b/task4/solution06/build.xml Sat Oct 11 23:38:46 2008 +0200
39.3 @@ -0,0 +1,69 @@
39.4 +<?xml version="1.0" encoding="UTF-8"?>
39.5 +<!-- You may freely edit this file. See commented blocks below for -->
39.6 +<!-- some examples of how to customize the build. -->
39.7 +<!-- (If you delete it and reopen the project it will be recreated.) -->
39.8 +<project name="currency" default="default" basedir=".">
39.9 + <description>Builds, tests, and runs the project.</description>
39.10 + <import file="nbproject/build-impl.xml"/>
39.11 + <!--
39.12 +
39.13 + There exist several targets which are by default empty and which can be
39.14 + used for execution of your tasks. These targets are usually executed
39.15 + before and after some main targets. They are:
39.16 +
39.17 + -pre-init: called before initialization of project properties
39.18 + -post-init: called after initialization of project properties
39.19 + -pre-compile: called before javac compilation
39.20 + -post-compile: called after javac compilation
39.21 + -pre-compile-single: called before javac compilation of single file
39.22 + -post-compile-single: called after javac compilation of single file
39.23 + -pre-compile-test: called before javac compilation of JUnit tests
39.24 + -post-compile-test: called after javac compilation of JUnit tests
39.25 + -pre-compile-test-single: called before javac compilation of single JUnit test
39.26 + -post-compile-test-single: called after javac compilation of single JUunit test
39.27 + -pre-jar: called before JAR building
39.28 + -post-jar: called after JAR building
39.29 + -post-clean: called after cleaning build products
39.30 +
39.31 + (Targets beginning with '-' are not intended to be called on their own.)
39.32 +
39.33 + Example of inserting an obfuscator after compilation could look like this:
39.34 +
39.35 + <target name="-post-compile">
39.36 + <obfuscate>
39.37 + <fileset dir="${build.classes.dir}"/>
39.38 + </obfuscate>
39.39 + </target>
39.40 +
39.41 + For list of available properties check the imported
39.42 + nbproject/build-impl.xml file.
39.43 +
39.44 +
39.45 + Another way to customize the build is by overriding existing main targets.
39.46 + The targets of interest are:
39.47 +
39.48 + -init-macrodef-javac: defines macro for javac compilation
39.49 + -init-macrodef-junit: defines macro for junit execution
39.50 + -init-macrodef-debug: defines macro for class debugging
39.51 + -init-macrodef-java: defines macro for class execution
39.52 + -do-jar-with-manifest: JAR building (if you are using a manifest)
39.53 + -do-jar-without-manifest: JAR building (if you are not using a manifest)
39.54 + run: execution of project
39.55 + -javadoc-build: Javadoc generation
39.56 + test-report: JUnit report generation
39.57 +
39.58 + An example of overriding the target for project execution could look like this:
39.59 +
39.60 + <target name="run" depends="currency-impl.jar">
39.61 + <exec dir="bin" executable="launcher.exe">
39.62 + <arg file="${dist.jar}"/>
39.63 + </exec>
39.64 + </target>
39.65 +
39.66 + Notice that the overridden target depends on the jar target and not only on
39.67 + the compile target as the regular run target does. Again, for a list of available
39.68 + properties which you can use, check the target you are overriding in the
39.69 + nbproject/build-impl.xml file.
39.70 +
39.71 + -->
39.72 +</project>
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
40.2 +++ b/task4/solution06/nbproject/build-impl.xml Sat Oct 11 23:38:46 2008 +0200
40.3 @@ -0,0 +1,642 @@
40.4 +<?xml version="1.0" encoding="UTF-8"?>
40.5 +<!--
40.6 +*** GENERATED FROM project.xml - DO NOT EDIT ***
40.7 +*** EDIT ../build.xml INSTEAD ***
40.8 +
40.9 +For the purpose of easier reading the script
40.10 +is divided into following sections:
40.11 +
40.12 + - initialization
40.13 + - compilation
40.14 + - jar
40.15 + - execution
40.16 + - debugging
40.17 + - javadoc
40.18 + - junit compilation
40.19 + - junit execution
40.20 + - junit debugging
40.21 + - applet
40.22 + - cleanup
40.23 +
40.24 + -->
40.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">
40.26 + <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
40.27 + <!--
40.28 + ======================
40.29 + INITIALIZATION SECTION
40.30 + ======================
40.31 + -->
40.32 + <target name="-pre-init">
40.33 + <!-- Empty placeholder for easier customization. -->
40.34 + <!-- You can override this target in the ../build.xml file. -->
40.35 + </target>
40.36 + <target depends="-pre-init" name="-init-private">
40.37 + <property file="nbproject/private/config.properties"/>
40.38 + <property file="nbproject/private/configs/${config}.properties"/>
40.39 + <property file="nbproject/private/private.properties"/>
40.40 + </target>
40.41 + <target depends="-pre-init,-init-private" name="-init-user">
40.42 + <property file="${user.properties.file}"/>
40.43 + <!-- The two properties below are usually overridden -->
40.44 + <!-- by the active platform. Just a fallback. -->
40.45 + <property name="default.javac.source" value="1.4"/>
40.46 + <property name="default.javac.target" value="1.4"/>
40.47 + </target>
40.48 + <target depends="-pre-init,-init-private,-init-user" name="-init-project">
40.49 + <property file="nbproject/configs/${config}.properties"/>
40.50 + <property file="nbproject/project.properties"/>
40.51 + </target>
40.52 + <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
40.53 + <available file="${manifest.file}" property="manifest.available"/>
40.54 + <condition property="manifest.available+main.class">
40.55 + <and>
40.56 + <isset property="manifest.available"/>
40.57 + <isset property="main.class"/>
40.58 + <not>
40.59 + <equals arg1="${main.class}" arg2="" trim="true"/>
40.60 + </not>
40.61 + </and>
40.62 + </condition>
40.63 + <condition property="manifest.available+main.class+mkdist.available">
40.64 + <and>
40.65 + <istrue value="${manifest.available+main.class}"/>
40.66 + <isset property="libs.CopyLibs.classpath"/>
40.67 + </and>
40.68 + </condition>
40.69 + <condition property="have.tests">
40.70 + <or>
40.71 + <available file="${test.src.dir}"/>
40.72 + </or>
40.73 + </condition>
40.74 + <condition property="have.sources">
40.75 + <or>
40.76 + <available file="${src.dir}"/>
40.77 + </or>
40.78 + </condition>
40.79 + <condition property="netbeans.home+have.tests">
40.80 + <and>
40.81 + <isset property="netbeans.home"/>
40.82 + <isset property="have.tests"/>
40.83 + </and>
40.84 + </condition>
40.85 + <condition property="no.javadoc.preview">
40.86 + <and>
40.87 + <isset property="javadoc.preview"/>
40.88 + <isfalse value="${javadoc.preview}"/>
40.89 + </and>
40.90 + </condition>
40.91 + <property name="run.jvmargs" value=""/>
40.92 + <property name="javac.compilerargs" value=""/>
40.93 + <property name="work.dir" value="${basedir}"/>
40.94 + <condition property="no.deps">
40.95 + <and>
40.96 + <istrue value="${no.dependencies}"/>
40.97 + </and>
40.98 + </condition>
40.99 + <property name="javac.debug" value="true"/>
40.100 + <property name="javadoc.preview" value="true"/>
40.101 + <property name="application.args" value=""/>
40.102 + <property name="source.encoding" value="${file.encoding}"/>
40.103 + <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
40.104 + <and>
40.105 + <isset property="javadoc.encoding"/>
40.106 + <not>
40.107 + <equals arg1="${javadoc.encoding}" arg2=""/>
40.108 + </not>
40.109 + </and>
40.110 + </condition>
40.111 + <property name="javadoc.encoding.used" value="${source.encoding}"/>
40.112 + <property name="includes" value="**"/>
40.113 + <property name="excludes" value=""/>
40.114 + <property name="do.depend" value="false"/>
40.115 + <condition property="do.depend.true">
40.116 + <istrue value="${do.depend}"/>
40.117 + </condition>
40.118 + <condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
40.119 + <and>
40.120 + <isset property="jaxws.endorsed.dir"/>
40.121 + <available file="nbproject/jaxws-build.xml"/>
40.122 + </and>
40.123 + </condition>
40.124 + </target>
40.125 + <target name="-post-init">
40.126 + <!-- Empty placeholder for easier customization. -->
40.127 + <!-- You can override this target in the ../build.xml file. -->
40.128 + </target>
40.129 + <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
40.130 + <fail unless="src.dir">Must set src.dir</fail>
40.131 + <fail unless="test.src.dir">Must set test.src.dir</fail>
40.132 + <fail unless="build.dir">Must set build.dir</fail>
40.133 + <fail unless="dist.dir">Must set dist.dir</fail>
40.134 + <fail unless="build.classes.dir">Must set build.classes.dir</fail>
40.135 + <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
40.136 + <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
40.137 + <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
40.138 + <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
40.139 + <fail unless="dist.jar">Must set dist.jar</fail>
40.140 + </target>
40.141 + <target name="-init-macrodef-property">
40.142 + <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
40.143 + <attribute name="name"/>
40.144 + <attribute name="value"/>
40.145 + <sequential>
40.146 + <property name="@{name}" value="${@{value}}"/>
40.147 + </sequential>
40.148 + </macrodef>
40.149 + </target>
40.150 + <target name="-init-macrodef-javac">
40.151 + <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
40.152 + <attribute default="${src.dir}" name="srcdir"/>
40.153 + <attribute default="${build.classes.dir}" name="destdir"/>
40.154 + <attribute default="${javac.classpath}" name="classpath"/>
40.155 + <attribute default="${includes}" name="includes"/>
40.156 + <attribute default="${excludes}" name="excludes"/>
40.157 + <attribute default="${javac.debug}" name="debug"/>
40.158 + <attribute default="" name="sourcepath"/>
40.159 + <element name="customize" optional="true"/>
40.160 + <sequential>
40.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}">
40.162 + <classpath>
40.163 + <path path="@{classpath}"/>
40.164 + </classpath>
40.165 + <compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
40.166 + <customize/>
40.167 + </javac>
40.168 + </sequential>
40.169 + </macrodef>
40.170 + <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
40.171 + <attribute default="${src.dir}" name="srcdir"/>
40.172 + <attribute default="${build.classes.dir}" name="destdir"/>
40.173 + <attribute default="${javac.classpath}" name="classpath"/>
40.174 + <sequential>
40.175 + <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
40.176 + <classpath>
40.177 + <path path="@{classpath}"/>
40.178 + </classpath>
40.179 + </depend>
40.180 + </sequential>
40.181 + </macrodef>
40.182 + <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
40.183 + <attribute default="${build.classes.dir}" name="destdir"/>
40.184 + <sequential>
40.185 + <fail unless="javac.includes">Must set javac.includes</fail>
40.186 + <pathconvert pathsep="," property="javac.includes.binary">
40.187 + <path>
40.188 + <filelist dir="@{destdir}" files="${javac.includes}"/>
40.189 + </path>
40.190 + <globmapper from="*.java" to="*.class"/>
40.191 + </pathconvert>
40.192 + <delete>
40.193 + <files includes="${javac.includes.binary}"/>
40.194 + </delete>
40.195 + </sequential>
40.196 + </macrodef>
40.197 + </target>
40.198 + <target name="-init-macrodef-junit">
40.199 + <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
40.200 + <attribute default="${includes}" name="includes"/>
40.201 + <attribute default="${excludes}" name="excludes"/>
40.202 + <attribute default="**" name="testincludes"/>
40.203 + <sequential>
40.204 + <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
40.205 + <batchtest todir="${build.test.results.dir}">
40.206 + <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
40.207 + <filename name="@{testincludes}"/>
40.208 + </fileset>
40.209 + </batchtest>
40.210 + <classpath>
40.211 + <path path="${run.test.classpath}"/>
40.212 + </classpath>
40.213 + <syspropertyset>
40.214 + <propertyref prefix="test-sys-prop."/>
40.215 + <mapper from="test-sys-prop.*" to="*" type="glob"/>
40.216 + </syspropertyset>
40.217 + <formatter type="brief" usefile="false"/>
40.218 + <formatter type="xml"/>
40.219 + <jvmarg line="${run.jvmargs}"/>
40.220 + </junit>
40.221 + </sequential>
40.222 + </macrodef>
40.223 + </target>
40.224 + <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
40.225 + <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
40.226 + <attribute default="${main.class}" name="name"/>
40.227 + <attribute default="${debug.classpath}" name="classpath"/>
40.228 + <attribute default="" name="stopclassname"/>
40.229 + <sequential>
40.230 + <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
40.231 + <classpath>
40.232 + <path path="@{classpath}"/>
40.233 + </classpath>
40.234 + </nbjpdastart>
40.235 + </sequential>
40.236 + </macrodef>
40.237 + <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
40.238 + <attribute default="${build.classes.dir}" name="dir"/>
40.239 + <sequential>
40.240 + <nbjpdareload>
40.241 + <fileset dir="@{dir}" includes="${fix.classes}">
40.242 + <include name="${fix.includes}*.class"/>
40.243 + </fileset>
40.244 + </nbjpdareload>
40.245 + </sequential>
40.246 + </macrodef>
40.247 + </target>
40.248 + <target name="-init-debug-args">
40.249 + <property name="version-output" value="java version "${ant.java.version}"/>
40.250 + <condition property="have-jdk-older-than-1.4">
40.251 + <or>
40.252 + <contains string="${version-output}" substring="java version "1.0"/>
40.253 + <contains string="${version-output}" substring="java version "1.1"/>
40.254 + <contains string="${version-output}" substring="java version "1.2"/>
40.255 + <contains string="${version-output}" substring="java version "1.3"/>
40.256 + </or>
40.257 + </condition>
40.258 + <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
40.259 + <istrue value="${have-jdk-older-than-1.4}"/>
40.260 + </condition>
40.261 + <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
40.262 + <os family="windows"/>
40.263 + </condition>
40.264 + <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
40.265 + <isset property="debug.transport"/>
40.266 + </condition>
40.267 + </target>
40.268 + <target depends="-init-debug-args" name="-init-macrodef-debug">
40.269 + <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
40.270 + <attribute default="${main.class}" name="classname"/>
40.271 + <attribute default="${debug.classpath}" name="classpath"/>
40.272 + <element name="customize" optional="true"/>
40.273 + <sequential>
40.274 + <java classname="@{classname}" dir="${work.dir}" fork="true">
40.275 + <jvmarg line="${debug-args-line}"/>
40.276 + <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
40.277 + <jvmarg line="${run.jvmargs}"/>
40.278 + <classpath>
40.279 + <path path="@{classpath}"/>
40.280 + </classpath>
40.281 + <syspropertyset>
40.282 + <propertyref prefix="run-sys-prop."/>
40.283 + <mapper from="run-sys-prop.*" to="*" type="glob"/>
40.284 + </syspropertyset>
40.285 + <customize/>
40.286 + </java>
40.287 + </sequential>
40.288 + </macrodef>
40.289 + </target>
40.290 + <target name="-init-macrodef-java">
40.291 + <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
40.292 + <attribute default="${main.class}" name="classname"/>
40.293 + <element name="customize" optional="true"/>
40.294 + <sequential>
40.295 + <java classname="@{classname}" dir="${work.dir}" fork="true">
40.296 + <jvmarg line="${run.jvmargs}"/>
40.297 + <classpath>
40.298 + <path path="${run.classpath}"/>
40.299 + </classpath>
40.300 + <syspropertyset>
40.301 + <propertyref prefix="run-sys-prop."/>
40.302 + <mapper from="run-sys-prop.*" to="*" type="glob"/>
40.303 + </syspropertyset>
40.304 + <customize/>
40.305 + </java>
40.306 + </sequential>
40.307 + </macrodef>
40.308 + </target>
40.309 + <target name="-init-presetdef-jar">
40.310 + <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
40.311 + <jar compress="${jar.compress}" jarfile="${dist.jar}">
40.312 + <j2seproject1:fileset dir="${build.classes.dir}"/>
40.313 + </jar>
40.314 + </presetdef>
40.315 + </target>
40.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"/>
40.317 + <!--
40.318 + ===================
40.319 + COMPILATION SECTION
40.320 + ===================
40.321 + -->
40.322 + <target depends="init" name="deps-jar" unless="no.deps"/>
40.323 + <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
40.324 + <target depends="init" name="-check-automatic-build">
40.325 + <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
40.326 + </target>
40.327 + <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
40.328 + <antcall target="clean"/>
40.329 + </target>
40.330 + <target depends="init,deps-jar" name="-pre-pre-compile">
40.331 + <mkdir dir="${build.classes.dir}"/>
40.332 + </target>
40.333 + <target name="-pre-compile">
40.334 + <!-- Empty placeholder for easier customization. -->
40.335 + <!-- You can override this target in the ../build.xml file. -->
40.336 + </target>
40.337 + <target if="do.depend.true" name="-compile-depend">
40.338 + <j2seproject3:depend/>
40.339 + </target>
40.340 + <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
40.341 + <j2seproject3:javac/>
40.342 + <copy todir="${build.classes.dir}">
40.343 + <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
40.344 + </copy>
40.345 + </target>
40.346 + <target name="-post-compile">
40.347 + <!-- Empty placeholder for easier customization. -->
40.348 + <!-- You can override this target in the ../build.xml file. -->
40.349 + </target>
40.350 + <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
40.351 + <target name="-pre-compile-single">
40.352 + <!-- Empty placeholder for easier customization. -->
40.353 + <!-- You can override this target in the ../build.xml file. -->
40.354 + </target>
40.355 + <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
40.356 + <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
40.357 + <j2seproject3:force-recompile/>
40.358 + <j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
40.359 + </target>
40.360 + <target name="-post-compile-single">
40.361 + <!-- Empty placeholder for easier customization. -->
40.362 + <!-- You can override this target in the ../build.xml file. -->
40.363 + </target>
40.364 + <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
40.365 + <!--
40.366 + ====================
40.367 + JAR BUILDING SECTION
40.368 + ====================
40.369 + -->
40.370 + <target depends="init" name="-pre-pre-jar">
40.371 + <dirname file="${dist.jar}" property="dist.jar.dir"/>
40.372 + <mkdir dir="${dist.jar.dir}"/>
40.373 + </target>
40.374 + <target name="-pre-jar">
40.375 + <!-- Empty placeholder for easier customization. -->
40.376 + <!-- You can override this target in the ../build.xml file. -->
40.377 + </target>
40.378 + <target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
40.379 + <j2seproject1:jar/>
40.380 + </target>
40.381 + <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
40.382 + <j2seproject1:jar manifest="${manifest.file}"/>
40.383 + </target>
40.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">
40.385 + <j2seproject1:jar manifest="${manifest.file}">
40.386 + <j2seproject1:manifest>
40.387 + <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
40.388 + </j2seproject1:manifest>
40.389 + </j2seproject1:jar>
40.390 + <echo>To run this application from the command line without Ant, try:</echo>
40.391 + <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
40.392 + <property location="${dist.jar}" name="dist.jar.resolved"/>
40.393 + <pathconvert property="run.classpath.with.dist.jar">
40.394 + <path path="${run.classpath}"/>
40.395 + <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
40.396 + </pathconvert>
40.397 + <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
40.398 + </target>
40.399 + <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
40.400 + <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
40.401 + <pathconvert property="run.classpath.without.build.classes.dir">
40.402 + <path path="${run.classpath}"/>
40.403 + <map from="${build.classes.dir.resolved}" to=""/>
40.404 + </pathconvert>
40.405 + <pathconvert pathsep=" " property="jar.classpath">
40.406 + <path path="${run.classpath.without.build.classes.dir}"/>
40.407 + <chainedmapper>
40.408 + <flattenmapper/>
40.409 + <globmapper from="*" to="lib/*"/>
40.410 + </chainedmapper>
40.411 + </pathconvert>
40.412 + <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
40.413 + <copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
40.414 + <fileset dir="${build.classes.dir}"/>
40.415 + <manifest>
40.416 + <attribute name="Main-Class" value="${main.class}"/>
40.417 + <attribute name="Class-Path" value="${jar.classpath}"/>
40.418 + </manifest>
40.419 + </copylibs>
40.420 + <echo>To run this application from the command line without Ant, try:</echo>
40.421 + <property location="${dist.jar}" name="dist.jar.resolved"/>
40.422 + <echo>java -jar "${dist.jar.resolved}"</echo>
40.423 + </target>
40.424 + <target name="-post-jar">
40.425 + <!-- Empty placeholder for easier customization. -->
40.426 + <!-- You can override this target in the ../build.xml file. -->
40.427 + </target>
40.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"/>
40.429 + <!--
40.430 + =================
40.431 + EXECUTION SECTION
40.432 + =================
40.433 + -->
40.434 + <target depends="init,compile" description="Run a main class." name="run">
40.435 + <j2seproject1:java>
40.436 + <customize>
40.437 + <arg line="${application.args}"/>
40.438 + </customize>
40.439 + </j2seproject1:java>
40.440 + </target>
40.441 + <target name="-do-not-recompile">
40.442 + <property name="javac.includes.binary" value=""/>
40.443 + </target>
40.444 + <target depends="init,-do-not-recompile,compile-single" name="run-single">
40.445 + <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
40.446 + <j2seproject1:java classname="${run.class}"/>
40.447 + </target>
40.448 + <!--
40.449 + =================
40.450 + DEBUGGING SECTION
40.451 + =================
40.452 + -->
40.453 + <target depends="init" if="netbeans.home" name="-debug-start-debugger">
40.454 + <j2seproject1:nbjpdastart name="${debug.class}"/>
40.455 + </target>
40.456 + <target depends="init,compile" name="-debug-start-debuggee">
40.457 + <j2seproject3:debug>
40.458 + <customize>
40.459 + <arg line="${application.args}"/>
40.460 + </customize>
40.461 + </j2seproject3:debug>
40.462 + </target>
40.463 + <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
40.464 + <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
40.465 + <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
40.466 + </target>
40.467 + <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
40.468 + <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
40.469 + <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
40.470 + <j2seproject3:debug classname="${debug.class}"/>
40.471 + </target>
40.472 + <target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
40.473 + <target depends="init" name="-pre-debug-fix">
40.474 + <fail unless="fix.includes">Must set fix.includes</fail>
40.475 + <property name="javac.includes" value="${fix.includes}.java"/>
40.476 + </target>
40.477 + <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
40.478 + <j2seproject1:nbjpdareload/>
40.479 + </target>
40.480 + <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
40.481 + <!--
40.482 + ===============
40.483 + JAVADOC SECTION
40.484 + ===============
40.485 + -->
40.486 + <target depends="init" name="-javadoc-build">
40.487 + <mkdir dir="${dist.javadoc.dir}"/>
40.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}">
40.489 + <classpath>
40.490 + <path path="${javac.classpath}"/>
40.491 + </classpath>
40.492 + <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
40.493 + <filename name="**/*.java"/>
40.494 + </fileset>
40.495 + </javadoc>
40.496 + </target>
40.497 + <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
40.498 + <nbbrowse file="${dist.javadoc.dir}/index.html"/>
40.499 + </target>
40.500 + <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
40.501 + <!--
40.502 + =========================
40.503 + JUNIT COMPILATION SECTION
40.504 + =========================
40.505 + -->
40.506 + <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
40.507 + <mkdir dir="${build.test.classes.dir}"/>
40.508 + </target>
40.509 + <target name="-pre-compile-test">
40.510 + <!-- Empty placeholder for easier customization. -->
40.511 + <!-- You can override this target in the ../build.xml file. -->
40.512 + </target>
40.513 + <target if="do.depend.true" name="-compile-test-depend">
40.514 + <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
40.515 + </target>
40.516 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
40.517 + <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
40.518 + <copy todir="${build.test.classes.dir}">
40.519 + <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
40.520 + </copy>
40.521 + </target>
40.522 + <target name="-post-compile-test">
40.523 + <!-- Empty placeholder for easier customization. -->
40.524 + <!-- You can override this target in the ../build.xml file. -->
40.525 + </target>
40.526 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
40.527 + <target name="-pre-compile-test-single">
40.528 + <!-- Empty placeholder for easier customization. -->
40.529 + <!-- You can override this target in the ../build.xml file. -->
40.530 + </target>
40.531 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
40.532 + <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
40.533 + <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
40.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}"/>
40.535 + <copy todir="${build.test.classes.dir}">
40.536 + <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
40.537 + </copy>
40.538 + </target>
40.539 + <target name="-post-compile-test-single">
40.540 + <!-- Empty placeholder for easier customization. -->
40.541 + <!-- You can override this target in the ../build.xml file. -->
40.542 + </target>
40.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"/>
40.544 + <!--
40.545 + =======================
40.546 + JUNIT EXECUTION SECTION
40.547 + =======================
40.548 + -->
40.549 + <target depends="init" if="have.tests" name="-pre-test-run">
40.550 + <mkdir dir="${build.test.results.dir}"/>
40.551 + </target>
40.552 + <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
40.553 + <j2seproject3:junit testincludes="**/*Test.java"/>
40.554 + </target>
40.555 + <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
40.556 + <fail if="tests.failed">Some tests failed; see details above.</fail>
40.557 + </target>
40.558 + <target depends="init" if="have.tests" name="test-report"/>
40.559 + <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
40.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"/>
40.561 + <target depends="init" if="have.tests" name="-pre-test-run-single">
40.562 + <mkdir dir="${build.test.results.dir}"/>
40.563 + </target>
40.564 + <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
40.565 + <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
40.566 + <j2seproject3:junit excludes="" includes="${test.includes}"/>
40.567 + </target>
40.568 + <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
40.569 + <fail if="tests.failed">Some tests failed; see details above.</fail>
40.570 + </target>
40.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"/>
40.572 + <!--
40.573 + =======================
40.574 + JUNIT DEBUGGING SECTION
40.575 + =======================
40.576 + -->
40.577 + <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
40.578 + <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
40.579 + <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
40.580 + <delete file="${test.report.file}"/>
40.581 + <mkdir dir="${build.test.results.dir}"/>
40.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}">
40.583 + <customize>
40.584 + <syspropertyset>
40.585 + <propertyref prefix="test-sys-prop."/>
40.586 + <mapper from="test-sys-prop.*" to="*" type="glob"/>
40.587 + </syspropertyset>
40.588 + <arg value="${test.class}"/>
40.589 + <arg value="showoutput=true"/>
40.590 + <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
40.591 + <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
40.592 + </customize>
40.593 + </j2seproject3:debug>
40.594 + </target>
40.595 + <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
40.596 + <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
40.597 + </target>
40.598 + <target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
40.599 + <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
40.600 + <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
40.601 + </target>
40.602 + <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
40.603 + <!--
40.604 + =========================
40.605 + APPLET EXECUTION SECTION
40.606 + =========================
40.607 + -->
40.608 + <target depends="init,compile-single" name="run-applet">
40.609 + <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
40.610 + <j2seproject1:java classname="sun.applet.AppletViewer">
40.611 + <customize>
40.612 + <arg value="${applet.url}"/>
40.613 + </customize>
40.614 + </j2seproject1:java>
40.615 + </target>
40.616 + <!--
40.617 + =========================
40.618 + APPLET DEBUGGING SECTION
40.619 + =========================
40.620 + -->
40.621 + <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
40.622 + <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
40.623 + <j2seproject3:debug classname="sun.applet.AppletViewer">
40.624 + <customize>
40.625 + <arg value="${applet.url}"/>
40.626 + </customize>
40.627 + </j2seproject3:debug>
40.628 + </target>
40.629 + <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
40.630 + <!--
40.631 + ===============
40.632 + CLEANUP SECTION
40.633 + ===============
40.634 + -->
40.635 + <target depends="init" name="deps-clean" unless="no.deps"/>
40.636 + <target depends="init" name="-do-clean">
40.637 + <delete dir="${build.dir}"/>
40.638 + <delete dir="${dist.dir}"/>
40.639 + </target>
40.640 + <target name="-post-clean">
40.641 + <!-- Empty placeholder for easier customization. -->
40.642 + <!-- You can override this target in the ../build.xml file. -->
40.643 + </target>
40.644 + <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
40.645 +</project>
41.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
41.2 +++ b/task4/solution06/nbproject/genfiles.properties Sat Oct 11 23:38:46 2008 +0200
41.3 @@ -0,0 +1,8 @@
41.4 +build.xml.data.CRC32=2ab820eb
41.5 +build.xml.script.CRC32=58a52595
41.6 +build.xml.stylesheet.CRC32=be360661
41.7 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
41.8 +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
41.9 +nbproject/build-impl.xml.data.CRC32=ff801896
41.10 +nbproject/build-impl.xml.script.CRC32=a0996c47
41.11 +nbproject/build-impl.xml.stylesheet.CRC32=e55b27f5
42.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
42.2 +++ b/task4/solution06/nbproject/project.properties Sat Oct 11 23:38:46 2008 +0200
42.3 @@ -0,0 +1,68 @@
42.4 +application.title=currency
42.5 +application.vendor=apidesign.org
42.6 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
42.7 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
42.8 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=default
42.9 +build.classes.dir=${build.dir}/classes
42.10 +build.classes.excludes=**/*.java,**/*.form
42.11 +# This directory is removed when the project is cleaned:
42.12 +build.dir=build
42.13 +build.generated.dir=${build.dir}/generated
42.14 +# Only compile against the classpath explicitly listed here:
42.15 +build.sysclasspath=ignore
42.16 +build.test.classes.dir=${build.dir}/test/classes
42.17 +build.test.results.dir=${build.dir}/test/results
42.18 +debug.classpath=\
42.19 + ${run.classpath}
42.20 +debug.test.classpath=\
42.21 + ${run.test.classpath}
42.22 +# This directory is removed when the project is cleaned:
42.23 +dist.dir=dist
42.24 +dist.jar=${dist.dir}/currency.jar
42.25 +dist.javadoc.dir=${dist.dir}/javadoc
42.26 +excludes=
42.27 +file.reference.junit-4.4.jar=../../libs/junit-4.4.jar
42.28 +file.reference.src-apifest08=..
42.29 +includes=**
42.30 +jar.compress=false
42.31 +javac.classpath=
42.32 +# Space-separated list of extra javac options
42.33 +javac.compilerargs=
42.34 +javac.deprecation=false
42.35 +javac.source=1.5
42.36 +javac.target=1.5
42.37 +javac.test.classpath=\
42.38 + ${javac.classpath}:\
42.39 + ${build.classes.dir}:\
42.40 + ${file.reference.junit-4.4.jar}
42.41 +javadoc.additionalparam=
42.42 +javadoc.author=false
42.43 +javadoc.encoding=
42.44 +javadoc.noindex=false
42.45 +javadoc.nonavbar=false
42.46 +javadoc.notree=false
42.47 +javadoc.private=false
42.48 +javadoc.splitindex=true
42.49 +javadoc.use=true
42.50 +javadoc.version=false
42.51 +javadoc.windowtitle=
42.52 +jnlp.codebase.type=local
42.53 +jnlp.codebase.url=file:/home/jarda/src/apifest08/currency/dist
42.54 +jnlp.descriptor=application
42.55 +jnlp.enabled=false
42.56 +jnlp.offline-allowed=false
42.57 +jnlp.signed=false
42.58 +meta.inf.dir=${src.dir}/META-INF
42.59 +platform.active=default_platform
42.60 +run.classpath=\
42.61 + ${javac.classpath}:\
42.62 + ${build.classes.dir}
42.63 +# Space-separated list of JVM arguments used when running the project
42.64 +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
42.65 +# or test-sys-prop.name=value to set system properties for unit tests):
42.66 +run.jvmargs=
42.67 +run.test.classpath=\
42.68 + ${javac.test.classpath}:\
42.69 + ${build.test.classes.dir}
42.70 +src.dir=src
42.71 +test.src.dir=test
43.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
43.2 +++ b/task4/solution06/nbproject/project.xml Sat Oct 11 23:38:46 2008 +0200
43.3 @@ -0,0 +1,16 @@
43.4 +<?xml version="1.0" encoding="UTF-8"?>
43.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
43.6 + <type>org.netbeans.modules.java.j2seproject</type>
43.7 + <configuration>
43.8 + <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
43.9 + <name>Currency Convertor Solution 06</name>
43.10 + <minimum-ant-version>1.6.5</minimum-ant-version>
43.11 + <source-roots>
43.12 + <root id="src.dir"/>
43.13 + </source-roots>
43.14 + <test-roots>
43.15 + <root id="test.src.dir"/>
43.16 + </test-roots>
43.17 + </data>
43.18 + </configuration>
43.19 +</project>
44.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
44.2 +++ b/task4/solution06/src/org/apidesign/apifest08/currency/Amount.java Sat Oct 11 23:38:46 2008 +0200
44.3 @@ -0,0 +1,81 @@
44.4 +package org.apidesign.apifest08.currency;
44.5 +
44.6 +import static org.apidesign.apifest08.currency.Assert.notNull;
44.7 +
44.8 +import java.math.BigDecimal;
44.9 +import java.math.RoundingMode;
44.10 +import java.util.Currency;
44.11 +
44.12 +/**
44.13 + * An amount representation. Amount is represented as composition of a value and
44.14 + * a currency.
44.15 + */
44.16 +public final class Amount {
44.17 +
44.18 + private final BigDecimal value;
44.19 + private final Currency currency;
44.20 + private final int scale;
44.21 + private final RoundingMode roundingMode;
44.22 +
44.23 + public static final RoundingMode DEFAULT_ROUNDING = RoundingMode.HALF_EVEN;
44.24 +
44.25 + public Amount(final BigDecimal value, final Currency currency) {
44.26 + notNull(value, "value");
44.27 + notNull(currency, "currency");
44.28 + this.value = value;
44.29 + this.currency = currency;
44.30 + this.scale = currency.getDefaultFractionDigits();
44.31 + this.roundingMode = DEFAULT_ROUNDING;
44.32 + }
44.33 +
44.34 + public Amount(final BigDecimal value, final Currency currency, final RoundingMode roundingMode) {
44.35 + notNull(value, "value");
44.36 + notNull(currency, "currency");
44.37 + notNull(roundingMode, "roundingMode");
44.38 +
44.39 + this.value = value;
44.40 + this.currency = currency;
44.41 + this.scale = currency.getDefaultFractionDigits();
44.42 + this.roundingMode = roundingMode;
44.43 + }
44.44 +
44.45 + public Amount(final long value, final Currency currency) {
44.46 + this(BigDecimal.valueOf(value), currency);
44.47 + }
44.48 +
44.49 + public Amount(final String value, final Currency currency) {
44.50 + this(new BigDecimal(value), currency);
44.51 + }
44.52 +
44.53 + /**
44.54 + * @return the value with scale of the associated currency and rounded by
44.55 + * the rounding mode.
44.56 + */
44.57 + public BigDecimal getValue() {
44.58 + return value.setScale(scale, roundingMode);
44.59 + }
44.60 +
44.61 + /**
44.62 + * @return the raw (no explicit scale, no explicit rounding) value
44.63 + */
44.64 + public BigDecimal getRawValue() {
44.65 + return value;
44.66 + }
44.67 +
44.68 + public Currency getCurrency() {
44.69 + return currency;
44.70 + }
44.71 +
44.72 + public int getScale() {
44.73 + return scale;
44.74 + }
44.75 +
44.76 + public RoundingMode getRoundingMode() {
44.77 + return roundingMode;
44.78 + }
44.79 +
44.80 + @Override
44.81 + public String toString() {
44.82 + return value + ",- " + currency.toString();
44.83 + }
44.84 +}
45.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
45.2 +++ b/task4/solution06/src/org/apidesign/apifest08/currency/Assert.java Sat Oct 11 23:38:46 2008 +0200
45.3 @@ -0,0 +1,11 @@
45.4 +package org.apidesign.apifest08.currency;
45.5 +
45.6 +public final class Assert {
45.7 + static void notNull(Object value, String argumentName) {
45.8 + if(value == null) {
45.9 + throw new IllegalArgumentException("The argument '" + argumentName + "' connot not be null");
45.10 + }
45.11 + }
45.12 +}
45.13 +
45.14 +
46.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
46.2 +++ b/task4/solution06/src/org/apidesign/apifest08/currency/ConversionException.java Sat Oct 11 23:38:46 2008 +0200
46.3 @@ -0,0 +1,26 @@
46.4 +package org.apidesign.apifest08.currency;
46.5 +
46.6 +/**
46.7 + * Indicates that a desired conversion cannot be performed.
46.8 + */
46.9 +public class ConversionException extends CurrencyException {
46.10 +
46.11 + private static final long serialVersionUID = 1L;
46.12 +
46.13 + public ConversionException() {
46.14 + super();
46.15 + }
46.16 +
46.17 + public ConversionException(String message, Throwable cause) {
46.18 + super(message, cause);
46.19 + }
46.20 +
46.21 + public ConversionException(String message) {
46.22 + super(message);
46.23 + }
46.24 +
46.25 + public ConversionException(Throwable cause) {
46.26 + super(cause);
46.27 + }
46.28 +
46.29 +}
47.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
47.2 +++ b/task4/solution06/src/org/apidesign/apifest08/currency/Convertor.java Sat Oct 11 23:38:46 2008 +0200
47.3 @@ -0,0 +1,176 @@
47.4 +package org.apidesign.apifest08.currency;
47.5 +
47.6 +import static org.apidesign.apifest08.currency.Assert.notNull;
47.7 +
47.8 +import java.math.BigDecimal;
47.9 +import java.math.RoundingMode;
47.10 +import java.util.ArrayList;
47.11 +import java.util.Currency;
47.12 +import java.util.List;
47.13 +
47.14 +/**
47.15 + * Currency covertor.
47.16 + */
47.17 +public final class Convertor {
47.18 +
47.19 + private List<ConvertorDelegate> convertorDelegates = new ArrayList<ConvertorDelegate>();
47.20 +
47.21 +
47.22 + /**
47.23 + * Create new instance of the converter for the given currencies and its rate.
47.24 + *
47.25 + * @param rateValue the rate between the first and the second currency
47.26 + * @param currencyFirst the first currency
47.27 + * @param currencySecond the second currency
47.28 + */
47.29 + public Convertor(BigDecimal rateValue, Currency currencyFirst, Currency currencySecond) {
47.30 + notNull(currencyFirst, "currencyFirst");
47.31 + notNull(currencySecond, "currencySecond");
47.32 + notNull(rateValue, "rateValue");
47.33 + convertorDelegates.add(new ConvertorDelegate(new StaticRateProvider(rateValue), currencyFirst, currencySecond));
47.34 + }
47.35 +
47.36 + /**
47.37 + * Create new instance of the converter for the given currencies and its rate.
47.38 + * A rate value is provided by {@link RateProvider}.
47.39 + *
47.40 + * @param rateProvider the rate provider
47.41 + * @param currencyFirst the first currency
47.42 + * @param currencySecond the second currency
47.43 + */
47.44 + public Convertor(RateProvider rateProvider, Currency currencyFirst, Currency currencySecond) {
47.45 + notNull(currencyFirst, "currencyFirst");
47.46 + notNull(currencySecond, "currencySecond");
47.47 + notNull(rateProvider, "rateProvider");
47.48 + convertorDelegates.add(new ConvertorDelegate(rateProvider, currencyFirst, currencySecond));
47.49 + }
47.50 +
47.51 + /**
47.52 + * Create new instance of the convertor from the given convertors.
47.53 + * @param convertors the convertors
47.54 + */
47.55 + public Convertor(Convertor... convertors) {
47.56 + notNull(convertors, "convertors");
47.57 + if(convertors.length == 0) {
47.58 + throw new IllegalArgumentException("There must be at least one converter.");
47.59 + }
47.60 +
47.61 + for(Convertor convertor: convertors) {
47.62 + if(convertor != null) {
47.63 + convertorDelegates.addAll(convertor.convertorDelegates);
47.64 + }
47.65 + }
47.66 + }
47.67 +
47.68 + /**
47.69 + * Converts an amount value between the two currencies of this converter.
47.70 + *
47.71 + * @param amount an amount
47.72 + * @param fromCurrency an amount currency
47.73 + * @param toCurrency to a target currency
47.74 + * @return a converted amount value
47.75 + *
47.76 + * @throws ConversionException if the conversion fails
47.77 + * @throws UnsupportedConversionException if the conversion between a given currencies is not supported.
47.78 + */
47.79 + public Amount convert(BigDecimal amount, Currency fromCurrency, Currency toCurrency) throws ConversionException {
47.80 + notNull(amount, "amount");
47.81 + notNull(fromCurrency, "fromCurrency");
47.82 + notNull(toCurrency, "toCurrency");
47.83 + ConvertorDelegate appropriateDelegate = null;
47.84 +
47.85 + //try find an appropriate delegate for conversion
47.86 + for(ConvertorDelegate delegate : convertorDelegates) {
47.87 + if(delegate.isConversionSupported(fromCurrency, toCurrency)) {
47.88 + appropriateDelegate = delegate;
47.89 + break;
47.90 + }
47.91 + }
47.92 +
47.93 + if(appropriateDelegate == null) {
47.94 + throw new UnsupportedConversionException(fromCurrency, toCurrency);
47.95 + }
47.96 +
47.97 + return appropriateDelegate.convert(amount, fromCurrency, toCurrency);
47.98 + }
47.99 +
47.100 + /**
47.101 + * Internal delegate implements a logic for conversion between two currencies
47.102 + * and vice versa.
47.103 + * @see #isConversionSupported(Currency, Currency)
47.104 + */
47.105 + private static class ConvertorDelegate {
47.106 + private final Currency first;
47.107 + private final Currency second;
47.108 + private final RateProvider rateProvider;
47.109 + public static final BigDecimal one = new BigDecimal(1);
47.110 +
47.111 +
47.112 + private ConvertorDelegate(RateProvider rateProvider, Currency currencyFirst, Currency currencySecond) {
47.113 + this.rateProvider = rateProvider;
47.114 + this.first = currencyFirst;
47.115 + this.second = currencySecond;
47.116 + }
47.117 +
47.118 + private Amount convert(BigDecimal amount, Currency fromCurrency, Currency toCurrency) throws ConversionException {
47.119 + BigDecimal rateValue = getRateValue(fromCurrency, toCurrency);
47.120 + BigDecimal result = rateValue.multiply(amount);
47.121 + return new Amount(result, toCurrency);
47.122 + }
47.123 +
47.124 + private BigDecimal getRateValue(Currency fromCurrency, Currency toCurrency) {
47.125 +
47.126 + BigDecimal retVal;
47.127 +
47.128 + if(first == fromCurrency) {
47.129 + BigDecimal rateValue = rateProvider.getRate();
47.130 + if(rateValue == null) {
47.131 + throw new NullPointerException("Rate cannot be null!");
47.132 + }
47.133 + retVal = rateValue;
47.134 + } else {
47.135 + BigDecimal rateValue = rateProvider.getRate();
47.136 + if(rateValue == null) {
47.137 + throw new NullPointerException("Rate cannot be null!");
47.138 + }
47.139 + //reverse rate
47.140 + retVal = one.divide(rateValue, 10 ,RoundingMode.HALF_UP);
47.141 + }
47.142 +
47.143 + return retVal;
47.144 + }
47.145 +
47.146 + /**
47.147 + * @return <code>true</code> if the delegate is able to convert from the given currency
47.148 + * to the given currency and vice versa otherwise <code>false</code>.
47.149 + */
47.150 + private boolean isConversionSupported(Currency fromCurrency, Currency toCurrency) {
47.151 + return ((fromCurrency == first || fromCurrency == second) && (toCurrency == first || toCurrency == second));
47.152 + }
47.153 + }
47.154 +
47.155 + /**
47.156 + * A rate provider. This class represents a way how could be "static" convertor
47.157 + * extended in order converts according to current rate.
47.158 + */
47.159 + public static abstract class RateProvider {
47.160 +
47.161 + /**
47.162 + * @return a rate between the from currency and the to currency associated with
47.163 + * a given convertor.
47.164 + */
47.165 + public abstract BigDecimal getRate();
47.166 + }
47.167 +
47.168 + private static class StaticRateProvider extends RateProvider{
47.169 + private final BigDecimal rateValue;
47.170 +
47.171 + private StaticRateProvider(BigDecimal rateValue){
47.172 + this.rateValue = rateValue;
47.173 + }
47.174 +
47.175 + public BigDecimal getRate() {
47.176 + return this.rateValue;
47.177 + }
47.178 + }
47.179 +}
48.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
48.2 +++ b/task4/solution06/src/org/apidesign/apifest08/currency/CurrencyException.java Sat Oct 11 23:38:46 2008 +0200
48.3 @@ -0,0 +1,25 @@
48.4 +package org.apidesign.apifest08.currency;
48.5 +
48.6 +/**
48.7 + * Top level runtime exception for 'currency' API.
48.8 + */
48.9 +public class CurrencyException extends RuntimeException{
48.10 +
48.11 + private static final long serialVersionUID = 1L;
48.12 +
48.13 + public CurrencyException() {
48.14 + super();
48.15 + }
48.16 +
48.17 + public CurrencyException(String message, Throwable cause) {
48.18 + super(message, cause);
48.19 + }
48.20 +
48.21 + public CurrencyException(String message) {
48.22 + super(message);
48.23 + }
48.24 +
48.25 + public CurrencyException(Throwable cause) {
48.26 + super(cause);
48.27 + }
48.28 +}
49.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
49.2 +++ b/task4/solution06/src/org/apidesign/apifest08/currency/UnsupportedConversionException.java Sat Oct 11 23:38:46 2008 +0200
49.3 @@ -0,0 +1,27 @@
49.4 +package org.apidesign.apifest08.currency;
49.5 +
49.6 +import java.util.Currency;
49.7 +
49.8 +public final class UnsupportedConversionException extends ConversionException{
49.9 +
49.10 + private static final long serialVersionUID = 1L;
49.11 +
49.12 + private Currency from;
49.13 + private Currency to;
49.14 +
49.15 + public UnsupportedConversionException(Currency from, Currency to) {
49.16 + super("Conversion from the currency " + from + " to the currency " + to + " or vice versa in not supported.");
49.17 + this.from = from;
49.18 + this.to = to;
49.19 + }
49.20 +
49.21 + public Currency getFrom() {
49.22 + return from;
49.23 + }
49.24 +
49.25 + public Currency getTo() {
49.26 + return to;
49.27 + }
49.28 +
49.29 +
49.30 +}
50.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
50.2 +++ b/task4/solution06/test/org/apidesign/apifest08/test/Currencies.java Sat Oct 11 23:38:46 2008 +0200
50.3 @@ -0,0 +1,9 @@
50.4 +package org.apidesign.apifest08.test;
50.5 +
50.6 +import java.util.Currency;
50.7 +
50.8 +public class Currencies {
50.9 + public static final Currency CZK = Currency.getInstance("CZK");
50.10 + public static final Currency SKK = Currency.getInstance("SKK");
50.11 + public static final Currency USD = Currency.getInstance("USD");
50.12 +}
51.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
51.2 +++ b/task4/solution06/test/org/apidesign/apifest08/test/Task1Test.java Sat Oct 11 23:38:46 2008 +0200
51.3 @@ -0,0 +1,136 @@
51.4 +package org.apidesign.apifest08.test;
51.5 +
51.6 +import static org.apidesign.apifest08.test.Currencies.CZK;
51.7 +import static org.apidesign.apifest08.test.Currencies.SKK;
51.8 +import static org.apidesign.apifest08.test.Currencies.USD;
51.9 +
51.10 +import java.math.BigDecimal;
51.11 +
51.12 +import junit.framework.TestCase;
51.13 +
51.14 +import org.apidesign.apifest08.currency.Amount;
51.15 +import org.apidesign.apifest08.currency.ConversionException;
51.16 +import org.apidesign.apifest08.currency.Convertor;
51.17 +import org.apidesign.apifest08.currency.UnsupportedConversionException;
51.18 +
51.19 +/** Finish the Convertor API, and then write bodies of methods inside
51.20 + * of this class to match the given tasks. To fullfil your task, use the
51.21 + * API define in the <code>org.apidesign.apifest08.currency</code> package.
51.22 + * Do not you reflection, or other hacks as your code
51.23 + * shall run without any runtime permissions.
51.24 + */
51.25 +public class Task1Test extends TestCase {
51.26 + public Task1Test(String testName) {
51.27 + super(testName);
51.28 + }
51.29 +
51.30 + @Override
51.31 + protected void setUp() throws Exception {
51.32 + }
51.33 +
51.34 + @Override
51.35 + protected void tearDown() throws Exception {
51.36 + }
51.37 +
51.38 + /** Create convertor that understands two currencies, CZK and
51.39 + * USD. Make 1 USD == 17 CZK.
51.40 + *
51.41 + * Creation of the convertor shall not require subclassing of any class
51.42 + * or interface on the client side.
51.43 + *
51.44 + * @return prepared convertor ready for converting USD to CZK and CZK to USD
51.45 + */
51.46 + public static Convertor createCZKtoUSD() {
51.47 + return new Convertor(new BigDecimal(17), USD, CZK);
51.48 + }
51.49 +
51.50 + /** Create convertor that understands two currencies, CZK and
51.51 + * SKK. Make 100 SKK == 80 CZK.
51.52 + *
51.53 + * Creation of the convertor shall not require subclassing of any class
51.54 + * or interface on the client side.
51.55 + *
51.56 + * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
51.57 + */
51.58 + public static Convertor createSKKtoCZK() {
51.59 + return new Convertor(new BigDecimal("0.8"), SKK, CZK);
51.60 + }
51.61 +
51.62 + /** Use the convertor from <code>createCZKtoUSD</code> method and do few conversions
51.63 + * with it.
51.64 + */
51.65 + public void testCurrencyCZKUSD() throws Exception {
51.66 + Convertor c = createCZKtoUSD();
51.67 + // convert $5 to CZK using c:
51.68 + Amount result = c.convert(new BigDecimal(5), USD, CZK);
51.69 + assertEquals("Result is 85 CZK", 85, result.getValue().intValue());
51.70 +
51.71 + // convert $8 to CZK
51.72 + result = c.convert(new BigDecimal(8), USD, CZK);
51.73 + assertEquals("Result is 136 CZK", 136, result.getValue().intValue());
51.74 +
51.75 + // convert 1003CZK to USD
51.76 + result = c.convert(new BigDecimal(1003), CZK, USD);
51.77 + assertEquals("Result is 59 USD", 59, result.getValue().intValue());
51.78 + }
51.79 +
51.80 + /** Use the convertor from <code>createSKKtoCZK</code> method and do few conversions
51.81 + * with it.
51.82 + */
51.83 + public void testCurrencySKKCZK() throws Exception {
51.84 + Convertor c = createSKKtoCZK();
51.85 + // convert 16CZK using c:
51.86 + Amount result = c.convert(new BigDecimal(16), CZK, SKK);
51.87 + assertEquals("Result is 20 SKK", 20, result.getValue().intValue());
51.88 +
51.89 + // convert 500SKK to CZK
51.90 + result = c.convert(new BigDecimal(500), SKK, CZK);
51.91 + assertEquals("Result is 400 CZK", 400, result.getValue().intValue());
51.92 + }
51.93 +
51.94 +
51.95 + /**
51.96 + * Verify that the CZK to USD convertor knows nothing about SKK.
51.97 + */
51.98 + public void testCannotConvertToSKKwithCZKUSDConvertor() throws Exception {
51.99 + Convertor c = createCZKtoUSD();
51.100 + // convert $5 to SKK, the API shall say this is not possible
51.101 + try {
51.102 + c.convert(new BigDecimal(5), USD, SKK);
51.103 + fail("convert $5 to SKK, the API shall say this is not possible");
51.104 + } catch (ConversionException e) {
51.105 + //expected
51.106 + }
51.107 +
51.108 + // convert 500 SKK to CZK, the API shall say this is not possible
51.109 +
51.110 + try {
51.111 + c.convert(new BigDecimal("500"), SKK, CZK);
51.112 + fail("convert 500 SKK to CZK, the API shall say this is not possible");
51.113 + } catch (ConversionException e) {
51.114 + //expected
51.115 + }
51.116 + }
51.117 +
51.118 + /**
51.119 + * Verify that the CZK to SKK convertor knows nothing about USD.
51.120 + */
51.121 + public void testCannotConvertToSKKwithCZKSKKConvertor() throws Exception {
51.122 + Convertor c = createSKKtoCZK();
51.123 + // convert $5 to SKK, the API shall say this is not possible
51.124 + try {
51.125 + c.convert(new BigDecimal(5), USD, SKK);
51.126 + fail("convert $5 to SKK, the API shall say this is not possible");
51.127 + } catch(ConversionException e) {
51.128 + //expected
51.129 + }
51.130 +
51.131 + try {
51.132 + c.convert(new BigDecimal(500), CZK, USD);
51.133 + fail("convert 500 CZK to USD, the API shall say this is not possible");
51.134 + } catch(ConversionException e) {
51.135 + //expected
51.136 + }
51.137 + }
51.138 +}
51.139 +
52.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
52.2 +++ b/task4/solution06/test/org/apidesign/apifest08/test/Task2Test.java Sat Oct 11 23:38:46 2008 +0200
52.3 @@ -0,0 +1,117 @@
52.4 +package org.apidesign.apifest08.test;
52.5 +
52.6 +import static org.apidesign.apifest08.test.Currencies.CZK;
52.7 +import static org.apidesign.apifest08.test.Currencies.USD;
52.8 +import static org.apidesign.apifest08.test.Currencies.SKK;
52.9 +
52.10 +import java.math.BigDecimal;
52.11 +
52.12 +import junit.framework.TestCase;
52.13 +import org.apidesign.apifest08.currency.Convertor;
52.14 +import org.apidesign.apifest08.test.Task1Test;
52.15 +
52.16 +/** There are many currencies around the world and many banks manipulate
52.17 + * with more than one or two at the same time. As banks are usually the
52.18 + * best paying clients, which is true even in case of your Convertor API,
52.19 + * it is reasonable to listen to their requests.
52.20 + * <p>
52.21 + * The quest for today is to enhance your existing convertor API to hold
52.22 + * information about many currencies and allow conversions between any of them.
52.23 + * Also, as conversion rates for diferent currencies usually arise from various
52.24 + * bank departments, there is another important need. There is a need to
52.25 + * compose two convertors into one by merging all the information about
52.26 + * currencies they know about.
52.27 + */
52.28 +public class Task2Test extends TestCase {
52.29 + public Task2Test(String testName) {
52.30 + super(testName);
52.31 + }
52.32 +
52.33 + @Override
52.34 + protected void setUp() throws Exception {
52.35 + }
52.36 +
52.37 + @Override
52.38 + protected void tearDown() throws Exception {
52.39 + }
52.40 +
52.41 + // As in Task1Test, keep in mind, that there are three parts
52.42 + // of the whole system:
52.43 + // 1. there is someone who knows the current exchange rate
52.44 + // 2. there is someone who wants to do the conversion
52.45 + // 3. there is the API between 1. and 2. which allows them to communicate
52.46 + //
52.47 + // Please backward compatibly enhance your existing API to support following
52.48 + // usecases:
52.49 + //
52.50 +
52.51 + /** Create convertor that understands two currencies, CZK and
52.52 + * SKK. Make 100 SKK == 75 CZK. This is method for the group of users that
52.53 + * knows the exchange rate, and needs to use the API to create objects
52.54 + * with the exchange rate. Anyone shall be ready to call this method without
52.55 + * any other method being called previously. The API itself shall know
52.56 + * nothing about any rates, before this method is called.
52.57 + */
52.58 + public static Convertor createTripleConvertor() {
52.59 + // Rates: 1USD = 15CZK
52.60 + // Rates: 1USD = 20SKK
52.61 + // Rates: 75CZK = 100SKK
52.62 + Convertor usdCzk = new Convertor(new BigDecimal(15), USD, CZK);
52.63 + Convertor usdSkk = new Convertor(new BigDecimal(20), USD, SKK);
52.64 + Convertor skkCzk = new Convertor(new BigDecimal("0.75"), SKK, CZK);
52.65 + return new Convertor(new Convertor[]{usdCzk, usdSkk, skkCzk});
52.66 + }
52.67 +
52.68 + /** Define convertor that understands three currencies. Use it.
52.69 + */
52.70 + public void testConvertorForUSDandCZKandSKK() throws Exception {
52.71 + Convertor c = createTripleConvertor();
52.72 +
52.73 + // convert $5 to CZK using c:
52.74 + assertEquals("Result is 75 CZK", 75 ,c.convert(new BigDecimal(5), USD, CZK).getValue().intValue());
52.75 +
52.76 + // convert $5 to SKK using c:
52.77 + assertEquals("Result is 100 SKK", 100, c.convert(new BigDecimal(5), USD, SKK).getValue().intValue());
52.78 +
52.79 + // convert 200SKK to CZK using c:
52.80 + assertEquals("Result is 150 CZK", 150, c.convert(new BigDecimal(200), SKK, CZK).getValue().intValue());
52.81 +
52.82 + // convert 200SKK to USK using c:
52.83 + assertEquals("Result is 10 USD", 10, c.convert(new BigDecimal(200), SKK, USD).getValue().intValue());
52.84 + }
52.85 +
52.86 + /** Merge all currency rates of convertor 1 with convertor 2.
52.87 + * Implement this using your API, preferably this method just delegates
52.88 + * into some API method which does the actual work, without requiring
52.89 + * API clients to code anything complex.
52.90 + */
52.91 + public static Convertor merge(Convertor one, Convertor two) {
52.92 + return new Convertor(new Convertor[]{one, two});
52.93 + }
52.94 +
52.95 + /** Join the convertors from previous task, Task1Test and show that it
52.96 + * can be used to do reasonable conversions.
52.97 + */
52.98 + public void testConvertorComposition() throws Exception {
52.99 + Convertor c = merge(
52.100 + Task1Test.createCZKtoUSD(),
52.101 + Task1Test.createSKKtoCZK()
52.102 + );
52.103 +
52.104 + // convert $5 to CZK using c:
52.105 + assertEquals("Result is 85 CZK", 85, c.convert(new BigDecimal(5), USD, CZK).getValue().intValue());
52.106 +
52.107 + // convert $8 to CZK using c:
52.108 + assertEquals("Result is 136 CZK", 136, c.convert(new BigDecimal(8), USD, CZK).getValue().intValue());
52.109 +
52.110 + // convert 1003CZK to USD using c:
52.111 + assertEquals("Result is 59 USD", 59, c.convert(new BigDecimal(1003), CZK, USD).getValue().intValue());
52.112 +
52.113 + // convert 16CZK using c:
52.114 + assertEquals("Result is 20 SKK", 20, c.convert(new BigDecimal(16), CZK, SKK).getValue().intValue());
52.115 +
52.116 + // convert 500SKK to CZK using c:
52.117 + assertEquals("Result is 400 CZK", 400, c.convert(new BigDecimal(500), SKK, CZK).getValue().intValue());
52.118 +
52.119 + }
52.120 +}
53.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
53.2 +++ b/task4/solution06/test/org/apidesign/apifest08/test/Task3Test.java Sat Oct 11 23:38:46 2008 +0200
53.3 @@ -0,0 +1,111 @@
53.4 +package org.apidesign.apifest08.test;
53.5 +
53.6 +import java.math.BigDecimal;
53.7 +import java.math.RoundingMode;
53.8 +
53.9 +import junit.framework.TestCase;
53.10 +import org.apidesign.apifest08.currency.Convertor;
53.11 +import static org.apidesign.apifest08.test.Currencies.*;
53.12 +
53.13 +/** The exchange rates are not always the same. They are changing. Day by day,
53.14 + * hour by hour, minute by minute. For every bank it is important to always
53.15 + * have the actual exchange rate available in the system. That is why let's
53.16 + * create a pluggable convertor that will always have up to date value of its
53.17 + * exchange rate.
53.18 + * <p>
53.19 + * The quest for today is to allow 3rd party developer to write a convertor
53.20 + * that adjusts its exchange rate everytime it is queried. This convertor is
53.21 + * written by independent vendor, the vendor knows only your Convertor API,
53.22 + * he does not know how the whole system looks and how the convertor is supposed
53.23 + * to be used.
53.24 + */
53.25 +public class Task3Test extends TestCase {
53.26 + public Task3Test(String testName) {
53.27 + super(testName);
53.28 + }
53.29 +
53.30 + @Override
53.31 + protected void setUp() throws Exception {
53.32 + }
53.33 +
53.34 + @Override
53.35 + protected void tearDown() throws Exception {
53.36 + }
53.37 +
53.38 + // Backward compatibly enhance your existing API to support following
53.39 + // usecases:
53.40 + //
53.41 +
53.42 +
53.43 + /** Without knowing anything about the surrounding system, write an
53.44 + * implementation of convertor that will return different rates everytime
53.45 + * it is queried. Convert USD to CZK and vice versa. Start with the rate of
53.46 + * 1USD = 16CZK and adjust it in favor of CZK by 0.01 CZK with every query.
53.47 + * As soon as you reach 1USD = 15CZK adjust it by 0.01 CZK in favor of USD
53.48 + * until you reach 1USD = 16CZK
53.49 + *
53.50 + * @return new instance of "online" USD and CZK convertor starting with rate 1USD = 16CZK
53.51 + */
53.52 + public static Convertor createOnlineCZKUSDConvertor() {
53.53 + Convertor.RateProvider rateProvider = new Convertor.RateProvider() {
53.54 + private BigDecimal seed = new BigDecimal("16.01").setScale(2);
53.55 +
53.56 + @Override
53.57 + public BigDecimal getRate() {
53.58 + if(seed.equals(new BigDecimal("15").setScale(2))) {
53.59 + seed = seed.add(new BigDecimal("0.01")).setScale(2);
53.60 + } else {
53.61 + seed = seed.subtract(new BigDecimal("0.01")).setScale(2);
53.62 + }
53.63 + return seed;
53.64 + }
53.65 +
53.66 + };
53.67 +
53.68 + // initial rate: 1USD = 16CZK
53.69 + // 2nd query 1USD = 15.99CZK
53.70 + // 3rd query 1USD = 15.98CZK
53.71 + // until 1USD = 15.00CZK
53.72 + // then 1USD = 15.01CZK
53.73 + // then 1USD = 15.02CZK
53.74 + // and so on and on up to 1USD = 16CZK
53.75 + // and then another round to 15, etc.
53.76 + return new Convertor(rateProvider, USD, CZK);
53.77 + }
53.78 +
53.79 + public void testFewQueriesForOnlineConvertor() {
53.80 + Convertor c = createOnlineCZKUSDConvertor();
53.81 + doFewQueriesForOnlineConvertor(c);
53.82 + }
53.83 +
53.84 + static void doFewQueriesForOnlineConvertor(Convertor c) {
53.85 + // convert $5 to CZK using c:
53.86 + assertEquals("Result is 80 CZK",80 ,c.convert(new BigDecimal(5), USD, CZK).getValue().intValue());
53.87 +
53.88 + // convert $8 to CZK using c:
53.89 + assertEquals("Result is 127.92 CZK", 127.92d , c.convert(new BigDecimal(8), USD, CZK).getValue().doubleValue());
53.90 +
53.91 + // convert $1 to CZK using c:
53.92 + assertEquals("Result is 15.98 CZK", 15.98d, c.convert(new BigDecimal(1), USD, CZK).getValue().doubleValue());
53.93 +
53.94 + // convert 15.97CZK to USD using c:
53.95 + assertEquals("Result is 1$", 1, c.convert(new BigDecimal("15.97").setScale(2), CZK, USD).getValue().intValue());
53.96 + }
53.97 +
53.98 + /** Join the convertors and show they behave sane.
53.99 + */
53.100 + public void testOnlineConvertorComposition() throws Exception {
53.101 + Convertor c = Task2Test.merge(
53.102 + createOnlineCZKUSDConvertor(),
53.103 + Task1Test.createSKKtoCZK()
53.104 + );
53.105 +
53.106 + // convert 16CZK to SKK using c:
53.107 + assertEquals("Result is 20 SKK", 20, c.convert(new BigDecimal(16), CZK, SKK).getValue().intValue());
53.108 +
53.109 + // convert 500SKK to CZK using c:
53.110 + assertEquals("Result is 400 CZK", 400, c.convert(new BigDecimal(500), SKK, CZK).getValue().intValue());
53.111 +
53.112 + doFewQueriesForOnlineConvertor(c);
53.113 + }
53.114 +}
54.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
54.2 +++ b/task4/solution07/build.xml Sat Oct 11 23:38:46 2008 +0200
54.3 @@ -0,0 +1,69 @@
54.4 +<?xml version="1.0" encoding="UTF-8"?>
54.5 +<!-- You may freely edit this file. See commented blocks below for -->
54.6 +<!-- some examples of how to customize the build. -->
54.7 +<!-- (If you delete it and reopen the project it will be recreated.) -->
54.8 +<project name="currency" default="default" basedir=".">
54.9 + <description>Builds, tests, and runs the project.</description>
54.10 + <import file="nbproject/build-impl.xml"/>
54.11 + <!--
54.12 +
54.13 + There exist several targets which are by default empty and which can be
54.14 + used for execution of your tasks. These targets are usually executed
54.15 + before and after some main targets. They are:
54.16 +
54.17 + -pre-init: called before initialization of project properties
54.18 + -post-init: called after initialization of project properties
54.19 + -pre-compile: called before javac compilation
54.20 + -post-compile: called after javac compilation
54.21 + -pre-compile-single: called before javac compilation of single file
54.22 + -post-compile-single: called after javac compilation of single file
54.23 + -pre-compile-test: called before javac compilation of JUnit tests
54.24 + -post-compile-test: called after javac compilation of JUnit tests
54.25 + -pre-compile-test-single: called before javac compilation of single JUnit test
54.26 + -post-compile-test-single: called after javac compilation of single JUunit test
54.27 + -pre-jar: called before JAR building
54.28 + -post-jar: called after JAR building
54.29 + -post-clean: called after cleaning build products
54.30 +
54.31 + (Targets beginning with '-' are not intended to be called on their own.)
54.32 +
54.33 + Example of inserting an obfuscator after compilation could look like this:
54.34 +
54.35 + <target name="-post-compile">
54.36 + <obfuscate>
54.37 + <fileset dir="${build.classes.dir}"/>
54.38 + </obfuscate>
54.39 + </target>
54.40 +
54.41 + For list of available properties check the imported
54.42 + nbproject/build-impl.xml file.
54.43 +
54.44 +
54.45 + Another way to customize the build is by overriding existing main targets.
54.46 + The targets of interest are:
54.47 +
54.48 + -init-macrodef-javac: defines macro for javac compilation
54.49 + -init-macrodef-junit: defines macro for junit execution
54.50 + -init-macrodef-debug: defines macro for class debugging
54.51 + -init-macrodef-java: defines macro for class execution
54.52 + -do-jar-with-manifest: JAR building (if you are using a manifest)
54.53 + -do-jar-without-manifest: JAR building (if you are not using a manifest)
54.54 + run: execution of project
54.55 + -javadoc-build: Javadoc generation
54.56 + test-report: JUnit report generation
54.57 +
54.58 + An example of overriding the target for project execution could look like this:
54.59 +
54.60 + <target name="run" depends="currency-impl.jar">
54.61 + <exec dir="bin" executable="launcher.exe">
54.62 + <arg file="${dist.jar}"/>
54.63 + </exec>
54.64 + </target>
54.65 +
54.66 + Notice that the overridden target depends on the jar target and not only on
54.67 + the compile target as the regular run target does. Again, for a list of available
54.68 + properties which you can use, check the target you are overriding in the
54.69 + nbproject/build-impl.xml file.
54.70 +
54.71 + -->
54.72 +</project>
55.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
55.2 +++ b/task4/solution07/nbproject/build-impl.xml Sat Oct 11 23:38:46 2008 +0200
55.3 @@ -0,0 +1,642 @@
55.4 +<?xml version="1.0" encoding="UTF-8"?>
55.5 +<!--
55.6 +*** GENERATED FROM project.xml - DO NOT EDIT ***
55.7 +*** EDIT ../build.xml INSTEAD ***
55.8 +
55.9 +For the purpose of easier reading the script
55.10 +is divided into following sections:
55.11 +
55.12 + - initialization
55.13 + - compilation
55.14 + - jar
55.15 + - execution
55.16 + - debugging
55.17 + - javadoc
55.18 + - junit compilation
55.19 + - junit execution
55.20 + - junit debugging
55.21 + - applet
55.22 + - cleanup
55.23 +
55.24 + -->
55.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">
55.26 + <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
55.27 + <!--
55.28 + ======================
55.29 + INITIALIZATION SECTION
55.30 + ======================
55.31 + -->
55.32 + <target name="-pre-init">
55.33 + <!-- Empty placeholder for easier customization. -->
55.34 + <!-- You can override this target in the ../build.xml file. -->
55.35 + </target>
55.36 + <target depends="-pre-init" name="-init-private">
55.37 + <property file="nbproject/private/config.properties"/>
55.38 + <property file="nbproject/private/configs/${config}.properties"/>
55.39 + <property file="nbproject/private/private.properties"/>
55.40 + </target>
55.41 + <target depends="-pre-init,-init-private" name="-init-user">
55.42 + <property file="${user.properties.file}"/>
55.43 + <!-- The two properties below are usually overridden -->
55.44 + <!-- by the active platform. Just a fallback. -->
55.45 + <property name="default.javac.source" value="1.4"/>
55.46 + <property name="default.javac.target" value="1.4"/>
55.47 + </target>
55.48 + <target depends="-pre-init,-init-private,-init-user" name="-init-project">
55.49 + <property file="nbproject/configs/${config}.properties"/>
55.50 + <property file="nbproject/project.properties"/>
55.51 + </target>
55.52 + <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
55.53 + <available file="${manifest.file}" property="manifest.available"/>
55.54 + <condition property="manifest.available+main.class">
55.55 + <and>
55.56 + <isset property="manifest.available"/>
55.57 + <isset property="main.class"/>
55.58 + <not>
55.59 + <equals arg1="${main.class}" arg2="" trim="true"/>
55.60 + </not>
55.61 + </and>
55.62 + </condition>
55.63 + <condition property="manifest.available+main.class+mkdist.available">
55.64 + <and>
55.65 + <istrue value="${manifest.available+main.class}"/>
55.66 + <isset property="libs.CopyLibs.classpath"/>
55.67 + </and>
55.68 + </condition>
55.69 + <condition property="have.tests">
55.70 + <or>
55.71 + <available file="${test.src.dir}"/>
55.72 + </or>
55.73 + </condition>
55.74 + <condition property="have.sources">
55.75 + <or>
55.76 + <available file="${src.dir}"/>
55.77 + </or>
55.78 + </condition>
55.79 + <condition property="netbeans.home+have.tests">
55.80 + <and>
55.81 + <isset property="netbeans.home"/>
55.82 + <isset property="have.tests"/>
55.83 + </and>
55.84 + </condition>
55.85 + <condition property="no.javadoc.preview">
55.86 + <and>
55.87 + <isset property="javadoc.preview"/>
55.88 + <isfalse value="${javadoc.preview}"/>
55.89 + </and>
55.90 + </condition>
55.91 + <property name="run.jvmargs" value=""/>
55.92 + <property name="javac.compilerargs" value=""/>
55.93 + <property name="work.dir" value="${basedir}"/>
55.94 + <condition property="no.deps">
55.95 + <and>
55.96 + <istrue value="${no.dependencies}"/>
55.97 + </and>
55.98 + </condition>
55.99 + <property name="javac.debug" value="true"/>
55.100 + <property name="javadoc.preview" value="true"/>
55.101 + <property name="application.args" value=""/>
55.102 + <property name="source.encoding" value="${file.encoding}"/>
55.103 + <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
55.104 + <and>
55.105 + <isset property="javadoc.encoding"/>
55.106 + <not>
55.107 + <equals arg1="${javadoc.encoding}" arg2=""/>
55.108 + </not>
55.109 + </and>
55.110 + </condition>
55.111 + <property name="javadoc.encoding.used" value="${source.encoding}"/>
55.112 + <property name="includes" value="**"/>
55.113 + <property name="excludes" value=""/>
55.114 + <property name="do.depend" value="false"/>
55.115 + <condition property="do.depend.true">
55.116 + <istrue value="${do.depend}"/>
55.117 + </condition>
55.118 + <condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
55.119 + <and>
55.120 + <isset property="jaxws.endorsed.dir"/>
55.121 + <available file="nbproject/jaxws-build.xml"/>
55.122 + </and>
55.123 + </condition>
55.124 + </target>
55.125 + <target name="-post-init">
55.126 + <!-- Empty placeholder for easier customization. -->
55.127 + <!-- You can override this target in the ../build.xml file. -->
55.128 + </target>
55.129 + <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
55.130 + <fail unless="src.dir">Must set src.dir</fail>
55.131 + <fail unless="test.src.dir">Must set test.src.dir</fail>
55.132 + <fail unless="build.dir">Must set build.dir</fail>
55.133 + <fail unless="dist.dir">Must set dist.dir</fail>
55.134 + <fail unless="build.classes.dir">Must set build.classes.dir</fail>
55.135 + <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
55.136 + <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
55.137 + <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
55.138 + <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
55.139 + <fail unless="dist.jar">Must set dist.jar</fail>
55.140 + </target>
55.141 + <target name="-init-macrodef-property">
55.142 + <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
55.143 + <attribute name="name"/>
55.144 + <attribute name="value"/>
55.145 + <sequential>
55.146 + <property name="@{name}" value="${@{value}}"/>
55.147 + </sequential>
55.148 + </macrodef>
55.149 + </target>
55.150 + <target name="-init-macrodef-javac">
55.151 + <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
55.152 + <attribute default="${src.dir}" name="srcdir"/>
55.153 + <attribute default="${build.classes.dir}" name="destdir"/>
55.154 + <attribute default="${javac.classpath}" name="classpath"/>
55.155 + <attribute default="${includes}" name="includes"/>
55.156 + <attribute default="${excludes}" name="excludes"/>
55.157 + <attribute default="${javac.debug}" name="debug"/>
55.158 + <attribute default="" name="sourcepath"/>
55.159 + <element name="customize" optional="true"/>
55.160 + <sequential>
55.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}">
55.162 + <classpath>
55.163 + <path path="@{classpath}"/>
55.164 + </classpath>
55.165 + <compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
55.166 + <customize/>
55.167 + </javac>
55.168 + </sequential>
55.169 + </macrodef>
55.170 + <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
55.171 + <attribute default="${src.dir}" name="srcdir"/>
55.172 + <attribute default="${build.classes.dir}" name="destdir"/>
55.173 + <attribute default="${javac.classpath}" name="classpath"/>
55.174 + <sequential>
55.175 + <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
55.176 + <classpath>
55.177 + <path path="@{classpath}"/>
55.178 + </classpath>
55.179 + </depend>
55.180 + </sequential>
55.181 + </macrodef>
55.182 + <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
55.183 + <attribute default="${build.classes.dir}" name="destdir"/>
55.184 + <sequential>
55.185 + <fail unless="javac.includes">Must set javac.includes</fail>
55.186 + <pathconvert pathsep="," property="javac.includes.binary">
55.187 + <path>
55.188 + <filelist dir="@{destdir}" files="${javac.includes}"/>
55.189 + </path>
55.190 + <globmapper from="*.java" to="*.class"/>
55.191 + </pathconvert>
55.192 + <delete>
55.193 + <files includes="${javac.includes.binary}"/>
55.194 + </delete>
55.195 + </sequential>
55.196 + </macrodef>
55.197 + </target>
55.198 + <target name="-init-macrodef-junit">
55.199 + <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
55.200 + <attribute default="${includes}" name="includes"/>
55.201 + <attribute default="${excludes}" name="excludes"/>
55.202 + <attribute default="**" name="testincludes"/>
55.203 + <sequential>
55.204 + <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
55.205 + <batchtest todir="${build.test.results.dir}">
55.206 + <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
55.207 + <filename name="@{testincludes}"/>
55.208 + </fileset>
55.209 + </batchtest>
55.210 + <classpath>
55.211 + <path path="${run.test.classpath}"/>
55.212 + </classpath>
55.213 + <syspropertyset>
55.214 + <propertyref prefix="test-sys-prop."/>
55.215 + <mapper from="test-sys-prop.*" to="*" type="glob"/>
55.216 + </syspropertyset>
55.217 + <formatter type="brief" usefile="false"/>
55.218 + <formatter type="xml"/>
55.219 + <jvmarg line="${run.jvmargs}"/>
55.220 + </junit>
55.221 + </sequential>
55.222 + </macrodef>
55.223 + </target>
55.224 + <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
55.225 + <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
55.226 + <attribute default="${main.class}" name="name"/>
55.227 + <attribute default="${debug.classpath}" name="classpath"/>
55.228 + <attribute default="" name="stopclassname"/>
55.229 + <sequential>
55.230 + <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
55.231 + <classpath>
55.232 + <path path="@{classpath}"/>
55.233 + </classpath>
55.234 + </nbjpdastart>
55.235 + </sequential>
55.236 + </macrodef>
55.237 + <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
55.238 + <attribute default="${build.classes.dir}" name="dir"/>
55.239 + <sequential>
55.240 + <nbjpdareload>
55.241 + <fileset dir="@{dir}" includes="${fix.classes}">
55.242 + <include name="${fix.includes}*.class"/>
55.243 + </fileset>
55.244 + </nbjpdareload>
55.245 + </sequential>
55.246 + </macrodef>
55.247 + </target>
55.248 + <target name="-init-debug-args">
55.249 + <property name="version-output" value="java version "${ant.java.version}"/>
55.250 + <condition property="have-jdk-older-than-1.4">
55.251 + <or>
55.252 + <contains string="${version-output}" substring="java version "1.0"/>
55.253 + <contains string="${version-output}" substring="java version "1.1"/>
55.254 + <contains string="${version-output}" substring="java version "1.2"/>
55.255 + <contains string="${version-output}" substring="java version "1.3"/>
55.256 + </or>
55.257 + </condition>
55.258 + <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
55.259 + <istrue value="${have-jdk-older-than-1.4}"/>
55.260 + </condition>
55.261 + <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
55.262 + <os family="windows"/>
55.263 + </condition>
55.264 + <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
55.265 + <isset property="debug.transport"/>
55.266 + </condition>
55.267 + </target>
55.268 + <target depends="-init-debug-args" name="-init-macrodef-debug">
55.269 + <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
55.270 + <attribute default="${main.class}" name="classname"/>
55.271 + <attribute default="${debug.classpath}" name="classpath"/>
55.272 + <element name="customize" optional="true"/>
55.273 + <sequential>
55.274 + <java classname="@{classname}" dir="${work.dir}" fork="true">
55.275 + <jvmarg line="${debug-args-line}"/>
55.276 + <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
55.277 + <jvmarg line="${run.jvmargs}"/>
55.278 + <classpath>
55.279 + <path path="@{classpath}"/>
55.280 + </classpath>
55.281 + <syspropertyset>
55.282 + <propertyref prefix="run-sys-prop."/>
55.283 + <mapper from="run-sys-prop.*" to="*" type="glob"/>
55.284 + </syspropertyset>
55.285 + <customize/>
55.286 + </java>
55.287 + </sequential>
55.288 + </macrodef>
55.289 + </target>
55.290 + <target name="-init-macrodef-java">
55.291 + <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
55.292 + <attribute default="${main.class}" name="classname"/>
55.293 + <element name="customize" optional="true"/>
55.294 + <sequential>
55.295 + <java classname="@{classname}" dir="${work.dir}" fork="true">
55.296 + <jvmarg line="${run.jvmargs}"/>
55.297 + <classpath>
55.298 + <path path="${run.classpath}"/>
55.299 + </classpath>
55.300 + <syspropertyset>
55.301 + <propertyref prefix="run-sys-prop."/>
55.302 + <mapper from="run-sys-prop.*" to="*" type="glob"/>
55.303 + </syspropertyset>
55.304 + <customize/>
55.305 + </java>
55.306 + </sequential>
55.307 + </macrodef>
55.308 + </target>
55.309 + <target name="-init-presetdef-jar">
55.310 + <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
55.311 + <jar compress="${jar.compress}" jarfile="${dist.jar}">
55.312 + <j2seproject1:fileset dir="${build.classes.dir}"/>
55.313 + </jar>
55.314 + </presetdef>
55.315 + </target>
55.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"/>
55.317 + <!--
55.318 + ===================
55.319 + COMPILATION SECTION
55.320 + ===================
55.321 + -->
55.322 + <target depends="init" name="deps-jar" unless="no.deps"/>
55.323 + <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
55.324 + <target depends="init" name="-check-automatic-build">
55.325 + <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
55.326 + </target>
55.327 + <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
55.328 + <antcall target="clean"/>
55.329 + </target>
55.330 + <target depends="init,deps-jar" name="-pre-pre-compile">
55.331 + <mkdir dir="${build.classes.dir}"/>
55.332 + </target>
55.333 + <target name="-pre-compile">
55.334 + <!-- Empty placeholder for easier customization. -->
55.335 + <!-- You can override this target in the ../build.xml file. -->
55.336 + </target>
55.337 + <target if="do.depend.true" name="-compile-depend">
55.338 + <j2seproject3:depend/>
55.339 + </target>
55.340 + <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
55.341 + <j2seproject3:javac/>
55.342 + <copy todir="${build.classes.dir}">
55.343 + <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
55.344 + </copy>
55.345 + </target>
55.346 + <target name="-post-compile">
55.347 + <!-- Empty placeholder for easier customization. -->
55.348 + <!-- You can override this target in the ../build.xml file. -->
55.349 + </target>
55.350 + <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
55.351 + <target name="-pre-compile-single">
55.352 + <!-- Empty placeholder for easier customization. -->
55.353 + <!-- You can override this target in the ../build.xml file. -->
55.354 + </target>
55.355 + <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
55.356 + <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
55.357 + <j2seproject3:force-recompile/>
55.358 + <j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
55.359 + </target>
55.360 + <target name="-post-compile-single">
55.361 + <!-- Empty placeholder for easier customization. -->
55.362 + <!-- You can override this target in the ../build.xml file. -->
55.363 + </target>
55.364 + <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
55.365 + <!--
55.366 + ====================
55.367 + JAR BUILDING SECTION
55.368 + ====================
55.369 + -->
55.370 + <target depends="init" name="-pre-pre-jar">
55.371 + <dirname file="${dist.jar}" property="dist.jar.dir"/>
55.372 + <mkdir dir="${dist.jar.dir}"/>
55.373 + </target>
55.374 + <target name="-pre-jar">
55.375 + <!-- Empty placeholder for easier customization. -->
55.376 + <!-- You can override this target in the ../build.xml file. -->
55.377 + </target>
55.378 + <target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
55.379 + <j2seproject1:jar/>
55.380 + </target>
55.381 + <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
55.382 + <j2seproject1:jar manifest="${manifest.file}"/>
55.383 + </target>
55.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">
55.385 + <j2seproject1:jar manifest="${manifest.file}">
55.386 + <j2seproject1:manifest>
55.387 + <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
55.388 + </j2seproject1:manifest>
55.389 + </j2seproject1:jar>
55.390 + <echo>To run this application from the command line without Ant, try:</echo>
55.391 + <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
55.392 + <property location="${dist.jar}" name="dist.jar.resolved"/>
55.393 + <pathconvert property="run.classpath.with.dist.jar">
55.394 + <path path="${run.classpath}"/>
55.395 + <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
55.396 + </pathconvert>
55.397 + <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
55.398 + </target>
55.399 + <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
55.400 + <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
55.401 + <pathconvert property="run.classpath.without.build.classes.dir">
55.402 + <path path="${run.classpath}"/>
55.403 + <map from="${build.classes.dir.resolved}" to=""/>
55.404 + </pathconvert>
55.405 + <pathconvert pathsep=" " property="jar.classpath">
55.406 + <path path="${run.classpath.without.build.classes.dir}"/>
55.407 + <chainedmapper>
55.408 + <flattenmapper/>
55.409 + <globmapper from="*" to="lib/*"/>
55.410 + </chainedmapper>
55.411 + </pathconvert>
55.412 + <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
55.413 + <copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
55.414 + <fileset dir="${build.classes.dir}"/>
55.415 + <manifest>
55.416 + <attribute name="Main-Class" value="${main.class}"/>
55.417 + <attribute name="Class-Path" value="${jar.classpath}"/>
55.418 + </manifest>
55.419 + </copylibs>
55.420 + <echo>To run this application from the command line without Ant, try:</echo>
55.421 + <property location="${dist.jar}" name="dist.jar.resolved"/>
55.422 + <echo>java -jar "${dist.jar.resolved}"</echo>
55.423 + </target>
55.424 + <target name="-post-jar">
55.425 + <!-- Empty placeholder for easier customization. -->
55.426 + <!-- You can override this target in the ../build.xml file. -->
55.427 + </target>
55.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"/>
55.429 + <!--
55.430 + =================
55.431 + EXECUTION SECTION
55.432 + =================
55.433 + -->
55.434 + <target depends="init,compile" description="Run a main class." name="run">
55.435 + <j2seproject1:java>
55.436 + <customize>
55.437 + <arg line="${application.args}"/>
55.438 + </customize>
55.439 + </j2seproject1:java>
55.440 + </target>
55.441 + <target name="-do-not-recompile">
55.442 + <property name="javac.includes.binary" value=""/>
55.443 + </target>
55.444 + <target depends="init,-do-not-recompile,compile-single" name="run-single">
55.445 + <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
55.446 + <j2seproject1:java classname="${run.class}"/>
55.447 + </target>
55.448 + <!--
55.449 + =================
55.450 + DEBUGGING SECTION
55.451 + =================
55.452 + -->
55.453 + <target depends="init" if="netbeans.home" name="-debug-start-debugger">
55.454 + <j2seproject1:nbjpdastart name="${debug.class}"/>
55.455 + </target>
55.456 + <target depends="init,compile" name="-debug-start-debuggee">
55.457 + <j2seproject3:debug>
55.458 + <customize>
55.459 + <arg line="${application.args}"/>
55.460 + </customize>
55.461 + </j2seproject3:debug>
55.462 + </target>
55.463 + <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
55.464 + <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
55.465 + <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
55.466 + </target>
55.467 + <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
55.468 + <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
55.469 + <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
55.470 + <j2seproject3:debug classname="${debug.class}"/>
55.471 + </target>
55.472 + <target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
55.473 + <target depends="init" name="-pre-debug-fix">
55.474 + <fail unless="fix.includes">Must set fix.includes</fail>
55.475 + <property name="javac.includes" value="${fix.includes}.java"/>
55.476 + </target>
55.477 + <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
55.478 + <j2seproject1:nbjpdareload/>
55.479 + </target>
55.480 + <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
55.481 + <!--
55.482 + ===============
55.483 + JAVADOC SECTION
55.484 + ===============
55.485 + -->
55.486 + <target depends="init" name="-javadoc-build">
55.487 + <mkdir dir="${dist.javadoc.dir}"/>
55.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}">
55.489 + <classpath>
55.490 + <path path="${javac.classpath}"/>
55.491 + </classpath>
55.492 + <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
55.493 + <filename name="**/*.java"/>
55.494 + </fileset>
55.495 + </javadoc>
55.496 + </target>
55.497 + <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
55.498 + <nbbrowse file="${dist.javadoc.dir}/index.html"/>
55.499 + </target>
55.500 + <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
55.501 + <!--
55.502 + =========================
55.503 + JUNIT COMPILATION SECTION
55.504 + =========================
55.505 + -->
55.506 + <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
55.507 + <mkdir dir="${build.test.classes.dir}"/>
55.508 + </target>
55.509 + <target name="-pre-compile-test">
55.510 + <!-- Empty placeholder for easier customization. -->
55.511 + <!-- You can override this target in the ../build.xml file. -->
55.512 + </target>
55.513 + <target if="do.depend.true" name="-compile-test-depend">
55.514 + <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
55.515 + </target>
55.516 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
55.517 + <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
55.518 + <copy todir="${build.test.classes.dir}">
55.519 + <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
55.520 + </copy>
55.521 + </target>
55.522 + <target name="-post-compile-test">
55.523 + <!-- Empty placeholder for easier customization. -->
55.524 + <!-- You can override this target in the ../build.xml file. -->
55.525 + </target>
55.526 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
55.527 + <target name="-pre-compile-test-single">
55.528 + <!-- Empty placeholder for easier customization. -->
55.529 + <!-- You can override this target in the ../build.xml file. -->
55.530 + </target>
55.531 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
55.532 + <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
55.533 + <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
55.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}"/>
55.535 + <copy todir="${build.test.classes.dir}">
55.536 + <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
55.537 + </copy>
55.538 + </target>
55.539 + <target name="-post-compile-test-single">
55.540 + <!-- Empty placeholder for easier customization. -->
55.541 + <!-- You can override this target in the ../build.xml file. -->
55.542 + </target>
55.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"/>
55.544 + <!--
55.545 + =======================
55.546 + JUNIT EXECUTION SECTION
55.547 + =======================
55.548 + -->
55.549 + <target depends="init" if="have.tests" name="-pre-test-run">
55.550 + <mkdir dir="${build.test.results.dir}"/>
55.551 + </target>
55.552 + <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
55.553 + <j2seproject3:junit testincludes="**/*Test.java"/>
55.554 + </target>
55.555 + <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
55.556 + <fail if="tests.failed">Some tests failed; see details above.</fail>
55.557 + </target>
55.558 + <target depends="init" if="have.tests" name="test-report"/>
55.559 + <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
55.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"/>
55.561 + <target depends="init" if="have.tests" name="-pre-test-run-single">
55.562 + <mkdir dir="${build.test.results.dir}"/>
55.563 + </target>
55.564 + <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
55.565 + <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
55.566 + <j2seproject3:junit excludes="" includes="${test.includes}"/>
55.567 + </target>
55.568 + <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
55.569 + <fail if="tests.failed">Some tests failed; see details above.</fail>
55.570 + </target>
55.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"/>
55.572 + <!--
55.573 + =======================
55.574 + JUNIT DEBUGGING SECTION
55.575 + =======================
55.576 + -->
55.577 + <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
55.578 + <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
55.579 + <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
55.580 + <delete file="${test.report.file}"/>
55.581 + <mkdir dir="${build.test.results.dir}"/>
55.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}">
55.583 + <customize>
55.584 + <syspropertyset>
55.585 + <propertyref prefix="test-sys-prop."/>
55.586 + <mapper from="test-sys-prop.*" to="*" type="glob"/>
55.587 + </syspropertyset>
55.588 + <arg value="${test.class}"/>
55.589 + <arg value="showoutput=true"/>
55.590 + <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
55.591 + <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
55.592 + </customize>
55.593 + </j2seproject3:debug>
55.594 + </target>
55.595 + <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
55.596 + <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
55.597 + </target>
55.598 + <target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
55.599 + <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
55.600 + <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
55.601 + </target>
55.602 + <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
55.603 + <!--
55.604 + =========================
55.605 + APPLET EXECUTION SECTION
55.606 + =========================
55.607 + -->
55.608 + <target depends="init,compile-single" name="run-applet">
55.609 + <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
55.610 + <j2seproject1:java classname="sun.applet.AppletViewer">
55.611 + <customize>
55.612 + <arg value="${applet.url}"/>
55.613 + </customize>
55.614 + </j2seproject1:java>
55.615 + </target>
55.616 + <!--
55.617 + =========================
55.618 + APPLET DEBUGGING SECTION
55.619 + =========================
55.620 + -->
55.621 + <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
55.622 + <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
55.623 + <j2seproject3:debug classname="sun.applet.AppletViewer">
55.624 + <customize>
55.625 + <arg value="${applet.url}"/>
55.626 + </customize>
55.627 + </j2seproject3:debug>
55.628 + </target>
55.629 + <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
55.630 + <!--
55.631 + ===============
55.632 + CLEANUP SECTION
55.633 + ===============
55.634 + -->
55.635 + <target depends="init" name="deps-clean" unless="no.deps"/>
55.636 + <target depends="init" name="-do-clean">
55.637 + <delete dir="${build.dir}"/>
55.638 + <delete dir="${dist.dir}"/>
55.639 + </target>
55.640 + <target name="-post-clean">
55.641 + <!-- Empty placeholder for easier customization. -->
55.642 + <!-- You can override this target in the ../build.xml file. -->
55.643 + </target>
55.644 + <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
55.645 +</project>
56.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
56.2 +++ b/task4/solution07/nbproject/genfiles.properties Sat Oct 11 23:38:46 2008 +0200
56.3 @@ -0,0 +1,8 @@
56.4 +build.xml.data.CRC32=2ab820eb
56.5 +build.xml.script.CRC32=58a52595
56.6 +build.xml.stylesheet.CRC32=be360661
56.7 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
56.8 +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
56.9 +nbproject/build-impl.xml.data.CRC32=979fc7ba
56.10 +nbproject/build-impl.xml.script.CRC32=92452d37
56.11 +nbproject/build-impl.xml.stylesheet.CRC32=e55b27f5
57.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
57.2 +++ b/task4/solution07/nbproject/project.properties Sat Oct 11 23:38:46 2008 +0200
57.3 @@ -0,0 +1,68 @@
57.4 +application.title=currency
57.5 +application.vendor=apidesign.org
57.6 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
57.7 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
57.8 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=default
57.9 +build.classes.dir=${build.dir}/classes
57.10 +build.classes.excludes=**/*.java,**/*.form
57.11 +# This directory is removed when the project is cleaned:
57.12 +build.dir=build
57.13 +build.generated.dir=${build.dir}/generated
57.14 +# Only compile against the classpath explicitly listed here:
57.15 +build.sysclasspath=ignore
57.16 +build.test.classes.dir=${build.dir}/test/classes
57.17 +build.test.results.dir=${build.dir}/test/results
57.18 +debug.classpath=\
57.19 + ${run.classpath}
57.20 +debug.test.classpath=\
57.21 + ${run.test.classpath}
57.22 +# This directory is removed when the project is cleaned:
57.23 +dist.dir=dist
57.24 +dist.jar=${dist.dir}/currency.jar
57.25 +dist.javadoc.dir=${dist.dir}/javadoc
57.26 +excludes=
57.27 +file.reference.junit-4.4.jar=../../libs/junit-4.4.jar
57.28 +file.reference.src-apifest08=..
57.29 +includes=**
57.30 +jar.compress=false
57.31 +javac.classpath=
57.32 +# Space-separated list of extra javac options
57.33 +javac.compilerargs=
57.34 +javac.deprecation=false
57.35 +javac.source=1.5
57.36 +javac.target=1.5
57.37 +javac.test.classpath=\
57.38 + ${javac.classpath}:\
57.39 + ${build.classes.dir}:\
57.40 + ${file.reference.junit-4.4.jar}
57.41 +javadoc.additionalparam=
57.42 +javadoc.author=false
57.43 +javadoc.encoding=
57.44 +javadoc.noindex=false
57.45 +javadoc.nonavbar=false
57.46 +javadoc.notree=false
57.47 +javadoc.private=false
57.48 +javadoc.splitindex=true
57.49 +javadoc.use=true
57.50 +javadoc.version=false
57.51 +javadoc.windowtitle=
57.52 +jnlp.codebase.type=local
57.53 +jnlp.codebase.url=file:/home/jarda/src/apifest08/currency/dist
57.54 +jnlp.descriptor=application
57.55 +jnlp.enabled=false
57.56 +jnlp.offline-allowed=false
57.57 +jnlp.signed=false
57.58 +meta.inf.dir=${src.dir}/META-INF
57.59 +platform.active=default_platform
57.60 +run.classpath=\
57.61 + ${javac.classpath}:\
57.62 + ${build.classes.dir}
57.63 +# Space-separated list of JVM arguments used when running the project
57.64 +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
57.65 +# or test-sys-prop.name=value to set system properties for unit tests):
57.66 +run.jvmargs=
57.67 +run.test.classpath=\
57.68 + ${javac.test.classpath}:\
57.69 + ${build.test.classes.dir}
57.70 +src.dir=src
57.71 +test.src.dir=test
58.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
58.2 +++ b/task4/solution07/nbproject/project.xml Sat Oct 11 23:38:46 2008 +0200
58.3 @@ -0,0 +1,16 @@
58.4 +<?xml version="1.0" encoding="UTF-8"?>
58.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
58.6 + <type>org.netbeans.modules.java.j2seproject</type>
58.7 + <configuration>
58.8 + <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
58.9 + <name>Currency Convertor Solution 07</name>
58.10 + <minimum-ant-version>1.6.5</minimum-ant-version>
58.11 + <source-roots>
58.12 + <root id="src.dir"/>
58.13 + </source-roots>
58.14 + <test-roots>
58.15 + <root id="test.src.dir"/>
58.16 + </test-roots>
58.17 + </data>
58.18 + </configuration>
58.19 +</project>
59.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
59.2 +++ b/task4/solution07/src/org/apidesign/apifest08/currency/ConversionRate.java Sat Oct 11 23:38:46 2008 +0200
59.3 @@ -0,0 +1,91 @@
59.4 +package org.apidesign.apifest08.currency;
59.5 +
59.6 +import java.math.BigDecimal;
59.7 +import java.math.RoundingMode;
59.8 +
59.9 +/**
59.10 + * A rate of conversion from one currency to another.
59.11 + * @author jdvorak
59.12 + */
59.13 +public class ConversionRate {
59.14 +
59.15 + private final MonetaryAmount srcUnitAmount;
59.16 + private final MonetaryAmount tgtUnitAmount;
59.17 + private final int tgtScale;
59.18 + private final RoundingMode roundingMode;
59.19 +
59.20 + /**
59.21 + * A new conversion rate that gives tgtUnitAmount per every srcUnitAmount.
59.22 + * @param srcUnitAmount the amount of source currency
59.23 + * @param tgtUnitAmount the corresponding amount of target currency
59.24 + * @param tgtScale the scale of the target amounts
59.25 + * @param roundingMode the rounding mode to use when producing the target amounts
59.26 + */
59.27 + public ConversionRate( final MonetaryAmount srcUnitAmount, final MonetaryAmount tgtUnitAmount, final int targetScale, final RoundingMode roundingMode ) {
59.28 + this.srcUnitAmount = srcUnitAmount;
59.29 + this.tgtUnitAmount = tgtUnitAmount;
59.30 + this.tgtScale = targetScale;
59.31 + this.roundingMode = roundingMode;
59.32 + }
59.33 +
59.34 + /**
59.35 + * A new conversion rate that gives tgtUnitAmount per every srcUnitAmount, default number of fraction digits and the given rounding mode.
59.36 + * @param srcUnitAmount the amount of source currency
59.37 + * @param tgtUnitAmount the corresponding amount of target currency
59.38 + * @param roundingMode the rounding mode to use
59.39 + */
59.40 + public ConversionRate( final MonetaryAmount srcUnitAmount, final MonetaryAmount tgtUnitAmount, final RoundingMode roundingMode ) {
59.41 + this( srcUnitAmount, tgtUnitAmount, tgtUnitAmount.getCurrency().getDefaultFractionDigits(), roundingMode );
59.42 + }
59.43 +
59.44 + /**
59.45 + * A new conversion rate that gives tgtUnitAmount per every srcUnitAmount, default number of fraction digits and {@link RoundingMode#HALF_EVEN}.
59.46 + * @param srcUnitAmount the amount of source currency
59.47 + * @param tgtUnitAmount the corresponding amount of target currency
59.48 + */
59.49 + public ConversionRate( final MonetaryAmount srcUnitAmount, final MonetaryAmount tgtUnitAmount ) {
59.50 + this( srcUnitAmount, tgtUnitAmount, RoundingMode.HALF_EVEN );
59.51 + }
59.52 +
59.53 + public RoundingMode getRoundingMode() {
59.54 + return roundingMode;
59.55 + }
59.56 +
59.57 + public MonetaryAmount getSrcUnitAmount() {
59.58 + return srcUnitAmount;
59.59 + }
59.60 +
59.61 + public int getTgtScale() {
59.62 + return tgtScale;
59.63 + }
59.64 +
59.65 + public MonetaryAmount getTgtUnitAmount() {
59.66 + return tgtUnitAmount;
59.67 + }
59.68 +
59.69 + /**
59.70 + * Multiplies the given amount with the given rate.
59.71 + * @param srcAmount
59.72 + * @return
59.73 + */
59.74 + public BigDecimal convert( final BigDecimal srcAmount ) {
59.75 + return srcAmount
59.76 + .multiply( tgtUnitAmount.getAmount() )
59.77 + .divide( srcUnitAmount.getAmount(), tgtScale, roundingMode );
59.78 + }
59.79 +
59.80 + /**
59.81 + * Creates a monetary amount that corresponds to the given source amount multiplied by the rate.
59.82 + * @param srcAmount the source amount
59.83 + * @return the monetary amount in the target currency
59.84 + * @throws IllegalArgumentException if the currency of srcAmount is not equal to the source currency of this rate
59.85 + */
59.86 + public MonetaryAmount convert( final MonetaryAmount srcAmount ) {
59.87 + if ( srcUnitAmount.getCurrency().equals( srcAmount.getCurrency() ) ) {
59.88 + return new MonetaryAmount( convert( srcAmount.getAmount() ), tgtUnitAmount.getCurrency() );
59.89 + } else {
59.90 + throw new IllegalArgumentException( "This rate converts from " + srcUnitAmount.getCurrency() + ", but a conversion from " + srcAmount.getCurrency() + " is attempted" );
59.91 + }
59.92 + }
59.93 +
59.94 +}
60.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
60.2 +++ b/task4/solution07/src/org/apidesign/apifest08/currency/Convertor.java Sat Oct 11 23:38:46 2008 +0200
60.3 @@ -0,0 +1,109 @@
60.4 +package org.apidesign.apifest08.currency;
60.5 +
60.6 +import java.util.Currency;
60.7 +
60.8 +/** This is the skeleton class for your API. You need to make it public, so
60.9 + * it is accessible to your client code (currently in Task1Test.java) file.
60.10 + * <p>
60.11 + * Feel free to create additional classes or rename this one, just keep all
60.12 + * the API and its implementation in this package. Do not spread it outside
60.13 + * to other packages.
60.14 + */
60.15 +public interface Convertor {
60.16 +
60.17 + /**
60.18 + * Converts by taking a request and producing a response.
60.19 + * If a convertor finds it cannot perform the requested conversion,
60.20 + * it should return a non-null {@link ConversionResult} that has null {@link ConversionResult#getNetAmount()}.
60.21 + * A convertor must not convert to a different currency than the one specified in the request.
60.22 + * <p>
60.23 + * When the need comes to extend the semantics, one subclasses the ConversionRequest and/or ConversionResult classes.
60.24 + * <p>
60.25 + * This method can be called as many times as you like.
60.26 + * A {@link Convertor} shall be considered immutable wrt calls to {@link #convert(org.apidesign.apifest08.currency.Convertor.ConversionRequest).
60.27 + * This method of a single {@link Convertor} can be called from many threads concurrently.
60.28 + * @param req the conversion request; mustn't be null
60.29 + * @return the result of carrying out the conversion request; never null
60.30 + * @throws IllegalRequestSubtypeException when the particular implementation cannot handle a specific ConversionRequest type
60.31 + */
60.32 + public ConversionResult convert( final ConversionRequest req ) throws IllegalRequestSubtypeException;
60.33 +
60.34 + /**
60.35 + * The request for converting a monetary amout into another currency.
60.36 + * Immutable.
60.37 + */
60.38 + public class ConversionRequest {
60.39 +
60.40 + private final MonetaryAmount srcAmount;
60.41 + private final Currency tgtCurrency;
60.42 +
60.43 + /**
60.44 + * A request to convert srcAmount into tgtCurrency.
60.45 + * @param srcAmount the source amount; must not be null
60.46 + * @param tgtCurrency the currency we want it in afterwards; must not be null
60.47 + */
60.48 + public ConversionRequest( final MonetaryAmount srcAmount, final Currency tgtCurrency ) {
60.49 + this.srcAmount = srcAmount;
60.50 + this.tgtCurrency = tgtCurrency;
60.51 + if ( srcAmount == null ) {
60.52 + throw new NullPointerException( "The source amount" );
60.53 + }
60.54 + if ( tgtCurrency == null ) {
60.55 + throw new NullPointerException( "The target currency" );
60.56 + }
60.57 + if ( srcAmount.getCurrency().equals( tgtCurrency ) ) {
60.58 + throw new IllegalArgumentException( "Cannot request conversion from " + srcAmount.getCurrency() + " to " + tgtCurrency );
60.59 + }
60.60 + }
60.61 +
60.62 + /**
60.63 + * The source amount.
60.64 + */
60.65 + public MonetaryAmount getSrcAmount() {
60.66 + return srcAmount;
60.67 + }
60.68 +
60.69 + /**
60.70 + * The target currency.
60.71 + */
60.72 + public Currency getTgtCurrency() {
60.73 + return tgtCurrency;
60.74 + }
60.75 +
60.76 + }
60.77 +
60.78 + /**
60.79 + * The result of converting a monetary amount into another currency.
60.80 + * For now it records just the net amount one recieves from the conversion.
60.81 + * Immutable.
60.82 + * <p>
60.83 + * <b>Extension note:</b>
60.84 + * Other items can be added further down the road, as the need for them arises.
60.85 + * These items might provide info on other aspects of the conversion,
60.86 + * such as the fee or a reason why the conversion might not be admissible.
60.87 + */
60.88 + public class ConversionResult {
60.89 +
60.90 + private final MonetaryAmount netAmount;
60.91 +
60.92 + /**
60.93 + * A new conversion result.
60.94 + * @param netAmount the amount one recieves from the conversion;
60.95 + * null means the conversion was not admissible
60.96 + */
60.97 + public ConversionResult( final MonetaryAmount netAmount ) {
60.98 + this.netAmount = netAmount;
60.99 + }
60.100 +
60.101 + /**
60.102 + * The amount one recieves from the conversion.
60.103 + * If null, the conversion is not admissible.
60.104 + * @return the amount
60.105 + */
60.106 + public MonetaryAmount getNetAmount() {
60.107 + return netAmount;
60.108 + }
60.109 +
60.110 + }
60.111 +
60.112 +}
61.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
61.2 +++ b/task4/solution07/src/org/apidesign/apifest08/currency/DelegatingConvertor.java Sat Oct 11 23:38:46 2008 +0200
61.3 @@ -0,0 +1,28 @@
61.4 +/*
61.5 + * To change this template, choose Tools | Templates
61.6 + * and open the template in the editor.
61.7 + */
61.8 +
61.9 +package org.apidesign.apifest08.currency;
61.10 +
61.11 +/**
61.12 + *
61.13 + * @author jdvorak
61.14 + */
61.15 +public class DelegatingConvertor implements Convertor {
61.16 +
61.17 + private final Convertor underlyingConvertor;
61.18 +
61.19 + public DelegatingConvertor( final Convertor underlyingConvertor ) {
61.20 + this.underlyingConvertor = underlyingConvertor;
61.21 + }
61.22 +
61.23 + protected Convertor getUnderlyingConvertor() {
61.24 + return underlyingConvertor;
61.25 + }
61.26 +
61.27 + public ConversionResult convert( final ConversionRequest req ) {
61.28 + return underlyingConvertor.convert( req );
61.29 + }
61.30 +
61.31 +}
62.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
62.2 +++ b/task4/solution07/src/org/apidesign/apifest08/currency/IllegalRequestSubtypeException.java Sat Oct 11 23:38:46 2008 +0200
62.3 @@ -0,0 +1,30 @@
62.4 +/*
62.5 + * To change this template, choose Tools | Templates
62.6 + * and open the template in the editor.
62.7 + */
62.8 +
62.9 +package org.apidesign.apifest08.currency;
62.10 +
62.11 +/**
62.12 + * Rised when a {@link Convertor} implementation cannot handle a particular subtype of {@link Convertor.ConversionRequest}.
62.13 + * @author jdvorak
62.14 + */
62.15 +public class IllegalRequestSubtypeException extends IllegalArgumentException {
62.16 +
62.17 + public IllegalRequestSubtypeException() {
62.18 + super();
62.19 + }
62.20 +
62.21 + public IllegalRequestSubtypeException( final String msg ) {
62.22 + super( msg );
62.23 + }
62.24 +
62.25 + public IllegalRequestSubtypeException( final Throwable cause ) {
62.26 + super( cause );
62.27 + }
62.28 +
62.29 + public IllegalRequestSubtypeException( final String msg, final Throwable cause ) {
62.30 + super( msg, cause );
62.31 + }
62.32 +
62.33 +}
63.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
63.2 +++ b/task4/solution07/src/org/apidesign/apifest08/currency/MonetaryAmount.java Sat Oct 11 23:38:46 2008 +0200
63.3 @@ -0,0 +1,89 @@
63.4 +package org.apidesign.apifest08.currency;
63.5 +
63.6 +import java.math.BigDecimal;
63.7 +import java.util.Currency;
63.8 +
63.9 +/**
63.10 + * An amount of a currency.
63.11 + * Immutable.
63.12 + * @author jdvorak
63.13 + */
63.14 +public class MonetaryAmount {
63.15 +
63.16 + private final BigDecimal amount;
63.17 + private final Currency currency;
63.18 +
63.19 + /**
63.20 + * A new amount.
63.21 + * @param amount the quantity of the currency; must not be null
63.22 + * @param currency the currency; must not be null
63.23 + */
63.24 + public MonetaryAmount( final BigDecimal amount, final Currency currency ) {
63.25 + this.amount = amount;
63.26 + this.currency = currency;
63.27 + if ( amount == null ) {
63.28 + throw new NullPointerException( "The amount" );
63.29 + }
63.30 + if ( currency == null ) {
63.31 + throw new NullPointerException( "The currency" );
63.32 + }
63.33 + }
63.34 +
63.35 + /**
63.36 + * A new amount.
63.37 + * @param amount the quantity of the currency; must not be null
63.38 + * @param currency the currency; must not be null
63.39 + */
63.40 + public MonetaryAmount( final double amount, final Currency currency ) {
63.41 + this( new BigDecimal( amount ), currency );
63.42 + }
63.43 +
63.44 + /**
63.45 + * The amount.
63.46 + * @return the amount
63.47 + */
63.48 + public BigDecimal getAmount() {
63.49 + return amount;
63.50 + }
63.51 +
63.52 + /**
63.53 + * The currency.
63.54 + * @return the currency
63.55 + */
63.56 + public Currency getCurrency() {
63.57 + return currency;
63.58 + }
63.59 +
63.60 + /**
63.61 + * The string representation of the monetary amount.
63.62 + * @return the amount, a non-breakable space, the currency
63.63 + */
63.64 + @Override
63.65 + public String toString() {
63.66 + return amount.toPlainString() + "\u00a0" + currency.toString();
63.67 + }
63.68 +
63.69 + /**
63.70 + * Two monetary amounts are equal to each other iff they have equal amounts of equal currencies.
63.71 + * @param other the other object
63.72 + * @return equality
63.73 + */
63.74 + @Override
63.75 + public boolean equals( final Object other ) {
63.76 + if ( other instanceof MonetaryAmount ) {
63.77 + final MonetaryAmount otherMonetaryAmount = (MonetaryAmount) other;
63.78 + return getAmount().equals( otherMonetaryAmount.getAmount() ) && getCurrency().equals( otherMonetaryAmount.getCurrency() );
63.79 + }
63.80 + return false;
63.81 + }
63.82 +
63.83 + /**
63.84 + * The hash code combines the hash codes of the amount and of the currency.
63.85 + * @return hash code
63.86 + */
63.87 + @Override
63.88 + public int hashCode() {
63.89 + return amount.hashCode() * 37 + currency.hashCode();
63.90 + }
63.91 +
63.92 +}
64.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
64.2 +++ b/task4/solution07/src/org/apidesign/apifest08/currency/TableConvertor.java Sat Oct 11 23:38:46 2008 +0200
64.3 @@ -0,0 +1,71 @@
64.4 +package org.apidesign.apifest08.currency;
64.5 +
64.6 +import java.util.Currency;
64.7 +import java.util.HashMap;
64.8 +import java.util.Map;
64.9 +
64.10 +/**
64.11 + * A {@link Convertor} that works from a pre-set conversion table.
64.12 + * First use {@link #putIntoTable(org.apidesign.apifest08.currency.ConversionRate)} to set the conversion table.
64.13 + * Then invoke the {@link #convert(org.apidesign.apifest08.currency.Convertor.ConversionRequest)} method as many times as you wish.
64.14 + * @author jdvorak
64.15 + */
64.16 +public class TableConvertor implements Convertor {
64.17 +
64.18 + private final Map<Currency, Map<Currency, ConversionRate>> conversionTable = new HashMap<Currency, Map<Currency, ConversionRate>>();
64.19 +
64.20 + public TableConvertor() {
64.21 + }
64.22 +
64.23 + /**
64.24 + * Puts a rate into the table.
64.25 + * @param rate
64.26 + */
64.27 + public void putIntoTable( final ConversionRate rate ) {
64.28 + final Currency srcCurrency = rate.getSrcUnitAmount().getCurrency();
64.29 + final Currency tgtCurrency = rate.getTgtUnitAmount().getCurrency();
64.30 + synchronized ( conversionTable ) {
64.31 + Map<Currency, ConversionRate> targetTable = conversionTable.get( srcCurrency );
64.32 + if ( targetTable == null ) {
64.33 + targetTable = new HashMap<Currency, ConversionRate>();
64.34 + conversionTable.put( srcCurrency, targetTable );
64.35 + }
64.36 + targetTable.put( tgtCurrency, rate );
64.37 + }
64.38 + }
64.39 +
64.40 + /**
64.41 + * Carries out the conversion.
64.42 + * If the table does not contain a conversion from the source currency to the target one,
64.43 + * a {@link ConversionResult} is returned that has null netAmount.
64.44 + * This implementation works with any {@link ConversionRequest}, it won't throw {@link IllegalRequestSubtypeException}.
64.45 + * @param req the conversion request
64.46 + * @return the conversion result
64.47 + */
64.48 + public ConversionResult convert( final ConversionRequest req ) {
64.49 + final Currency srcCurrency = req.getSrcAmount().getCurrency();
64.50 + final Currency tgtCurrency = req.getTgtCurrency();
64.51 + final ConversionRate rate = findConversionRate( srcCurrency, tgtCurrency );
64.52 + if ( rate != null ) {
64.53 + final MonetaryAmount tgtAmount = rate.convert( req.getSrcAmount() );
64.54 + return new ConversionResult( tgtAmount );
64.55 + } else {
64.56 + return new ConversionResult( null ); // did not find the pair of currencies in the table
64.57 + }
64.58 + }
64.59 +
64.60 + /**
64.61 + * Looks up the conversion between the given currencies in the table.
64.62 + * @param srcCurrency the source currency
64.63 + * @param tgtCurrency the target currency
64.64 + * @return the conversion rate; null means no conversion between the currencies was found in the table
64.65 + */
64.66 + protected ConversionRate findConversionRate( final Currency srcCurrency, final Currency tgtCurrency ) {
64.67 + synchronized ( conversionTable ) {
64.68 + final Map<Currency, ConversionRate> targetTable = conversionTable.get(srcCurrency);
64.69 + final ConversionRate rate = (targetTable != null) ? targetTable.get(tgtCurrency) : null;
64.70 + return rate;
64.71 + }
64.72 + }
64.73 +
64.74 +}
65.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
65.2 +++ b/task4/solution07/src/org/apidesign/apifest08/currency/anothervendor/ZigZaggingBidirectionalConvertor.java Sat Oct 11 23:38:46 2008 +0200
65.3 @@ -0,0 +1,130 @@
65.4 +/*
65.5 + * To change this template, choose Tools | Templates
65.6 + * and open the template in the editor.
65.7 + */
65.8 +
65.9 +package org.apidesign.apifest08.currency.anothervendor;
65.10 +
65.11 +import java.math.BigDecimal;
65.12 +import java.util.Currency;
65.13 +import java.util.Iterator;
65.14 +import org.apidesign.apifest08.currency.Convertor;
65.15 +import org.apidesign.apifest08.currency.IllegalRequestSubtypeException;
65.16 +import org.apidesign.apifest08.currency.MonetaryAmount;
65.17 +
65.18 +
65.19 +/**
65.20 + * A convertor that changes the rate by a step amount on every conversion it performs.
65.21 + * @author jdvorak
65.22 + */
65.23 +public class ZigZaggingBidirectionalConvertor implements Convertor {
65.24 +
65.25 + private final MonetaryAmount srcRateAmount;
65.26 +
65.27 + private final Currency tgtCurrency;
65.28 +
65.29 + private final Iterator<BigDecimal> rateIterator;
65.30 +
65.31 + /**
65.32 + * Costructor with the precise amounts.
65.33 + * @param srcRateAmount
65.34 + * @param tgtCurrency
65.35 + * @param startAmount
65.36 + * @param endAmount
65.37 + * @param stepAmount
65.38 + */
65.39 + public ZigZaggingBidirectionalConvertor( final MonetaryAmount srcRateAmount, final Currency tgtCurrency, final BigDecimal startAmount, final BigDecimal endAmount, final BigDecimal stepAmount ) {
65.40 + this.srcRateAmount = srcRateAmount;
65.41 + this.tgtCurrency = tgtCurrency;
65.42 + this.rateIterator = new ZigZaggingBigDecimalIterator( startAmount, endAmount, stepAmount );
65.43 + }
65.44 +
65.45 + /**
65.46 + * Do the conversion; updates the rate.
65.47 + * @param req
65.48 + * @return
65.49 + * @throws org.apidesign.apifest08.currency.IllegalRequestSubtypeException
65.50 + */
65.51 + public synchronized ConversionResult convert( ConversionRequest req ) throws IllegalRequestSubtypeException {
65.52 + if ( tgtCurrency.equals( req.getTgtCurrency() ) ) {
65.53 + if ( srcRateAmount.getCurrency().equals( req.getSrcAmount().getCurrency() ) ) {
65.54 + final BigDecimal tgtRateAmount = rateIterator.next();
65.55 + final BigDecimal tgtAmount = req.getSrcAmount().getAmount().multiply( tgtRateAmount ).divide( srcRateAmount.getAmount() );
65.56 + return new ConversionResult( new MonetaryAmount( tgtAmount, tgtCurrency ) );
65.57 + }
65.58 + }
65.59 + if ( srcRateAmount.getCurrency().equals( req.getTgtCurrency() ) ) {
65.60 + if ( tgtCurrency.equals( req.getSrcAmount().getCurrency() ) ) {
65.61 + final BigDecimal tgtRateAmount = rateIterator.next();
65.62 + final BigDecimal tgtAmount = req.getSrcAmount().getAmount().multiply( srcRateAmount.getAmount() ).divide( tgtRateAmount );
65.63 + return new ConversionResult( new MonetaryAmount( tgtAmount, srcRateAmount.getCurrency() ) );
65.64 + }
65.65 + }
65.66 + return new ConversionResult( null );
65.67 + }
65.68 +
65.69 +}
65.70 +
65.71 +/**
65.72 + * An iterator that goes zig first, then zag, then zig again, then zag again, ad libitum.
65.73 + * @author jdvorak
65.74 + */
65.75 +class ZigZaggingBigDecimalIterator implements Iterator<BigDecimal> {
65.76 +
65.77 + private BigDecimal zigBounce;
65.78 +
65.79 + private BigDecimal zagBounce;
65.80 +
65.81 + private BigDecimal step;
65.82 +
65.83 + private BigDecimal currentValue;
65.84 +
65.85 + protected ZigZaggingBigDecimalIterator( final BigDecimal zagBounce, final BigDecimal zigBounce, final BigDecimal step ) {
65.86 + this. zigBounce = zigBounce;
65.87 + this.zagBounce = zagBounce;
65.88 + this.currentValue = zagBounce;
65.89 + this.step = step;
65.90 +
65.91 + if ( zigBounce == null ) {
65.92 + throw new NullPointerException( "zigAmount" );
65.93 + }
65.94 + if ( zagBounce == null ) {
65.95 + throw new NullPointerException( "zagAmount" );
65.96 + }
65.97 + if ( step == null ) {
65.98 + throw new NullPointerException( "stepAmount" );
65.99 + }
65.100 + final int stepSign = step.signum();
65.101 + if ( stepSign == 0 ) {
65.102 + throw new IllegalArgumentException( "stepAmount can't be zero" );
65.103 + }
65.104 + if ( stepSign * zigBounce.compareTo( zagBounce ) < 0 ) {
65.105 + throw new IllegalArgumentException( "stepAmount shall have the same sign as endAmount - startAmount" );
65.106 + }
65.107 + }
65.108 +
65.109 + public boolean hasNext() {
65.110 + return true;
65.111 + }
65.112 +
65.113 + public BigDecimal next() {
65.114 + final BigDecimal result = currentValue;
65.115 +
65.116 + currentValue = currentValue.add( step );
65.117 + final int stepSign = step.signum();
65.118 + final int currentMinusZigSign = currentValue.compareTo( zigBounce );
65.119 + if ( stepSign * currentMinusZigSign >= 0 ) {
65.120 + final BigDecimal temp = zigBounce;
65.121 + zigBounce = zagBounce;
65.122 + zagBounce = temp;
65.123 + step = step.negate();
65.124 + }
65.125 +
65.126 + return result;
65.127 + }
65.128 +
65.129 + public void remove() {
65.130 + throw new UnsupportedOperationException("Removal is not supported.");
65.131 + }
65.132 +
65.133 +}
65.134 \ No newline at end of file
66.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
66.2 +++ b/task4/solution07/test/org/apidesign/apifest08/test/ContractImposingDelegatingConvertor.java Sat Oct 11 23:38:46 2008 +0200
66.3 @@ -0,0 +1,53 @@
66.4 +/*
66.5 + * To change this template, choose Tools | Templates
66.6 + * and open the template in the editor.
66.7 + */
66.8 +
66.9 +package org.apidesign.apifest08.test;
66.10 +
66.11 +import java.math.BigDecimal;
66.12 +import java.util.Currency;
66.13 +import junit.framework.Assert;
66.14 +import org.apidesign.apifest08.currency.Convertor;
66.15 +import org.apidesign.apifest08.currency.DelegatingConvertor;
66.16 +import org.apidesign.apifest08.currency.MonetaryAmount;
66.17 +
66.18 +/**
66.19 + * A delegating convertor that checks preconditions and postconditions.
66.20 + * Useful for testing.
66.21 + * @author jdvorak
66.22 + */
66.23 +public class ContractImposingDelegatingConvertor extends DelegatingConvertor {
66.24 +
66.25 + public ContractImposingDelegatingConvertor( final Convertor underlyingConvertor ) {
66.26 + super( underlyingConvertor );
66.27 + }
66.28 +
66.29 + @Override
66.30 + public ConversionResult convert( final ConversionRequest req ) {
66.31 + Assert.assertNotNull( "The request", req );
66.32 + final ConversionResult result = super.convert( req );
66.33 + Assert.assertNotNull( "Result of the convert() call", result );
66.34 + final MonetaryAmount netAmount = result.getNetAmount();
66.35 + if ( netAmount != null ) {
66.36 + Assert.assertEquals( "Converted to a different currency than specified in the request", req.getTgtCurrency(), netAmount.getCurrency() );
66.37 + }
66.38 + return result;
66.39 + }
66.40 +
66.41 + /**
66.42 + * Do some tests on our own.
66.43 + * @return this
66.44 + */
66.45 + public Convertor test() {
66.46 + try {
66.47 + final Currency aCurrency = Currency.getInstance( "EUR" );
66.48 + new ConversionRequest( new MonetaryAmount( BigDecimal.ONE, aCurrency ), aCurrency );
66.49 + Assert.fail( "Should have thrown an IllegalArgumentException" );
66.50 + } catch ( final IllegalArgumentException e ) {
66.51 + Assert.assertEquals( "Cannot request conversion from EUR to EUR", e.getMessage() );
66.52 + }
66.53 + return this;
66.54 + }
66.55 +
66.56 +}
67.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
67.2 +++ b/task4/solution07/test/org/apidesign/apifest08/test/Task1Test.java Sat Oct 11 23:38:46 2008 +0200
67.3 @@ -0,0 +1,177 @@
67.4 +package org.apidesign.apifest08.test;
67.5 +
67.6 +import java.util.Currency;
67.7 +import junit.framework.TestCase;
67.8 +import org.apidesign.apifest08.currency.ConversionRate;
67.9 +import org.apidesign.apifest08.currency.Convertor;
67.10 +import org.apidesign.apifest08.currency.MonetaryAmount;
67.11 +import org.apidesign.apifest08.currency.TableConvertor;
67.12 +
67.13 +/** Finish the Convertor API, and then write bodies of methods inside
67.14 + * of this class to match the given tasks. To fullfil your task, use the
67.15 + * API define in the <code>org.apidesign.apifest08.currency</code> package.
67.16 + * Do not you reflection, or other hacks as your code
67.17 + * shall run without any runtime permissions.
67.18 + */
67.19 +public class Task1Test extends TestCase {
67.20 + public Task1Test(String testName) {
67.21 + super(testName);
67.22 + }
67.23 +
67.24 + @Override
67.25 + protected void setUp() throws Exception {
67.26 + }
67.27 +
67.28 + @Override
67.29 + protected void tearDown() throws Exception {
67.30 + }
67.31 +
67.32 + //
67.33 + // Imagine that there are three parts of the whole system:
67.34 + // 1. there is someone who knows the current exchange rate
67.35 + // 2. there is someone who wants to do the conversion
67.36 + // 3. there is the API between 1. and 2. which allows them to communicate
67.37 + // Please design such API
67.38 + //
67.39 +
67.40 + protected static final Currency CZK = Currency.getInstance( "CZK" );
67.41 + protected static final Currency SKK = Currency.getInstance( "SKK" );
67.42 + protected static final Currency USD = Currency.getInstance( "USD" );
67.43 +
67.44 + /** Create convertor that understands two currencies, CZK and
67.45 + * USD. Make 1 USD == 17 CZK.
67.46 + * USD. Make 1 USD == 17 CZK. This is a method provided for #1 group -
67.47 + * e.g. those that know the exchange rate. They somehow need to create
67.48 + * the objects from the API and tell them the exchange rate. The API itself
67.49 + * knows nothing about any rates, before the createCZKtoUSD method is called.
67.50 + *
67.51 + * Creation of the convertor shall not require subclassing of any class
67.52 + * or interface on the client side.
67.53 + *
67.54 + * @return prepared convertor ready for converting USD to CZK and CZK to USD
67.55 + */
67.56 + public static Convertor createCZKtoUSD() {
67.57 + final TableConvertor convertor = new TableConvertor();
67.58 + final MonetaryAmount amountInCZK = new MonetaryAmount( 17, CZK );
67.59 + final MonetaryAmount amountInUSD = new MonetaryAmount( 1, USD );
67.60 + convertor.putIntoTable( new ConversionRate( amountInCZK, amountInUSD ) );
67.61 + convertor.putIntoTable( new ConversionRate( amountInUSD, amountInCZK ) );
67.62 + return new ContractImposingDelegatingConvertor( convertor ).test();
67.63 + }
67.64 +
67.65 + /** Create convertor that understands two currencies, CZK and
67.66 + * SKK. Make 100 SKK == 80 CZK. Again this is method for the #1 group -
67.67 + * it knows the exchange rate, and needs to use the API to create objects
67.68 + * with the exchange rate. Anyone shall be ready to call this method without
67.69 + * any other method being called previously. The API itself shall know
67.70 + * nothing about any rates, before this method is called.
67.71 + *
67.72 + * Creation of the convertor shall not require subclassing of any class
67.73 + * or interface on the client side.
67.74 + *
67.75 + * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
67.76 + */
67.77 + public static Convertor createSKKtoCZK() {
67.78 + final TableConvertor convertor = new TableConvertor();
67.79 + final MonetaryAmount amountInSKK = new MonetaryAmount( 100, SKK );
67.80 + final MonetaryAmount amountInCZK = new MonetaryAmount( 80, CZK );
67.81 + convertor.putIntoTable( new ConversionRate( amountInSKK, amountInCZK ) );
67.82 + convertor.putIntoTable( new ConversionRate( amountInCZK, amountInSKK ) );
67.83 + return new ContractImposingDelegatingConvertor( convertor ).test();
67.84 + }
67.85 +
67.86 + //
67.87 + // now the methods for group #2 follow:
67.88 + // this group knows nothing about exchange rates, but knows how to use
67.89 + // the API to do conversions. It somehow (by calling one of the factory
67.90 + // methods) gets objects from the API and uses them to do the conversions.
67.91 + //
67.92 +
67.93 + /** Use the convertor from <code>createCZKtoUSD</code> method and do few conversions
67.94 + * with it.
67.95 + */
67.96 + public void testCurrencyCZKUSD() throws Exception {
67.97 + final Convertor c = createCZKtoUSD();
67.98 +
67.99 + // convert $5 to CZK using c:
67.100 + final Convertor.ConversionResult r1 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), CZK ) );
67.101 + final MonetaryAmount a1 = r1.getNetAmount();
67.102 + // assertEquals("Result is 85 CZK");
67.103 + assertNotNull( a1 );
67.104 + assertEquals( 85.0, a1.getAmount().doubleValue() );
67.105 + assertEquals( CZK, a1.getCurrency() );
67.106 +
67.107 + // convert $8 to CZK
67.108 + final Convertor.ConversionResult r2 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 8, USD ), CZK ) );
67.109 + final MonetaryAmount a2 = r2.getNetAmount();
67.110 + // assertEquals("Result is 136 CZK");
67.111 + assertNotNull( a2 );
67.112 + assertEquals( 136.0, a2.getAmount().doubleValue() );
67.113 + assertEquals( CZK, a2.getCurrency() );
67.114 +
67.115 + // convert 1003CZK to USD
67.116 + final Convertor.ConversionResult r3 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 1003, CZK ), USD ) );
67.117 + final MonetaryAmount a3 = r3.getNetAmount();
67.118 + // assertEquals("Result is 59 USD");
67.119 + assertNotNull( a3 );
67.120 + assertEquals( 59.0, a3.getAmount().doubleValue() );
67.121 + assertEquals( USD, a3.getCurrency() );
67.122 + }
67.123 +
67.124 + /** Use the convertor from <code>createSKKtoCZK</code> method and do few conversions
67.125 + * with it.
67.126 + */
67.127 + public void testCurrencySKKCZK() throws Exception {
67.128 + final Convertor c = createSKKtoCZK();
67.129 +
67.130 + // convert 16CZK using c:
67.131 + final Convertor.ConversionResult r1 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 16, CZK ), SKK ) );
67.132 + final MonetaryAmount a1 = r1.getNetAmount();
67.133 + // assertEquals("Result is 20 SKK");
67.134 + assertNotNull( a1 );
67.135 + assertEquals( 20.0, a1.getAmount().doubleValue() );
67.136 + assertEquals( SKK, a1.getCurrency() );
67.137 +
67.138 + // convert 500SKK to CZK
67.139 + final Convertor.ConversionResult r2 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 500, SKK ), CZK ) );
67.140 + final MonetaryAmount a2 = r2.getNetAmount();
67.141 + // assertEquals("Result is 400 CZK");
67.142 + assertNotNull( a2 );
67.143 + assertEquals( 400.0, a2.getAmount().doubleValue() );
67.144 + assertEquals( CZK, a2.getCurrency() );
67.145 + }
67.146 +
67.147 + /** Verify that the CZK to USD convertor knows nothing about SKK.
67.148 + */
67.149 + public void testCannotConvertToSKKwithCZKUSDConvertor() throws Exception {
67.150 + final Convertor c = createCZKtoUSD();
67.151 +
67.152 + // convert $5 to SKK, the API shall say this is not possible
67.153 + final Convertor.ConversionResult r1 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), SKK ) );
67.154 + final MonetaryAmount a1 = r1.getNetAmount();
67.155 + assertNull( a1 );
67.156 +
67.157 + // convert 500 SKK to CZK, the API shall say this is not possible
67.158 + final Convertor.ConversionResult r2 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, SKK ), CZK ) );
67.159 + final MonetaryAmount a2 = r2.getNetAmount();
67.160 + assertNull( a2 );
67.161 + }
67.162 +
67.163 + /** Verify that the CZK to SKK convertor knows nothing about USD.
67.164 + */
67.165 + public void testCannotConvertToUSDwithCZKSKKConvertor() throws Exception {
67.166 + final Convertor c = createSKKtoCZK();
67.167 +
67.168 + // convert $5 to SKK, the API shall say this is not possible
67.169 + final Convertor.ConversionResult r1 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), SKK ) );
67.170 + final MonetaryAmount a1 = r1.getNetAmount();
67.171 + assertNull( a1 );
67.172 +
67.173 + // convert 500 CZK to USD, the API shall say this is not possible
67.174 + final Convertor.ConversionResult r2 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, CZK ), USD ) );
67.175 + final MonetaryAmount a2 = r2.getNetAmount();
67.176 + assertNull( a2 );
67.177 + }
67.178 +
67.179 +}
67.180 +
68.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
68.2 +++ b/task4/solution07/test/org/apidesign/apifest08/test/Task2Test.java Sat Oct 11 23:38:46 2008 +0200
68.3 @@ -0,0 +1,192 @@
68.4 +package org.apidesign.apifest08.test;
68.5 +
68.6 +import java.util.Currency;
68.7 +import junit.framework.TestCase;
68.8 +import org.apidesign.apifest08.currency.ConversionRate;
68.9 +import org.apidesign.apifest08.currency.Convertor;
68.10 +import org.apidesign.apifest08.currency.IllegalRequestSubtypeException;
68.11 +import org.apidesign.apifest08.currency.MonetaryAmount;
68.12 +import org.apidesign.apifest08.currency.TableConvertor;
68.13 +
68.14 +/** There are many currencies around the world and many banks manipulate
68.15 + * with more than one or two at the same time. As banks are usually the
68.16 + * best paying clients, which is true even in case of your Convertor API,
68.17 + * it is reasonable to listen to their requests.
68.18 + * <p>
68.19 + * The quest for today is to enhance your existing convertor API to hold
68.20 + * information about many currencies and allow conversions between any of them.
68.21 + * Also, as conversion rates for diferent currencies usually arise from various
68.22 + * bank departments, there is another important need. There is a need to
68.23 + * compose two convertors into one by merging all the information about
68.24 + * currencies they know about.
68.25 + */
68.26 +public class Task2Test extends TestCase {
68.27 + public Task2Test(String testName) {
68.28 + super(testName);
68.29 + }
68.30 +
68.31 + @Override
68.32 + protected void setUp() throws Exception {
68.33 + }
68.34 +
68.35 + @Override
68.36 + protected void tearDown() throws Exception {
68.37 + }
68.38 +
68.39 + protected static final Currency CZK = Currency.getInstance( "CZK" );
68.40 + protected static final Currency SKK = Currency.getInstance( "SKK" );
68.41 + protected static final Currency USD = Currency.getInstance( "USD" );
68.42 +
68.43 + // As in Task1Test, keep in mind, that there are three parts
68.44 + // of the whole system:
68.45 + // 1. there is someone who knows the current exchange rate
68.46 + // 2. there is someone who wants to do the conversion
68.47 + // 3. there is the API between 1. and 2. which allows them to communicate
68.48 + //
68.49 + // Please backward compatibly enhance your existing API to support following
68.50 + // usecases:
68.51 + //
68.52 +
68.53 + /** Create convertor that understands two currencies, CZK and
68.54 + * SKK. Make 100 SKK == 75 CZK. This is method for the group of users that
68.55 + * knows the exchange rate, and needs to use the API to create objects
68.56 + * with the exchange rate. Anyone shall be ready to call this method without
68.57 + * any other method being called previously. The API itself shall know
68.58 + * nothing about any rates, before this method is called.
68.59 + */
68.60 + public static Convertor createTripleConvertor() {
68.61 + // Rates: 1USD = 15CZK
68.62 + // Rates: 1USD = 20SKK
68.63 + // Rates: 75CZK = 100SKK
68.64 + final TableConvertor convertor = new TableConvertor();
68.65 + final MonetaryAmount amountInUSD = new MonetaryAmount( 1, USD );
68.66 + final MonetaryAmount amountInCZK = new MonetaryAmount( 15, CZK );
68.67 + final MonetaryAmount amountInSKK = new MonetaryAmount( 20, SKK );
68.68 + convertor.putIntoTable( new ConversionRate( amountInCZK, amountInUSD ) );
68.69 + convertor.putIntoTable( new ConversionRate( amountInUSD, amountInCZK ) );
68.70 + convertor.putIntoTable( new ConversionRate( amountInSKK, amountInUSD ) );
68.71 + convertor.putIntoTable( new ConversionRate( amountInUSD, amountInSKK ) );
68.72 + convertor.putIntoTable( new ConversionRate( amountInSKK, amountInCZK ) );
68.73 + convertor.putIntoTable( new ConversionRate( amountInCZK, amountInSKK ) );
68.74 + return new ContractImposingDelegatingConvertor( convertor ).test();
68.75 + }
68.76 +
68.77 + /** Define convertor that understands three currencies. Use it.
68.78 + */
68.79 + public void testConvertorForUSDandCZKandSKK() throws Exception {
68.80 + final Convertor c = createTripleConvertor();
68.81 +
68.82 + // convert $5 to CZK using c:
68.83 + final Convertor.ConversionResult r1 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), CZK ) );
68.84 + final MonetaryAmount a1 = r1.getNetAmount();
68.85 + // assertEquals("Result is 75 CZK");
68.86 + assertNotNull( a1 );
68.87 + assertEquals( 75.0, a1.getAmount().doubleValue() );
68.88 + assertEquals( CZK, a1.getCurrency() );
68.89 +
68.90 + // convert $5 to SKK using c:
68.91 + final Convertor.ConversionResult r2 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), SKK ) );
68.92 + final MonetaryAmount a2 = r2.getNetAmount();
68.93 + // assertEquals("Result is 100 SKK");
68.94 + assertNotNull( a2 );
68.95 + assertEquals( 100.0, a2.getAmount().doubleValue() );
68.96 + assertEquals( SKK, a2.getCurrency() );
68.97 +
68.98 + // convert 200SKK to CZK using c:
68.99 + final Convertor.ConversionResult r3 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 200, SKK ), CZK ) );
68.100 + final MonetaryAmount a3 = r3.getNetAmount();
68.101 + // assertEquals("Result is 150 CZK");
68.102 + assertNotNull( a3 );
68.103 + assertEquals( 150.0, a3.getAmount().doubleValue() );
68.104 + assertEquals( CZK, a3.getCurrency() );
68.105 +
68.106 + // convert 200SKK to USK using c:
68.107 + final Convertor.ConversionResult r4 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 200, SKK ), USD ) );
68.108 + final MonetaryAmount a4 = r4.getNetAmount();
68.109 + // assertEquals("Result is 10 USD");
68.110 + assertNotNull( a4 );
68.111 + assertEquals( 10.0, a4.getAmount().doubleValue() );
68.112 + assertEquals( USD, a4.getCurrency() );
68.113 + }
68.114 +
68.115 + /** Merge all currency rates of convertor 1 with convertor 2.
68.116 + * Implement this using your API, preferably this method just delegates
68.117 + * into some API method which does the actual work, without requiring
68.118 + * API clients to code anything complex.
68.119 + */
68.120 + public static Convertor merge( final Convertor one, final Convertor two ) {
68.121 + return new Convertor() {
68.122 +
68.123 + public ConversionResult convert( ConversionRequest req ) throws IllegalRequestSubtypeException {
68.124 + final ConversionResult res1 = one.convert( req );
68.125 + final ConversionResult res2 = two.convert( req );
68.126 + if ( res1.getNetAmount() != null ) {
68.127 + if ( res2.getNetAmount() != null ) {
68.128 + // TODO check if they arrive at the same thing
68.129 + return res1;
68.130 + } else {
68.131 + return res1;
68.132 + }
68.133 + } else {
68.134 + if ( res2.getNetAmount() != null ) {
68.135 + return res2;
68.136 + } else {
68.137 + // neither converts
68.138 + return new ConversionResult( null );
68.139 + }
68.140 + }
68.141 + }
68.142 +
68.143 + };
68.144 + }
68.145 +
68.146 + /** Join the convertors from previous task, Task1Test and show that it
68.147 + * can be used to do reasonable conversions.
68.148 + */
68.149 + public void testConvertorComposition() throws Exception {
68.150 + final Convertor c = merge(
68.151 + Task1Test.createCZKtoUSD(),
68.152 + Task1Test.createSKKtoCZK()
68.153 + );
68.154 +
68.155 + // convert $5 to CZK using c:
68.156 + final Convertor.ConversionResult r1 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), CZK ) );
68.157 + final MonetaryAmount a1 = r1.getNetAmount();
68.158 + // assertEquals("Result is 85 CZK");
68.159 + assertNotNull( a1 );
68.160 + assertEquals( 85.0, a1.getAmount().doubleValue() );
68.161 + assertEquals( CZK, a1.getCurrency() );
68.162 +
68.163 + // convert $8 to CZK
68.164 + final Convertor.ConversionResult r2 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 8, USD ), CZK ) );
68.165 + final MonetaryAmount a2 = r2.getNetAmount();
68.166 + // assertEquals("Result is 136 CZK");
68.167 + assertNotNull( a2 );
68.168 + assertEquals( 136.0, a2.getAmount().doubleValue() );
68.169 + assertEquals( CZK, a2.getCurrency() );
68.170 +
68.171 + // convert 1003CZK to USD
68.172 + final Convertor.ConversionResult r3 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 1003, CZK ), USD ) );
68.173 + final MonetaryAmount a3 = r3.getNetAmount();
68.174 + // assertEquals("Result is 59 USD");
68.175 + assertNotNull( a3 );
68.176 + assertEquals( 59.0, a3.getAmount().doubleValue() );
68.177 + assertEquals( USD, a3.getCurrency() );
68.178 +
68.179 + // convert 16CZK using c:
68.180 + final Convertor.ConversionResult r4 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 16, CZK ), SKK ) );
68.181 + final MonetaryAmount a4 = r4.getNetAmount();
68.182 + // assertEquals("Result is 20 SKK");
68.183 + assertNotNull( a4 );
68.184 + assertEquals( 20.0, a4.getAmount().doubleValue() );
68.185 + assertEquals( SKK, a4.getCurrency() );
68.186 +
68.187 + // convert 500SKK to CZK using c:
68.188 + final Convertor.ConversionResult r5 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 500, SKK ), CZK ) );
68.189 + final MonetaryAmount a5 = r5.getNetAmount();
68.190 + // assertEquals("Result is 400 CZK");
68.191 + assertNotNull( a5 );
68.192 + assertEquals( 400.0, a5.getAmount().doubleValue() );
68.193 + assertEquals( CZK, a5.getCurrency() );
68.194 + }
68.195 +}
69.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
69.2 +++ b/task4/solution07/test/org/apidesign/apifest08/test/Task3Test.java Sat Oct 11 23:38:46 2008 +0200
69.3 @@ -0,0 +1,135 @@
69.4 +package org.apidesign.apifest08.test;
69.5 +
69.6 +import java.math.BigDecimal;
69.7 +import java.util.Currency;
69.8 +import junit.framework.TestCase;
69.9 +import org.apidesign.apifest08.currency.Convertor;
69.10 +import org.apidesign.apifest08.currency.MonetaryAmount;
69.11 +import org.apidesign.apifest08.currency.anothervendor.ZigZaggingBidirectionalConvertor;
69.12 +
69.13 +/** The exchange rates are not always the same. They are changing. Day by day,
69.14 + * hour by hour, minute by minute. For every bank it is important to always
69.15 + * have the actual exchange rate available in the system. That is why let's
69.16 + * create a pluggable convertor that will always have up to date value of its
69.17 + * exchange rate.
69.18 + * <p>
69.19 + * The quest for today is to allow 3rd party developer to write a convertor
69.20 + * that adjusts its exchange rate everytime it is queried. This convertor is
69.21 + * written by independent vendor, the vendor knows only your Convertor API,
69.22 + * he does not know how the whole system looks and how the convertor is supposed
69.23 + * to be used.
69.24 + */
69.25 +public class Task3Test extends TestCase {
69.26 + public Task3Test(String testName) {
69.27 + super(testName);
69.28 + }
69.29 +
69.30 + @Override
69.31 + protected void setUp() throws Exception {
69.32 + }
69.33 +
69.34 + @Override
69.35 + protected void tearDown() throws Exception {
69.36 + }
69.37 +
69.38 + protected static final Currency CZK = Currency.getInstance( "CZK" );
69.39 + protected static final Currency SKK = Currency.getInstance( "SKK" );
69.40 + protected static final Currency USD = Currency.getInstance( "USD" );
69.41 +
69.42 + // Backward compatibly enhance your existing API to support following
69.43 + // usecases:
69.44 + //
69.45 +
69.46 +
69.47 + /** Without knowing anything about the surrounding system, write an
69.48 + * implementation of convertor that will return different rates everytime
69.49 + * it is queried. Convert USD to CZK and vice versa. Start with the rate of
69.50 + * 1USD = 16CZK and adjust it in favor of CZK by 0.01 CZK with every query.
69.51 + * As soon as you reach 1USD = 15CZK adjust it by 0.01 CZK in favor of USD
69.52 + * until you reach 1USD = 16CZK
69.53 + *
69.54 + * @return new instance of "online" USD and CZK convertor starting with rate 1USD = 16CZK
69.55 + */
69.56 + public static Convertor createOnlineCZKUSDConvertor() {
69.57 + // initial rate: 1USD = 16CZK
69.58 + // 2nd query 1USD = 15.99CZK
69.59 + // 3rd query 1USD = 15.98CZK
69.60 + // until 1USD = 15.00CZK
69.61 + // then 1USD = 15.01CZK
69.62 + // then 1USD = 15.02CZK
69.63 + // and so on and on up to 1USD = 16CZK
69.64 + // and then another round to 15, etc.
69.65 + final MonetaryAmount oneUSD = new MonetaryAmount( 1, USD );
69.66 + final BigDecimal startAmount = new BigDecimal( 16 );
69.67 + final BigDecimal endAmount = new BigDecimal( 15 );
69.68 + final BigDecimal stepAmount = BigDecimal.ONE.movePointLeft( 2 ).negate();
69.69 + return new ContractImposingDelegatingConvertor( new ZigZaggingBidirectionalConvertor( oneUSD, CZK, startAmount, endAmount, stepAmount ) );
69.70 + }
69.71 +
69.72 + public void testFewQueriesForOnlineConvertor() {
69.73 + Convertor c = createOnlineCZKUSDConvertor();
69.74 + doFewQueriesForOnlineConvertor(c);
69.75 + }
69.76 +
69.77 + static void doFewQueriesForOnlineConvertor( final Convertor c ) {
69.78 + // convert $5 to CZK using c:
69.79 + final Convertor.ConversionResult r1 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), CZK ) );
69.80 + final MonetaryAmount a1 = r1.getNetAmount();
69.81 + //assertEquals("Result is 80 CZK");
69.82 + assertNotNull( a1 );
69.83 + assertEquals( 80.0, a1.getAmount().doubleValue() );
69.84 + assertEquals( CZK, a1.getCurrency() );
69.85 +
69.86 + // convert $8 to CZK using c:
69.87 + final Convertor.ConversionResult r2 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 8, USD ), CZK ) );
69.88 + final MonetaryAmount a2 = r2.getNetAmount();
69.89 + //assertEquals("Result is 127.92 CZK");
69.90 + assertNotNull( a2 );
69.91 + assertEquals( 12792.0, a2.getAmount().movePointRight( 2 ).doubleValue() );
69.92 + assertEquals( CZK, a2.getCurrency() );
69.93 +
69.94 + // convert $1 to CZK using c:
69.95 + final Convertor.ConversionResult r3 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 1, USD ), CZK ) );
69.96 + final MonetaryAmount a3 = r3.getNetAmount();
69.97 + //assertEquals("Result is 15.98 CZK");
69.98 + assertNotNull( a3 );
69.99 + assertEquals( 1598.0, a3.getAmount().movePointRight( 2 ).doubleValue() );
69.100 + assertEquals( CZK, a3.getCurrency() );
69.101 +
69.102 + // convert 15.97CZK to USD using c:
69.103 + final BigDecimal s4 = new BigDecimal( 1597 ).movePointLeft( 2 );
69.104 + final Convertor.ConversionResult r4 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( s4, CZK ), USD ) );
69.105 + final MonetaryAmount a4 = r4.getNetAmount();
69.106 + //assertEquals("Result is 1$");
69.107 + assertNotNull( a4 );
69.108 + assertEquals( 1.0, a4.getAmount().doubleValue() );
69.109 + assertEquals( USD, a4.getCurrency() );
69.110 + }
69.111 +
69.112 + /** Join the convertors and show they behave sane.
69.113 + */
69.114 + public void testOnlineConvertorComposition() throws Exception {
69.115 + final Convertor c = Task2Test.merge(
69.116 + createOnlineCZKUSDConvertor(),
69.117 + Task1Test.createSKKtoCZK()
69.118 + );
69.119 +
69.120 + // convert 16CZK using c:
69.121 + final Convertor.ConversionResult r4 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 16, CZK ), SKK ) );
69.122 + final MonetaryAmount a4 = r4.getNetAmount();
69.123 + // assertEquals("Result is 20 SKK");
69.124 + assertNotNull( a4 );
69.125 + assertEquals( 20.0, a4.getAmount().doubleValue() );
69.126 + assertEquals( SKK, a4.getCurrency() );
69.127 +
69.128 + // convert 500SKK to CZK using c:
69.129 + final Convertor.ConversionResult r5 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 500, SKK ), CZK ) );
69.130 + final MonetaryAmount a5 = r5.getNetAmount();
69.131 + // assertEquals("Result is 400 CZK");
69.132 + assertNotNull( a5 );
69.133 + assertEquals( 400.0, a5.getAmount().doubleValue() );
69.134 + assertEquals( CZK, a5.getCurrency() );
69.135 +
69.136 + doFewQueriesForOnlineConvertor(c);
69.137 + }
69.138 +}
70.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
70.2 +++ b/task4/solution11/build.xml Sat Oct 11 23:38:46 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/task4/solution11/nbproject/build-impl.xml Sat Oct 11 23:38:46 2008 +0200
71.3 @@ -0,0 +1,629 @@
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_11-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 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="dt_socket">
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 "${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 "1.0"/>
71.253 + <contains string="${version-output}" substring="java version "1.1"/>
71.254 + <contains string="${version-output}" substring="java version "1.2"/>
71.255 + <contains string="${version-output}" substring="java version "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 + </target>
71.262 + <target depends="-init-debug-args" name="-init-macrodef-debug">
71.263 + <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
71.264 + <attribute default="${main.class}" name="classname"/>
71.265 + <attribute default="${debug.classpath}" name="classpath"/>
71.266 + <element name="customize" optional="true"/>
71.267 + <sequential>
71.268 + <java classname="@{classname}" dir="${work.dir}" fork="true">
71.269 + <jvmarg line="${debug-args-line}"/>
71.270 + <jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/>
71.271 + <jvmarg line="${run.jvmargs}"/>
71.272 + <classpath>
71.273 + <path path="@{classpath}"/>
71.274 + </classpath>
71.275 + <syspropertyset>
71.276 + <propertyref prefix="run-sys-prop."/>
71.277 + <mapper from="run-sys-prop.*" to="*" type="glob"/>
71.278 + </syspropertyset>
71.279 + <customize/>
71.280 + </java>
71.281 + </sequential>
71.282 + </macrodef>
71.283 + </target>
71.284 + <target name="-init-macrodef-java">
71.285 + <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
71.286 + <attribute default="${main.class}" name="classname"/>
71.287 + <element name="customize" optional="true"/>
71.288 + <sequential>
71.289 + <java classname="@{classname}" dir="${work.dir}" fork="true">
71.290 + <jvmarg line="${run.jvmargs}"/>
71.291 + <classpath>
71.292 + <path path="${run.classpath}"/>
71.293 + </classpath>
71.294 + <syspropertyset>
71.295 + <propertyref prefix="run-sys-prop."/>
71.296 + <mapper from="run-sys-prop.*" to="*" type="glob"/>
71.297 + </syspropertyset>
71.298 + <customize/>
71.299 + </java>
71.300 + </sequential>
71.301 + </macrodef>
71.302 + </target>
71.303 + <target name="-init-presetdef-jar">
71.304 + <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
71.305 + <jar compress="${jar.compress}" jarfile="${dist.jar}">
71.306 + <j2seproject1:fileset dir="${build.classes.dir}"/>
71.307 + </jar>
71.308 + </presetdef>
71.309 + </target>
71.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"/>
71.311 + <!--
71.312 + ===================
71.313 + COMPILATION SECTION
71.314 + ===================
71.315 + -->
71.316 + <target depends="init" name="deps-jar" unless="no.deps"/>
71.317 + <target depends="init,deps-jar" name="-pre-pre-compile">
71.318 + <mkdir dir="${build.classes.dir}"/>
71.319 + </target>
71.320 + <target name="-pre-compile">
71.321 + <!-- Empty placeholder for easier customization. -->
71.322 + <!-- You can override this target in the ../build.xml file. -->
71.323 + </target>
71.324 + <target if="do.depend.true" name="-compile-depend">
71.325 + <j2seproject3:depend/>
71.326 + </target>
71.327 + <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
71.328 + <j2seproject3:javac/>
71.329 + <copy todir="${build.classes.dir}">
71.330 + <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
71.331 + </copy>
71.332 + </target>
71.333 + <target name="-post-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 depends="init,deps-jar,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
71.338 + <target name="-pre-compile-single">
71.339 + <!-- Empty placeholder for easier customization. -->
71.340 + <!-- You can override this target in the ../build.xml file. -->
71.341 + </target>
71.342 + <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
71.343 + <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
71.344 + <j2seproject3:force-recompile/>
71.345 + <j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
71.346 + </target>
71.347 + <target name="-post-compile-single">
71.348 + <!-- Empty placeholder for easier customization. -->
71.349 + <!-- You can override this target in the ../build.xml file. -->
71.350 + </target>
71.351 + <target depends="init,deps-jar,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
71.352 + <!--
71.353 + ====================
71.354 + JAR BUILDING SECTION
71.355 + ====================
71.356 + -->
71.357 + <target depends="init" name="-pre-pre-jar">
71.358 + <dirname file="${dist.jar}" property="dist.jar.dir"/>
71.359 + <mkdir dir="${dist.jar.dir}"/>
71.360 + </target>
71.361 + <target name="-pre-jar">
71.362 + <!-- Empty placeholder for easier customization. -->
71.363 + <!-- You can override this target in the ../build.xml file. -->
71.364 + </target>
71.365 + <target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
71.366 + <j2seproject1:jar/>
71.367 + </target>
71.368 + <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
71.369 + <j2seproject1:jar manifest="${manifest.file}"/>
71.370 + </target>
71.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">
71.372 + <j2seproject1:jar manifest="${manifest.file}">
71.373 + <j2seproject1:manifest>
71.374 + <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
71.375 + </j2seproject1:manifest>
71.376 + </j2seproject1:jar>
71.377 + <echo>To run this application from the command line without Ant, try:</echo>
71.378 + <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
71.379 + <property location="${dist.jar}" name="dist.jar.resolved"/>
71.380 + <pathconvert property="run.classpath.with.dist.jar">
71.381 + <path path="${run.classpath}"/>
71.382 + <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
71.383 + </pathconvert>
71.384 + <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
71.385 + </target>
71.386 + <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
71.387 + <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
71.388 + <pathconvert property="run.classpath.without.build.classes.dir">
71.389 + <path path="${run.classpath}"/>
71.390 + <map from="${build.classes.dir.resolved}" to=""/>
71.391 + </pathconvert>
71.392 + <pathconvert pathsep=" " property="jar.classpath">
71.393 + <path path="${run.classpath.without.build.classes.dir}"/>
71.394 + <chainedmapper>
71.395 + <flattenmapper/>
71.396 + <globmapper from="*" to="lib/*"/>
71.397 + </chainedmapper>
71.398 + </pathconvert>
71.399 + <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
71.400 + <copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
71.401 + <fileset dir="${build.classes.dir}"/>
71.402 + <manifest>
71.403 + <attribute name="Main-Class" value="${main.class}"/>
71.404 + <attribute name="Class-Path" value="${jar.classpath}"/>
71.405 + </manifest>
71.406 + </copylibs>
71.407 + <echo>To run this application from the command line without Ant, try:</echo>
71.408 + <property location="${dist.jar}" name="dist.jar.resolved"/>
71.409 + <echo>java -jar "${dist.jar.resolved}"</echo>
71.410 + </target>
71.411 + <target name="-post-jar">
71.412 + <!-- Empty placeholder for easier customization. -->
71.413 + <!-- You can override this target in the ../build.xml file. -->
71.414 + </target>
71.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"/>
71.416 + <!--
71.417 + =================
71.418 + EXECUTION SECTION
71.419 + =================
71.420 + -->
71.421 + <target depends="init,compile" description="Run a main class." name="run">
71.422 + <j2seproject1:java>
71.423 + <customize>
71.424 + <arg line="${application.args}"/>
71.425 + </customize>
71.426 + </j2seproject1:java>
71.427 + </target>
71.428 + <target name="-do-not-recompile">
71.429 + <property name="javac.includes.binary" value=""/>
71.430 + </target>
71.431 + <target depends="init,-do-not-recompile,compile-single" name="run-single">
71.432 + <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
71.433 + <j2seproject1:java classname="${run.class}"/>
71.434 + </target>
71.435 + <!--
71.436 + =================
71.437 + DEBUGGING SECTION
71.438 + =================
71.439 + -->
71.440 + <target depends="init" if="netbeans.home" name="-debug-start-debugger">
71.441 + <j2seproject1:nbjpdastart name="${debug.class}"/>
71.442 + </target>
71.443 + <target depends="init,compile" name="-debug-start-debuggee">
71.444 + <j2seproject3:debug>
71.445 + <customize>
71.446 + <arg line="${application.args}"/>
71.447 + </customize>
71.448 + </j2seproject3:debug>
71.449 + </target>
71.450 + <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
71.451 + <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
71.452 + <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
71.453 + </target>
71.454 + <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
71.455 + <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
71.456 + <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
71.457 + <j2seproject3:debug classname="${debug.class}"/>
71.458 + </target>
71.459 + <target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
71.460 + <target depends="init" name="-pre-debug-fix">
71.461 + <fail unless="fix.includes">Must set fix.includes</fail>
71.462 + <property name="javac.includes" value="${fix.includes}.java"/>
71.463 + </target>
71.464 + <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
71.465 + <j2seproject1:nbjpdareload/>
71.466 + </target>
71.467 + <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
71.468 + <!--
71.469 + ===============
71.470 + JAVADOC SECTION
71.471 + ===============
71.472 + -->
71.473 + <target depends="init" name="-javadoc-build">
71.474 + <mkdir dir="${dist.javadoc.dir}"/>
71.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}">
71.476 + <classpath>
71.477 + <path path="${javac.classpath}"/>
71.478 + </classpath>
71.479 + <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
71.480 + <filename name="**/*.java"/>
71.481 + </fileset>
71.482 + </javadoc>
71.483 + </target>
71.484 + <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
71.485 + <nbbrowse file="${dist.javadoc.dir}/index.html"/>
71.486 + </target>
71.487 + <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
71.488 + <!--
71.489 + =========================
71.490 + JUNIT COMPILATION SECTION
71.491 + =========================
71.492 + -->
71.493 + <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
71.494 + <mkdir dir="${build.test.classes.dir}"/>
71.495 + </target>
71.496 + <target name="-pre-compile-test">
71.497 + <!-- Empty placeholder for easier customization. -->
71.498 + <!-- You can override this target in the ../build.xml file. -->
71.499 + </target>
71.500 + <target if="do.depend.true" name="-compile-test-depend">
71.501 + <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
71.502 + </target>
71.503 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
71.504 + <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
71.505 + <copy todir="${build.test.classes.dir}">
71.506 + <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
71.507 + </copy>
71.508 + </target>
71.509 + <target name="-post-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 depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
71.514 + <target name="-pre-compile-test-single">
71.515 + <!-- Empty placeholder for easier customization. -->
71.516 + <!-- You can override this target in the ../build.xml file. -->
71.517 + </target>
71.518 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
71.519 + <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
71.520 + <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
71.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}"/>
71.522 + <copy todir="${build.test.classes.dir}">
71.523 + <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
71.524 + </copy>
71.525 + </target>
71.526 + <target name="-post-compile-test-single">
71.527 + <!-- Empty placeholder for easier customization. -->
71.528 + <!-- You can override this target in the ../build.xml file. -->
71.529 + </target>
71.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"/>
71.531 + <!--
71.532 + =======================
71.533 + JUNIT EXECUTION SECTION
71.534 + =======================
71.535 + -->
71.536 + <target depends="init" if="have.tests" name="-pre-test-run">
71.537 + <mkdir dir="${build.test.results.dir}"/>
71.538 + </target>
71.539 + <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
71.540 + <j2seproject3:junit testincludes="**/*Test.java"/>
71.541 + </target>
71.542 + <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
71.543 + <fail if="tests.failed">Some tests failed; see details above.</fail>
71.544 + </target>
71.545 + <target depends="init" if="have.tests" name="test-report"/>
71.546 + <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
71.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"/>
71.548 + <target depends="init" if="have.tests" name="-pre-test-run-single">
71.549 + <mkdir dir="${build.test.results.dir}"/>
71.550 + </target>
71.551 + <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
71.552 + <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
71.553 + <j2seproject3:junit excludes="" includes="${test.includes}"/>
71.554 + </target>
71.555 + <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
71.556 + <fail if="tests.failed">Some tests failed; see details above.</fail>
71.557 + </target>
71.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"/>
71.559 + <!--
71.560 + =======================
71.561 + JUNIT DEBUGGING SECTION
71.562 + =======================
71.563 + -->
71.564 + <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
71.565 + <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
71.566 + <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
71.567 + <delete file="${test.report.file}"/>
71.568 + <mkdir dir="${build.test.results.dir}"/>
71.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}">
71.570 + <customize>
71.571 + <syspropertyset>
71.572 + <propertyref prefix="test-sys-prop."/>
71.573 + <mapper from="test-sys-prop.*" to="*" type="glob"/>
71.574 + </syspropertyset>
71.575 + <arg value="${test.class}"/>
71.576 + <arg value="showoutput=true"/>
71.577 + <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
71.578 + <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
71.579 + </customize>
71.580 + </j2seproject3:debug>
71.581 + </target>
71.582 + <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
71.583 + <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
71.584 + </target>
71.585 + <target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
71.586 + <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
71.587 + <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
71.588 + </target>
71.589 + <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
71.590 + <!--
71.591 + =========================
71.592 + APPLET EXECUTION SECTION
71.593 + =========================
71.594 + -->
71.595 + <target depends="init,compile-single" name="run-applet">
71.596 + <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
71.597 + <j2seproject1:java classname="sun.applet.AppletViewer">
71.598 + <customize>
71.599 + <arg value="${applet.url}"/>
71.600 + </customize>
71.601 + </j2seproject1:java>
71.602 + </target>
71.603 + <!--
71.604 + =========================
71.605 + APPLET DEBUGGING SECTION
71.606 + =========================
71.607 + -->
71.608 + <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
71.609 + <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
71.610 + <j2seproject3:debug classname="sun.applet.AppletViewer">
71.611 + <customize>
71.612 + <arg value="${applet.url}"/>
71.613 + </customize>
71.614 + </j2seproject3:debug>
71.615 + </target>
71.616 + <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
71.617 + <!--
71.618 + ===============
71.619 + CLEANUP SECTION
71.620 + ===============
71.621 + -->
71.622 + <target depends="init" name="deps-clean" unless="no.deps"/>
71.623 + <target depends="init" name="-do-clean">
71.624 + <delete dir="${build.dir}"/>
71.625 + <delete dir="${dist.dir}"/>
71.626 + </target>
71.627 + <target name="-post-clean">
71.628 + <!-- Empty placeholder for easier customization. -->
71.629 + <!-- You can override this target in the ../build.xml file. -->
71.630 + </target>
71.631 + <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
71.632 +</project>
72.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
72.2 +++ b/task4/solution11/nbproject/genfiles.properties Sat Oct 11 23:38:46 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=0e1e702f
72.10 +nbproject/build-impl.xml.script.CRC32=c899f2cf
72.11 +nbproject/build-impl.xml.stylesheet.CRC32=487672f9
73.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
73.2 +++ b/task4/solution11/nbproject/project.properties Sat Oct 11 23:38:46 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=-Xlint:unchecked
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/task4/solution11/nbproject/project.xml Sat Oct 11 23:38:46 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 11</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/task4/solution11/src/org/apidesign/apifest08/currency/Computer.java Sat Oct 11 23:38:46 2008 +0200
75.3 @@ -0,0 +1,61 @@
75.4 +package org.apidesign.apifest08.currency;
75.5 +
75.6 +/**
75.7 + * Interface declaring method for computing conversion.
75.8 + *
75.9 + * Because of a vague definition of currency amount's type,
75.10 + * the interface has a generic type.
75.11 + *
75.12 + * @author ked
75.13 + * @see http://wiki.apidesign.org/wiki/APIDesignPatterns:ResponseReply
75.14 + */
75.15 +interface Computer<AmountType> {
75.16 +
75.17 + void compute(ComputerRequest<AmountType> request, ComputerResponse<AmountType> response);
75.18 +
75.19 + final class ComputerRequest<AmountType> {
75.20 +
75.21 + private AmountType input;
75.22 + private AmountType inputCurrencyRatio;
75.23 + private AmountType outputCurrencyRatio;
75.24 +
75.25 + AmountType getInput() {
75.26 + return input;
75.27 + }
75.28 +
75.29 + void setInput(AmountType input) {
75.30 + this.input = input;
75.31 + }
75.32 +
75.33 + AmountType getInputCurrencyRatio() {
75.34 + return inputCurrencyRatio;
75.35 + }
75.36 +
75.37 + void setInputCurrencyRatio(AmountType inputCurrencyRatio) {
75.38 + this.inputCurrencyRatio = inputCurrencyRatio;
75.39 + }
75.40 +
75.41 + AmountType getOutputCurrencyRatio() {
75.42 + return outputCurrencyRatio;
75.43 + }
75.44 +
75.45 + void setOutputCurrencyRatio(AmountType outputCurrencyRatio) {
75.46 + this.outputCurrencyRatio = outputCurrencyRatio;
75.47 + }
75.48 + }
75.49 +
75.50 + final class ComputerResponse<AmountType> {
75.51 +
75.52 + private AmountType result;
75.53 +
75.54 + AmountType getResult() {
75.55 + return result;
75.56 + }
75.57 +
75.58 + void setResult(AmountType result) {
75.59 + this.result = result;
75.60 + }
75.61 + }
75.62 +
75.63 +
75.64 +}
75.65 \ No newline at end of file
76.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
76.2 +++ b/task4/solution11/src/org/apidesign/apifest08/currency/Convertor.java Sat Oct 11 23:38:46 2008 +0200
76.3 @@ -0,0 +1,311 @@
76.4 +package org.apidesign.apifest08.currency;
76.5 +
76.6 +import java.util.ArrayList;
76.7 +import java.util.Collection;
76.8 +import java.util.HashSet;
76.9 +import java.util.List;
76.10 +import java.util.Set;
76.11 +import org.apidesign.apifest08.currency.Computer.ComputerRequest;
76.12 +import org.apidesign.apifest08.currency.Computer.ComputerResponse;
76.13 +
76.14 +/**
76.15 + * Convertor.
76.16 + *
76.17 + * In Task 1's version provides conversion between currency values
76.18 + * with amount stored in integer or double, that are identified
76.19 + * with string value. Exchange rates are immutable.
76.20 + *
76.21 + * In Task2's version provides support for multiple exchange rates
76.22 + * between different currencies & merging exchange rates from
76.23 + * existing convertors into new convertor's instance.
76.24 + * No time for javadoc these features, sorry.
76.25 + *
76.26 + * In Task3's version supports reading of current exchange rates
76.27 + * from data sources. Data sources are merged during convertors' merging
76.28 + * as well as static exchange rates.
76.29 + * No time for javadoc, again.
76.30 + *
76.31 + * @author ked
76.32 + */
76.33 +public final class Convertor<AmountType, IdentifierType> {
76.34 +
76.35 + Computer<AmountType> computer;
76.36 + // each static exchange rate could be a special case of an exchange rate data source
76.37 + List<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates = new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
76.38 + List<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources = new ArrayList<ExchangeRateDataSource<AmountType, IdentifierType>>();
76.39 +
76.40 + Convertor(Computer<AmountType> computer) {
76.41 + this.computer = computer;
76.42 + }
76.43 +
76.44 + void addExchangeRates(Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
76.45 + for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
76.46 + if (isExchangeRate(
76.47 + exchangeRate.getCurrencyA().getIdentifier(),
76.48 + exchangeRate.getCurrencyB().getIdentifier())) {
76.49 + throw new IllegalArgumentException("Duplicate exchange rate!");
76.50 + }
76.51 + this.exchangeRates.add(exchangeRate);
76.52 + }
76.53 + }
76.54 +
76.55 + void addExchangeRateDataSources(Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources) {
76.56 + for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : exchangeRateDataSources) {
76.57 + if (isExchangeRate(
76.58 + exchangeRateDataSource.getCurrencyAIdentifier(),
76.59 + exchangeRateDataSource.getCurrencyBIdentifier())) {
76.60 + throw new IllegalArgumentException("Duplicate exchange rate!");
76.61 + }
76.62 + this.exchangeRateDataSources.add(exchangeRateDataSource);
76.63 + }
76.64 + }
76.65 +
76.66 + ExchangeRateValue<AmountType, IdentifierType> findExchangeRate(
76.67 + IdentifierType currencyA,
76.68 + IdentifierType currencyB) {
76.69 + for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
76.70 + if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) ||
76.71 + (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) {
76.72 + return exchangeRate;
76.73 + }
76.74 + }
76.75 + for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : exchangeRateDataSources) {
76.76 + if ((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) ||
76.77 + (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) {
76.78 + return exchangeRateDataSource.getExchangeRate();
76.79 + }
76.80 + }
76.81 + return null;
76.82 + }
76.83 +
76.84 + boolean isExchangeRate(
76.85 + IdentifierType currencyA,
76.86 + IdentifierType currencyB) {
76.87 + for (ExchangeRateValue<AmountType, IdentifierType> exchangeRate : exchangeRates) {
76.88 + if ((exchangeRate.getCurrencyA().getIdentifier().equals(currencyA) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyB)) ||
76.89 + (exchangeRate.getCurrencyA().getIdentifier().equals(currencyB) && exchangeRate.getCurrencyB().getIdentifier().equals(currencyA))) {
76.90 + return true;
76.91 + }
76.92 + }
76.93 + for (ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource : exchangeRateDataSources) {
76.94 + if ((exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyA) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyB)) ||
76.95 + (exchangeRateDataSource.getCurrencyAIdentifier().equals(currencyB) && exchangeRateDataSource.getCurrencyBIdentifier().equals(currencyA))) {
76.96 + return true;
76.97 + }
76.98 + }
76.99 + return false;
76.100 + }
76.101 +
76.102 + /**
76.103 + * Convert an amount of the one currency to an amount of the another one currency
76.104 + * with respect to previously specified exchange rates.
76.105 + *
76.106 + * @param targetCurrency an identifier of the requested currency
76.107 + * @param currencyValue an amount of the another one currency
76.108 + * @return an amount of the requested currency
76.109 + */
76.110 + public CurrencyValue<AmountType, IdentifierType> convert(
76.111 + IdentifierType targetCurrency,
76.112 + CurrencyValue<AmountType, IdentifierType> currencyValue) {
76.113 + ExchangeRateValue<AmountType, IdentifierType> exchangeRate =
76.114 + findExchangeRate(currencyValue.getIdentifier(), targetCurrency);
76.115 + if (exchangeRate == null) {
76.116 + throw new IllegalArgumentException("Inappropriate currencies to convert!");
76.117 + }
76.118 +
76.119 + ComputerRequest<AmountType> computerRequest = new ComputerRequest<AmountType>();
76.120 + computerRequest.setInput(currencyValue.getAmount());
76.121 +
76.122 + IdentifierType targetCurrencyRef; // just for backward compatibility :-(
76.123 + if (exchangeRate.getCurrencyA().getIdentifier().equals(targetCurrency)) {
76.124 + computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
76.125 + computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
76.126 + targetCurrencyRef = exchangeRate.getCurrencyA().getIdentifier();
76.127 + } else {
76.128 + computerRequest.setInputCurrencyRatio(exchangeRate.getCurrencyA().getAmount());
76.129 + computerRequest.setOutputCurrencyRatio(exchangeRate.getCurrencyB().getAmount());
76.130 + targetCurrencyRef = exchangeRate.getCurrencyB().getIdentifier();
76.131 + }
76.132 +
76.133 + ComputerResponse<AmountType> computerResponse = new ComputerResponse<AmountType>();
76.134 + computer.compute(computerRequest, computerResponse);
76.135 +
76.136 + return CurrencyValue.getCurrencyValue(
76.137 + computerResponse.getResult(),
76.138 + targetCurrencyRef);
76.139 + }
76.140 +
76.141 + // ---
76.142 + // MERGING
76.143 + // ---
76.144 + static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
76.145 + Computer<AmountType> computer,
76.146 + Collection<Convertor<AmountType, IdentifierType>> convertors) {
76.147 + Set<ExchangeRateValue<AmountType, IdentifierType>> exchangeRatesSet = new HashSet<ExchangeRateValue<AmountType, IdentifierType>>();
76.148 + Set<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSourcesSet = new HashSet<ExchangeRateDataSource<AmountType, IdentifierType>>();
76.149 + for (Convertor<AmountType, IdentifierType> convertor : convertors) {
76.150 + exchangeRatesSet.addAll(convertor.exchangeRates);
76.151 + }
76.152 + for (Convertor<AmountType, IdentifierType> convertor : convertors) {
76.153 + exchangeRateDataSourcesSet.addAll(convertor.exchangeRateDataSources);
76.154 + }
76.155 +
76.156 + Convertor<AmountType, IdentifierType> c = new Convertor<AmountType, IdentifierType>(computer);
76.157 + c.addExchangeRates(exchangeRatesSet);
76.158 + c.addExchangeRateDataSources(exchangeRateDataSourcesSet);
76.159 + return c;
76.160 + }
76.161 +
76.162 + static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> mergeConvertors(
76.163 + Computer<AmountType> computer,
76.164 + Convertor<AmountType, IdentifierType> convertorA,
76.165 + Convertor<AmountType, IdentifierType> convertorB) {
76.166 + Collection<Convertor<AmountType, IdentifierType>> convertors =
76.167 + new ArrayList<Convertor<AmountType, IdentifierType>>();
76.168 + convertors.add(convertorA);
76.169 + convertors.add(convertorB);
76.170 + return mergeConvertors(computer, convertors);
76.171 + }
76.172 +
76.173 + public static Convertor<Double, String> mergeConvertorsDoubleString(
76.174 + Collection<Convertor<Double, String>> convertors) {
76.175 + return mergeConvertors(DoubleComputer, convertors);
76.176 + }
76.177 +
76.178 + public static Convertor<Double, String> mergeConvertorsDoubleString(
76.179 + Convertor<Double, String> convertorA,
76.180 + Convertor<Double, String> convertorB) {
76.181 + return mergeConvertors(DoubleComputer, convertorA, convertorB);
76.182 + }
76.183 +
76.184 + public static Convertor<Integer, String> mergeConvertorsIntegerString(
76.185 + Collection<Convertor<Integer, String>> convertors) {
76.186 + return mergeConvertors(IntegerComputer, convertors);
76.187 + }
76.188 +
76.189 + public static Convertor<Integer, String> mergeConvertorsIntegerString(
76.190 + Convertor<Integer, String> convertorA,
76.191 + Convertor<Integer, String> convertorB) {
76.192 + return mergeConvertors(IntegerComputer, convertorA, convertorB);
76.193 + }
76.194 +
76.195 + // ---
76.196 + // CREATION
76.197 + // ---
76.198 + static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
76.199 + Computer<AmountType> computer, Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates) {
76.200 + Convertor<AmountType, IdentifierType> c = new Convertor<AmountType, IdentifierType>(computer);
76.201 + c.addExchangeRates(exchangeRates);
76.202 + return c;
76.203 + }
76.204 +
76.205 + static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertorDataSource(
76.206 + Computer<AmountType> computer, Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources) {
76.207 + Convertor<AmountType, IdentifierType> c = new Convertor<AmountType, IdentifierType>(computer);
76.208 + c.addExchangeRateDataSources(exchangeRateDataSources);
76.209 + return c;
76.210 + }
76.211 +
76.212 + static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertor(
76.213 + Computer<AmountType> computer, ExchangeRateValue<AmountType, IdentifierType> exchangeRate) {
76.214 + Collection<ExchangeRateValue<AmountType, IdentifierType>> exchangeRates =
76.215 + new ArrayList<ExchangeRateValue<AmountType, IdentifierType>>();
76.216 + exchangeRates.add(exchangeRate);
76.217 + return getConvertor(computer, exchangeRates);
76.218 + }
76.219 +
76.220 + static <AmountType, IdentifierType> Convertor<AmountType, IdentifierType> getConvertorDataSource(
76.221 + Computer<AmountType> computer, ExchangeRateDataSource<AmountType, IdentifierType> exchangeRateDataSource) {
76.222 + Collection<ExchangeRateDataSource<AmountType, IdentifierType>> exchangeRateDataSources =
76.223 + new ArrayList<ExchangeRateDataSource<AmountType, IdentifierType>>();
76.224 + exchangeRateDataSources.add(exchangeRateDataSource);
76.225 + return getConvertorDataSource(computer, exchangeRateDataSources);
76.226 + }
76.227 +
76.228 + public static Convertor<Double, String> getConvertorDoubleString(
76.229 + Collection<ExchangeRateValue<Double, String>> exchangeRates) {
76.230 + return getConvertor(DoubleComputer, exchangeRates);
76.231 + }
76.232 +
76.233 + public static Convertor<Double, String> getConvertorDoubleString(
76.234 + ExchangeRateValue<Double, String> exchangeRate) {
76.235 + return getConvertor(DoubleComputer, exchangeRate);
76.236 + }
76.237 +
76.238 + public static Convertor<Double, String> getConvertorDataSourceDoubleString(
76.239 + Collection<ExchangeRateDataSource<Double, String>> exchangeRateDataSources) {
76.240 + return getConvertorDataSource(DoubleComputer, exchangeRateDataSources);
76.241 + }
76.242 +
76.243 + public static Convertor<Double, String> getConvertorDataSourceDoubleString(
76.244 + ExchangeRateDataSource<Double, String> exchangeRateDataSource) {
76.245 + return getConvertorDataSource(DoubleComputer, exchangeRateDataSource);
76.246 + }
76.247 +
76.248 + public static Convertor<Integer, String> getConvertorIntegerString(
76.249 + Collection<ExchangeRateValue<Integer, String>> exchangeRates) {
76.250 + return getConvertor(IntegerComputer, exchangeRates);
76.251 + }
76.252 +
76.253 + public static Convertor<Integer, String> getConvertorIntegerString(
76.254 + ExchangeRateValue<Integer, String> exchangeRate) {
76.255 + return getConvertor(IntegerComputer, exchangeRate);
76.256 + }
76.257 +
76.258 + public static Convertor<Integer, String> getConvertorDataSourceIntegerString(
76.259 + Collection<ExchangeRateDataSource<Integer, String>> exchangeRateDataSources) {
76.260 + return getConvertorDataSource(IntegerComputer, exchangeRateDataSources);
76.261 + }
76.262 +
76.263 + public static Convertor<Integer, String> getConvertorDataSourceIntegerString(
76.264 + ExchangeRateDataSource<Integer, String> exchangeRateDataSource) {
76.265 + return getConvertorDataSource(IntegerComputer, exchangeRateDataSource);
76.266 + }
76.267 +
76.268 + // ---
76.269 + // BACKWARD COMPATIBILITY - CREATION
76.270 + // ---
76.271 + /**
76.272 + * Creates convertor for Double|String values with specified exchange rate
76.273 + * between two currencies.
76.274 + *
76.275 + * @param firstCurrencyExchangeRate first currency
76.276 + * @param secondCurrencyExchangeRate second currency
76.277 + * @return convertor
76.278 + */
76.279 + public static Convertor<Double, String> getConvertorDoubleString(
76.280 + CurrencyValue<Double, String> firstCurrencyExchangeRate,
76.281 + CurrencyValue<Double, String> secondCurrencyExchangeRate) {
76.282 + return getConvertorDoubleString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
76.283 + }
76.284 +
76.285 + /**
76.286 + * Creates convertor for Integer|String values with specified exchange rate
76.287 + * between two currencies.
76.288 + *
76.289 + * @param firstCurrencyExchangeRate first currency
76.290 + * @param secondCurrencyExchangeRate second currency
76.291 + * @return convertor
76.292 + */
76.293 + public static Convertor<Integer, String> getConvertorIntegerString(
76.294 + CurrencyValue<Integer, String> firstCurrencyExchangeRate,
76.295 + CurrencyValue<Integer, String> secondCurrencyExchangeRate) {
76.296 + return getConvertorIntegerString(ExchangeRateValue.getExchangeRate(firstCurrencyExchangeRate, secondCurrencyExchangeRate));
76.297 + }
76.298 +
76.299 + // ---
76.300 + // COMPUTERS
76.301 + // ---
76.302 + static final Computer<Double> DoubleComputer = new Computer<Double>() {
76.303 +
76.304 + public void compute(ComputerRequest<Double> request, ComputerResponse<Double> response) {
76.305 + response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());
76.306 + }
76.307 + };
76.308 + static final Computer<Integer> IntegerComputer = new Computer<Integer>() {
76.309 +
76.310 + public void compute(ComputerRequest<Integer> request, ComputerResponse<Integer> response) {
76.311 + response.setResult(request.getInput() * request.getOutputCurrencyRatio() / request.getInputCurrencyRatio());
76.312 + }
76.313 + };
76.314 +}
77.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
77.2 +++ b/task4/solution11/src/org/apidesign/apifest08/currency/CurrencyValue.java Sat Oct 11 23:38:46 2008 +0200
77.3 @@ -0,0 +1,72 @@
77.4 +package org.apidesign.apifest08.currency;
77.5 +
77.6 +import java.io.Serializable;
77.7 +
77.8 +/**
77.9 + * Value class, holding an amount of the currency & an identifier of the currency.
77.10 + * Designed to be an immutable.
77.11 + *
77.12 + * Because of a vague definition of types of the both fields,
77.13 + * the class has generic types, used as types of the fields.
77.14 + * These types should be immutable classes, too.
77.15 + *
77.16 + * @author ked
77.17 + */
77.18 +public final class CurrencyValue<AmountType, IdentifierType> implements Serializable {
77.19 +
77.20 + private final AmountType amount;
77.21 + private final IdentifierType identifier;
77.22 +
77.23 + private CurrencyValue(AmountType amount, IdentifierType identifier) {
77.24 + this.amount = amount;
77.25 + this.identifier = identifier;
77.26 + }
77.27 +
77.28 + public AmountType getAmount() {
77.29 + return amount;
77.30 + }
77.31 +
77.32 + public IdentifierType getIdentifier() {
77.33 + return identifier;
77.34 + }
77.35 +
77.36 + @Override
77.37 + public boolean equals(Object obj) {
77.38 + if (obj == null) {
77.39 + return false;
77.40 + }
77.41 + if (getClass() != obj.getClass()) {
77.42 + return false;
77.43 + }
77.44 + final CurrencyValue other = (CurrencyValue) obj;
77.45 + if (this.amount != other.amount && (this.amount == null || !this.amount.equals(other.amount))) {
77.46 + return false;
77.47 + }
77.48 + if (this.identifier != other.identifier && (this.identifier == null || !this.identifier.equals(other.identifier))) {
77.49 + return false;
77.50 + }
77.51 + return true;
77.52 + }
77.53 +
77.54 + @Override
77.55 + public int hashCode() {
77.56 + int hash = 7;
77.57 + hash = 97 * hash + (this.amount != null ? this.amount.hashCode() : 0);
77.58 + hash = 97 * hash + (this.identifier != null ? this.identifier.hashCode() : 0);
77.59 + return hash;
77.60 + }
77.61 +
77.62 + /**
77.63 + * Creates new instance.
77.64 + * Generic types of the new instance are derived from types of the parameters.
77.65 + *
77.66 + * @param <AmountType> type of the currency amount
77.67 + * @param <IdentifierType> type of the currency identifier
77.68 + * @param amount currency amount
77.69 + * @param identifier currency identifier
77.70 + * @return new instance
77.71 + */
77.72 + public static <AmountType, IdentifierType> CurrencyValue<AmountType, IdentifierType> getCurrencyValue(AmountType amount, IdentifierType identifier) {
77.73 + return new CurrencyValue<AmountType, IdentifierType>(amount, identifier);
77.74 + }
77.75 +}
78.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
78.2 +++ b/task4/solution11/src/org/apidesign/apifest08/currency/ExchangeRateDataSource.java Sat Oct 11 23:38:46 2008 +0200
78.3 @@ -0,0 +1,103 @@
78.4 +package org.apidesign.apifest08.currency;
78.5 +
78.6 +import org.apidesign.apifest08.currency.ExchangeRateProvider.ExchangeRateRequest;
78.7 +import org.apidesign.apifest08.currency.ExchangeRateProvider.ExchangeRateResponse;
78.8 +
78.9 +/**
78.10 + * Exchange rate data source.
78.11 + *
78.12 + * @author ked
78.13 + */
78.14 +public final class ExchangeRateDataSource<AmountType, IdentifierType> {
78.15 +
78.16 + private final IdentifierType currencyAIdentifier;
78.17 +
78.18 + private final IdentifierType currencyBIdentifier;
78.19 +
78.20 + private final ExchangeRateProvider<AmountType, IdentifierType> exchangeRateProvider;
78.21 +
78.22 + private ExchangeRateDataSource(
78.23 + IdentifierType currencyAIdentifier,
78.24 + IdentifierType currencyBIdentifier,
78.25 + ExchangeRateProvider<AmountType, IdentifierType> exchangeRateProvider) {
78.26 + if (currencyAIdentifier == null ||
78.27 + currencyBIdentifier == null ||
78.28 + currencyAIdentifier.equals(currencyBIdentifier)) {
78.29 + throw new IllegalArgumentException("Inappropriate exchange rates' identifiers!");
78.30 + }
78.31 + this.currencyAIdentifier = currencyAIdentifier;
78.32 + this.currencyBIdentifier = currencyBIdentifier;
78.33 + this.exchangeRateProvider = exchangeRateProvider;
78.34 + }
78.35 +
78.36 + public IdentifierType getCurrencyAIdentifier() {
78.37 + return currencyAIdentifier;
78.38 + }
78.39 +
78.40 + public IdentifierType getCurrencyBIdentifier() {
78.41 + return currencyBIdentifier;
78.42 + }
78.43 +
78.44 + public ExchangeRateValue<AmountType, IdentifierType> getExchangeRate() {
78.45 + ExchangeRateRequest<AmountType, IdentifierType> request =
78.46 + new ExchangeRateRequest<AmountType, IdentifierType>();
78.47 + ExchangeRateResponse<AmountType, IdentifierType> response =
78.48 + new ExchangeRateResponse<AmountType, IdentifierType>();
78.49 +
78.50 + request.setCurrencyAIdentifier(currencyAIdentifier);
78.51 + request.setCurrencyBIdentifier(currencyBIdentifier);
78.52 +
78.53 + exchangeRateProvider.getExchangeRate(request, response);
78.54 +
78.55 + if (response.getExchangeRate().getCurrencyA().getIdentifier().equals(currencyAIdentifier) &&
78.56 + response.getExchangeRate().getCurrencyB().getIdentifier().equals(currencyBIdentifier)) {
78.57 + return response.getExchangeRate();
78.58 + } else {
78.59 + throw new IllegalStateException("Data source's provider returned inappropriate exchange rate!");
78.60 + }
78.61 + }
78.62 +
78.63 + public static <AmountType, IdentifierType> ExchangeRateDataSource<AmountType, IdentifierType> getExchangeRateDataSource(
78.64 + IdentifierType currencyAIdentifier,
78.65 + IdentifierType currencyBIdentifier,
78.66 + ExchangeRateProvider<AmountType, IdentifierType> exchangeRateProvider) {
78.67 + return new ExchangeRateDataSource<AmountType, IdentifierType>(
78.68 + currencyAIdentifier,
78.69 + currencyBIdentifier,
78.70 + exchangeRateProvider);
78.71 + }
78.72 +
78.73 + @Override
78.74 + public boolean equals(Object obj) {
78.75 + if (obj == null) {
78.76 + return false;
78.77 + }
78.78 + if (getClass() != obj.getClass()) {
78.79 + return false;
78.80 + }
78.81 + final ExchangeRateDataSource other =
78.82 + (ExchangeRateDataSource) obj;
78.83 + if (this.currencyAIdentifier != other.currencyAIdentifier &&
78.84 + (this.currencyAIdentifier == null || !this.currencyAIdentifier.equals(other.currencyAIdentifier))) {
78.85 + return false;
78.86 + }
78.87 + if (this.currencyBIdentifier != other.currencyBIdentifier &&
78.88 + (this.currencyBIdentifier == null || !this.currencyBIdentifier.equals(other.currencyBIdentifier))) {
78.89 + return false;
78.90 + }
78.91 + if (this.exchangeRateProvider != other.exchangeRateProvider &&
78.92 + (this.exchangeRateProvider == null || !this.exchangeRateProvider.equals(other.exchangeRateProvider))) {
78.93 + return false;
78.94 + }
78.95 + return true;
78.96 + }
78.97 +
78.98 + @Override
78.99 + public int hashCode() {
78.100 + int hash = 7;
78.101 + hash = 83 * hash + (this.currencyAIdentifier != null ? this.currencyAIdentifier.hashCode() : 0);
78.102 + hash = 83 * hash + (this.currencyBIdentifier != null ? this.currencyBIdentifier.hashCode() : 0);
78.103 + hash = 83 * hash + (this.exchangeRateProvider != null ? this.exchangeRateProvider.hashCode() : 0);
78.104 + return hash;
78.105 + }
78.106 +}
79.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
79.2 +++ b/task4/solution11/src/org/apidesign/apifest08/currency/ExchangeRateProvider.java Sat Oct 11 23:38:46 2008 +0200
79.3 @@ -0,0 +1,55 @@
79.4 +package org.apidesign.apifest08.currency;
79.5 +
79.6 +/**
79.7 + * Exchange rate provider.
79.8 + *
79.9 + * @author ked
79.10 + * @see http://wiki.apidesign.org/wiki/APIDesignPatterns:ResponseReply
79.11 + */
79.12 +public interface ExchangeRateProvider<AmountType, IdentifierType> {
79.13 +
79.14 + public void getExchangeRate(
79.15 + ExchangeRateRequest<AmountType, IdentifierType> request,
79.16 + ExchangeRateResponse<AmountType, IdentifierType> response);
79.17 +
79.18 + public final class ExchangeRateRequest<AmountType, IdentifierType> {
79.19 +
79.20 + private IdentifierType currencyAIdentifier;
79.21 + private IdentifierType currencyBIdentifier;
79.22 +
79.23 + ExchangeRateRequest() {
79.24 + }
79.25 +
79.26 + public IdentifierType getCurrencyAIdentifier() {
79.27 + return currencyAIdentifier;
79.28 + }
79.29 +
79.30 + void setCurrencyAIdentifier(IdentifierType currencyAIdentifier) {
79.31 + this.currencyAIdentifier = currencyAIdentifier;
79.32 + }
79.33 +
79.34 + public IdentifierType getCurrencyBIdentifier() {
79.35 + return currencyBIdentifier;
79.36 + }
79.37 +
79.38 + void setCurrencyBIdentifier(IdentifierType currencyBIdentifier) {
79.39 + this.currencyBIdentifier = currencyBIdentifier;
79.40 + }
79.41 + }
79.42 +
79.43 + public final class ExchangeRateResponse<AmountType, IdentifierType> {
79.44 +
79.45 + private ExchangeRateValue<AmountType, IdentifierType> exchangeRate;
79.46 +
79.47 + ExchangeRateResponse() {
79.48 + }
79.49 +
79.50 + ExchangeRateValue<AmountType, IdentifierType> getExchangeRate() {
79.51 + return exchangeRate;
79.52 + }
79.53 +
79.54 + public void setExchangeRate(ExchangeRateValue<AmountType, IdentifierType> exchangeRate) {
79.55 + this.exchangeRate = exchangeRate;
79.56 + }
79.57 + }
79.58 +}
80.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
80.2 +++ b/task4/solution11/src/org/apidesign/apifest08/currency/ExchangeRateValue.java Sat Oct 11 23:38:46 2008 +0200
80.3 @@ -0,0 +1,78 @@
80.4 +package org.apidesign.apifest08.currency;
80.5 +
80.6 +import java.io.Serializable;
80.7 +
80.8 +/**
80.9 + * Value class, holding an exchange rate between two currencies.
80.10 + * Designed to be an immutable.
80.11 + *
80.12 + * @author ked
80.13 + */
80.14 +public final class ExchangeRateValue<AmountType, IdentifierType> implements Serializable {
80.15 +
80.16 + private final CurrencyValue<AmountType, IdentifierType> currencyA;
80.17 + private final CurrencyValue<AmountType, IdentifierType> currencyB;
80.18 +
80.19 + private ExchangeRateValue(
80.20 + CurrencyValue<AmountType, IdentifierType> currencyA,
80.21 + CurrencyValue<AmountType, IdentifierType> currencyB) {
80.22 + if (currencyA.getIdentifier() == null ||
80.23 + currencyB.getIdentifier() == null ||
80.24 + currencyA.getIdentifier().equals(currencyB)) {
80.25 + throw new IllegalArgumentException("Inappropriate exchange rates' identifiers!");
80.26 + }
80.27 +
80.28 + this.currencyA = currencyA;
80.29 + this.currencyB = currencyB;
80.30 + }
80.31 +
80.32 + public CurrencyValue<AmountType, IdentifierType> getCurrencyA() {
80.33 + return currencyA;
80.34 + }
80.35 +
80.36 + public CurrencyValue<AmountType, IdentifierType> getCurrencyB() {
80.37 + return currencyB;
80.38 + }
80.39 +
80.40 + @Override
80.41 + public boolean equals(Object obj) {
80.42 + if (obj == null) {
80.43 + return false;
80.44 + }
80.45 + if (getClass() != obj.getClass()) {
80.46 + return false;
80.47 + }
80.48 + final ExchangeRateValue other = (ExchangeRateValue) obj;
80.49 + if (this.currencyA != other.currencyA && (this.currencyA == null || !this.currencyA.equals(other.currencyA))) {
80.50 + return false;
80.51 + }
80.52 + if (this.currencyB != other.currencyB && (this.currencyB == null || !this.currencyB.equals(other.currencyB))) {
80.53 + return false;
80.54 + }
80.55 + return true;
80.56 + }
80.57 +
80.58 + @Override
80.59 + public int hashCode() {
80.60 + int hash = 3;
80.61 + hash = 71 * hash + (this.currencyA != null ? this.currencyA.hashCode() : 0);
80.62 + hash = 71 * hash + (this.currencyB != null ? this.currencyB.hashCode() : 0);
80.63 + return hash;
80.64 + }
80.65 +
80.66 + /**
80.67 + * Creates new instance.
80.68 + * Generic types of the new instance are derived from types of the parameters.
80.69 + *
80.70 + * @param <AmountType> type of the currency amount
80.71 + * @param <IdentifierType> type of the currency identifier
80.72 + * @param currencyA one currency of the exchange rate
80.73 + * @param currencyB another currency of the exchange rate
80.74 + * @return new instance
80.75 + */
80.76 + public static <AmountType, IdentifierType> ExchangeRateValue<AmountType, IdentifierType> getExchangeRate(
80.77 + CurrencyValue<AmountType, IdentifierType> currencyA,
80.78 + CurrencyValue<AmountType, IdentifierType> currencyB) {
80.79 + return new ExchangeRateValue<AmountType, IdentifierType>(currencyA, currencyB);
80.80 + }
80.81 +}
81.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
81.2 +++ b/task4/solution11/test/org/apidesign/apifest08/test/Task1Test.java Sat Oct 11 23:38:46 2008 +0200
81.3 @@ -0,0 +1,157 @@
81.4 +package org.apidesign.apifest08.test;
81.5 +
81.6 +import junit.framework.TestCase;
81.7 +import org.apidesign.apifest08.currency.Convertor;
81.8 +import org.apidesign.apifest08.currency.CurrencyValue;
81.9 +
81.10 +/** Finish the Convertor API, and then write bodies of methods inside
81.11 + * of this class to match the given tasks. To fullfil your task, use the
81.12 + * API define in the <code>org.apidesign.apifest08.currency</code> package.
81.13 + * Do not you reflection, or other hacks as your code
81.14 + * shall run without any runtime permissions.
81.15 + */
81.16 +public class Task1Test extends TestCase {
81.17 + public Task1Test(String testName) {
81.18 + super(testName);
81.19 + }
81.20 +
81.21 + @Override
81.22 + protected void setUp() throws Exception {
81.23 + }
81.24 +
81.25 + @Override
81.26 + protected void tearDown() throws Exception {
81.27 + }
81.28 +
81.29 + //
81.30 + // Imagine that there are three parts of the whole system:
81.31 + // 1. there is someone who knows the current exchange rate
81.32 + // 2. there is someone who wants to do the conversion
81.33 + // 3. there is the API between 1. and 2. which allows them to communicate
81.34 + // Please design such API
81.35 + //
81.36 +
81.37 + /** Create convertor that understands two currencies, CZK and
81.38 + * USD. Make 1 USD == 17 CZK. This is a method provided for #1 group -
81.39 + * e.g. those that know the exchange rate. They somehow need to create
81.40 + * the objects from the API and tell them the exchange rate. The API itself
81.41 + * knows nothing about any rates, before the createCZKtoUSD method is called.
81.42 + *
81.43 + * Creation of the convertor shall not require subclassing of any class
81.44 + * or interface on the client side.
81.45 + *
81.46 + * @return prepared convertor ready for converting USD to CZK and CZK to USD
81.47 + */
81.48 + public static Convertor<Double, String> createCZKtoUSD() {
81.49 + return Convertor.getConvertorDoubleString(
81.50 + CurrencyValue.getCurrencyValue(1d, "USD"),
81.51 + CurrencyValue.getCurrencyValue(17d, "CZK")
81.52 + );
81.53 + }
81.54 +
81.55 + /** Create convertor that understands two currencies, CZK and
81.56 + * SKK. Make 100 SKK == 80 CZK. Again this is method for the #1 group -
81.57 + * it knows the exchange rate, and needs to use the API to create objects
81.58 + * with the exchange rate. Anyone shall be ready to call this method without
81.59 + * any other method being called previously. The API itself shall know
81.60 + * nothing about any rates, before this method is called.
81.61 + *
81.62 + * Creation of the convertor shall not require subclassing of any class
81.63 + * or interface on the client side.
81.64 + *
81.65 + * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
81.66 + */
81.67 + public static Convertor<Double, String> createSKKtoCZK() {
81.68 + return Convertor.getConvertorDoubleString(
81.69 + CurrencyValue.getCurrencyValue(100d, "SKK"),
81.70 + CurrencyValue.getCurrencyValue(80d, "CZK")
81.71 + );
81.72 + }
81.73 +
81.74 + //
81.75 + // now the methods for group #2 follow:
81.76 + // this group knows nothing about exchange rates, but knows how to use
81.77 + // the API to do conversions. It somehow (by calling one of the factory
81.78 + // methods) gets objects from the API and uses them to do the conversions.
81.79 + //
81.80 +
81.81 + /** Use the convertor from <code>createCZKtoUSD</code> method and do few conversions
81.82 + * with it.
81.83 + */
81.84 + public void testCurrencyCZKUSD() throws Exception {
81.85 + Convertor<Double, String> c = createCZKtoUSD();
81.86 +
81.87 + CurrencyValue<Double, String> result;
81.88 +
81.89 + // convert $5 to CZK using c:
81.90 + // assertEquals("Result is 85 CZK");
81.91 + result = c.convert("CZK", CurrencyValue.getCurrencyValue(5d, "USD"));
81.92 + assertEquals(CurrencyValue.getCurrencyValue(85d, "CZK"), result);
81.93 +
81.94 + // convert $8 to CZK
81.95 + // assertEquals("Result is 136 CZK");
81.96 + result = c.convert("CZK", CurrencyValue.getCurrencyValue(8d, "USD"));
81.97 + assertEquals(CurrencyValue.getCurrencyValue(136d, "CZK"), result);
81.98 +
81.99 + // convert 1003CZK to USD
81.100 + // assertEquals("Result is 59 USD");
81.101 + result = c.convert("USD", CurrencyValue.getCurrencyValue(1003d, "CZK"));
81.102 + assertEquals(CurrencyValue.getCurrencyValue(59d, "USD"), result);
81.103 + }
81.104 +
81.105 + /** Use the convertor from <code>createSKKtoCZK</code> method and do few conversions
81.106 + * with it.
81.107 + */
81.108 + public void testCurrencySKKCZK() throws Exception {
81.109 + Convertor<Double, String> c = createSKKtoCZK();
81.110 +
81.111 + CurrencyValue<Double, String> result;
81.112 +
81.113 + // convert 16CZK using c:
81.114 + // assertEquals("Result is 20 SKK");
81.115 + result = c.convert("SKK", CurrencyValue.getCurrencyValue(16d, "CZK"));
81.116 + assertEquals(CurrencyValue.getCurrencyValue(20d, "SKK"), result);
81.117 +
81.118 + // convert 500SKK to CZK
81.119 + // assertEquals("Result is 400 CZK");
81.120 + result = c.convert("CZK", CurrencyValue.getCurrencyValue(500d, "SKK"));
81.121 + assertEquals(CurrencyValue.getCurrencyValue(400d, "CZK"), result);
81.122 + }
81.123 +
81.124 + /** Verify that the CZK to USD convertor knows nothing about SKK.
81.125 + */
81.126 + public void testCannotConvertToSKKwithCZKUSDConvertor() throws Exception {
81.127 + Convertor<Double, String> c = createCZKtoUSD();
81.128 + try {
81.129 + // convert $5 to SKK, the API shall say this is not possible
81.130 + c.convert("SKK", CurrencyValue.getCurrencyValue(16d, "CZK"));
81.131 + fail("Should not convert");
81.132 + } catch (Exception e) {
81.133 + }
81.134 + try {
81.135 + // convert 500 SKK to CZK, the API shall say this is not possible
81.136 + c.convert("CZK", CurrencyValue.getCurrencyValue(500d, "SKK"));
81.137 + fail("Should not convert");
81.138 + } catch (Exception e) {
81.139 + }
81.140 +
81.141 + }
81.142 +
81.143 + /** Verify that the CZK to SKK convertor knows nothing about USD.
81.144 + */
81.145 + public void testCannotConvertToUSDwithSKKCZKConvertor() throws Exception {
81.146 + Convertor<Double, String> c = createSKKtoCZK();
81.147 + try {
81.148 + // convert $5 to SKK, the API shall say this is not possible
81.149 + c.convert("SKK", CurrencyValue.getCurrencyValue(5d, "USD"));
81.150 + fail("Should not convert");
81.151 + } catch (Exception e) {
81.152 + }
81.153 + try {
81.154 + // convert 500 CZK to USD, the API shall say this is not possible
81.155 + c.convert("USD", CurrencyValue.getCurrencyValue(500d, "CZK"));
81.156 + fail("Should not convert");
81.157 + } catch (Exception e) {
81.158 + }
81.159 + }
81.160 +}
82.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
82.2 +++ b/task4/solution11/test/org/apidesign/apifest08/test/Task2Test.java Sat Oct 11 23:38:46 2008 +0200
82.3 @@ -0,0 +1,140 @@
82.4 +package org.apidesign.apifest08.test;
82.5 +
82.6 +import java.util.ArrayList;
82.7 +import java.util.Collection;
82.8 +import junit.framework.TestCase;
82.9 +import org.apidesign.apifest08.currency.Convertor;
82.10 +import org.apidesign.apifest08.currency.CurrencyValue;
82.11 +import org.apidesign.apifest08.currency.ExchangeRateValue;
82.12 +
82.13 +/** There are many currencies around the world and many banks manipulate
82.14 + * with more than one or two at the same time. As banks are usually the
82.15 + * best paying clients, which is true even in case of your Convertor API,
82.16 + * it is reasonable to listen to their requests.
82.17 + * <p>
82.18 + * The quest for today is to enhance your existing convertor API to hold
82.19 + * information about many currencies and allow conversions between any of them.
82.20 + * Also, as conversion rates for diferent currencies usually arise from various
82.21 + * bank departments, there is another important need. There is a need to
82.22 + * compose two convertors into one by merging all the information about
82.23 + * currencies they know about.
82.24 + */
82.25 +public class Task2Test extends TestCase {
82.26 +
82.27 + public Task2Test(String testName) {
82.28 + super(testName);
82.29 + }
82.30 +
82.31 + @Override
82.32 + protected void setUp() throws Exception {
82.33 + }
82.34 +
82.35 + @Override
82.36 + protected void tearDown() throws Exception {
82.37 + }
82.38 +
82.39 + // As in Task1Test, keep in mind, that there are three parts
82.40 + // of the whole system:
82.41 + // 1. there is someone who knows the current exchange rate
82.42 + // 2. there is someone who wants to do the conversion
82.43 + // 3. there is the API between 1. and 2. which allows them to communicate
82.44 + //
82.45 + // Please backward compatibly enhance your existing API to support following
82.46 + // usecases:
82.47 + //
82.48 + /** Create convertor that understands two currencies, CZK and
82.49 + * SKK. Make 100 SKK == 75 CZK. This is method for the group of users that
82.50 + * knows the exchange rate, and needs to use the API to create objects
82.51 + * with the exchange rate. Anyone shall be ready to call this method without
82.52 + * any other method being called previously. The API itself shall know
82.53 + * nothing about any rates, before this method is called.
82.54 + */
82.55 + public static Convertor<Double, String> createTripleConvertor() {
82.56 + // Rates: 1USD = 15CZK
82.57 + // Rates: 1USD = 20SKK
82.58 + // Rates: 75CZK = 100SKK
82.59 + Collection<ExchangeRateValue<Double, String>> exchangeRates =
82.60 + new ArrayList<ExchangeRateValue<Double, String>>();
82.61 + exchangeRates.add(ExchangeRateValue.getExchangeRate(
82.62 + CurrencyValue.getCurrencyValue(1d, "USD"),
82.63 + CurrencyValue.getCurrencyValue(15d, "CZK")));
82.64 + exchangeRates.add(ExchangeRateValue.getExchangeRate(
82.65 + CurrencyValue.getCurrencyValue(1d, "USD"),
82.66 + CurrencyValue.getCurrencyValue(20d, "SKK")));
82.67 + exchangeRates.add(ExchangeRateValue.getExchangeRate(
82.68 + CurrencyValue.getCurrencyValue(75d, "CZK"),
82.69 + CurrencyValue.getCurrencyValue(100d, "SKK")));
82.70 + return Convertor.getConvertorDoubleString(exchangeRates);
82.71 + }
82.72 +
82.73 + /** Define convertor that understands three currencies. Use it.
82.74 + */
82.75 + public void testConvertorForUSDandCZKandSKK() throws Exception {
82.76 + Convertor<Double, String> c = createTripleConvertor();
82.77 +
82.78 + CurrencyValue<Double, String> result;
82.79 + // convert $5 to CZK using c:
82.80 + // assertEquals("Result is 75 CZK");
82.81 + result = c.convert("CZK", CurrencyValue.getCurrencyValue(5d, "USD"));
82.82 + assertEquals(CurrencyValue.getCurrencyValue(75d, "CZK"), result);
82.83 +
82.84 + // convert $5 to SKK using c:
82.85 + // assertEquals("Result is 100 SKK");
82.86 + result = c.convert("SKK", CurrencyValue.getCurrencyValue(5d, "USD"));
82.87 + assertEquals(CurrencyValue.getCurrencyValue(100d, "SKK"), result);
82.88 +
82.89 + // convert 200SKK to CZK using c:
82.90 + // assertEquals("Result is 150 CZK");
82.91 + result = c.convert("CZK", CurrencyValue.getCurrencyValue(200d, "SKK"));
82.92 + assertEquals(CurrencyValue.getCurrencyValue(150d, "CZK"), result);
82.93 +
82.94 + // convert 200SKK to USK using c:
82.95 + // assertEquals("Result is 10 USD");
82.96 + result = c.convert("USD", CurrencyValue.getCurrencyValue(200d, "SKK"));
82.97 + assertEquals(CurrencyValue.getCurrencyValue(10d, "USD"), result);
82.98 + }
82.99 +
82.100 + /** Merge all currency rates of convertor 1 with convertor 2.
82.101 + * Implement this using your API, preferably this method just delegates
82.102 + * into some API method which does the actual work, without requiring
82.103 + * API clients to code anything complex.
82.104 + */
82.105 + public static Convertor<Double, String> merge(Convertor<Double, String> one, Convertor<Double, String> two) {
82.106 + return Convertor.mergeConvertorsDoubleString(one, two);
82.107 + }
82.108 +
82.109 + /** Join the convertors from previous task, Task1Test and show that it
82.110 + * can be used to do reasonable conversions.
82.111 + */
82.112 + public void testConvertorComposition() throws Exception {
82.113 + Convertor<Double, String> c = merge(
82.114 + Task1Test.createCZKtoUSD(),
82.115 + Task1Test.createSKKtoCZK());
82.116 +
82.117 + CurrencyValue<Double, String> result;
82.118 + // convert $5 to CZK using c:
82.119 + // assertEquals("Result is 85 CZK");
82.120 + result = c.convert("CZK", CurrencyValue.getCurrencyValue(5d, "USD"));
82.121 + assertEquals(CurrencyValue.getCurrencyValue(85d, "CZK"), result);
82.122 +
82.123 + // convert $8 to CZK using c:
82.124 + // assertEquals("Result is 136 CZK");
82.125 + result = c.convert("CZK", CurrencyValue.getCurrencyValue(8d, "USD"));
82.126 + assertEquals(CurrencyValue.getCurrencyValue(136d, "CZK"), result);
82.127 +
82.128 + // convert 1003CZK to USD using c:
82.129 + // assertEquals("Result is 59 USD");
82.130 + result = c.convert("USD", CurrencyValue.getCurrencyValue(1003d, "CZK"));
82.131 + assertEquals(CurrencyValue.getCurrencyValue(59d, "USD"), result);
82.132 +
82.133 + // convert 16CZK using c:
82.134 + // assertEquals("Result is 20 SKK");
82.135 + result = c.convert("SKK", CurrencyValue.getCurrencyValue(16d, "CZK"));
82.136 + assertEquals(CurrencyValue.getCurrencyValue(20d, "SKK"), result);
82.137 +
82.138 + // convert 500SKK to CZK using c:
82.139 + // assertEquals("Result is 400 CZK");
82.140 + result = c.convert("CZK", CurrencyValue.getCurrencyValue(500d, "SKK"));
82.141 + assertEquals(CurrencyValue.getCurrencyValue(400d, "CZK"), result);
82.142 + }
82.143 +}
83.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
83.2 +++ b/task4/solution11/test/org/apidesign/apifest08/test/Task3Test.java Sat Oct 11 23:38:46 2008 +0200
83.3 @@ -0,0 +1,136 @@
83.4 +package org.apidesign.apifest08.test;
83.5 +
83.6 +import junit.framework.TestCase;
83.7 +import org.apidesign.apifest08.currency.Convertor;
83.8 +import org.apidesign.apifest08.currency.CurrencyValue;
83.9 +import org.apidesign.apifest08.currency.ExchangeRateDataSource;
83.10 +import org.apidesign.apifest08.currency.ExchangeRateProvider;
83.11 +import org.apidesign.apifest08.currency.ExchangeRateProvider.ExchangeRateRequest;
83.12 +import org.apidesign.apifest08.currency.ExchangeRateProvider.ExchangeRateResponse;
83.13 +import org.apidesign.apifest08.currency.ExchangeRateValue;
83.14 +
83.15 +/** The exchange rates are not always the same. They are changing. Day by day,
83.16 + * hour by hour, minute by minute. For every bank it is important to always
83.17 + * have the actual exchange rate available in the system. That is why let's
83.18 + * create a pluggable convertor that will always have up to date value of its
83.19 + * exchange rate.
83.20 + * <p>
83.21 + * The quest for today is to allow 3rd party developer to write a convertor
83.22 + * that adjusts its exchange rate everytime it is queried. This convertor is
83.23 + * written by independent vendor, the vendor knows only your Convertor API,
83.24 + * he does not know how the whole system looks and how the convertor is supposed
83.25 + * to be used.
83.26 + */
83.27 +public class Task3Test extends TestCase {
83.28 +
83.29 + public Task3Test(String testName) {
83.30 + super(testName);
83.31 + }
83.32 +
83.33 + @Override
83.34 + protected void setUp() throws Exception {
83.35 + }
83.36 +
83.37 + @Override
83.38 + protected void tearDown() throws Exception {
83.39 + }
83.40 +
83.41 + // Backward compatibly enhance your existing API to support following
83.42 + // usecases:
83.43 + //
83.44 + /** Without knowing anything about the surrounding system, write an
83.45 + * implementation of convertor that will return different rates everytime
83.46 + * it is queried. Convert USD to CZK and vice versa. Start with the rate of
83.47 + * 1USD = 16CZK and adjust it in favor of CZK by 0.01 CZK with every query.
83.48 + * As soon as you reach 1USD = 15CZK adjust it by 0.01 CZK in favor of USD
83.49 + * until you reach 1USD = 16CZK
83.50 + *
83.51 + * @return new instance of "online" USD and CZK convertor starting with rate 1USD = 16CZK
83.52 + */
83.53 + public static Convertor<Double, String> createOnlineCZKUSDConvertor() {
83.54 + // initial rate: 1USD = 16CZK
83.55 + // 2nd query 1USD = 15.99CZK
83.56 + // 3rd query 1USD = 15.98CZK
83.57 + // until 1USD = 15.00CZK
83.58 + // then 1USD = 15.01CZK
83.59 + // then 1USD = 15.02CZK
83.60 + // and so on and on up to 1USD = 16CZK
83.61 + // and then another round to 15, etc.
83.62 + return Convertor.getConvertorDataSourceDoubleString(
83.63 + ExchangeRateDataSource.getExchangeRateDataSource(
83.64 + "USD", "CZK", new ExchangeRateProvider<Double, String>() {
83.65 +
83.66 + double currentRate = 16d;
83.67 + double step;
83.68 +
83.69 + public void getExchangeRate(ExchangeRateRequest<Double, String> request,
83.70 + ExchangeRateResponse<Double, String> response) {
83.71 + if ((request.getCurrencyAIdentifier().equals("CZK") && request.getCurrencyBIdentifier().equals("USD")) ||
83.72 + (request.getCurrencyAIdentifier().equals("USD") && request.getCurrencyBIdentifier().equals("CZK"))) {
83.73 + response.setExchangeRate(ExchangeRateValue.getExchangeRate(
83.74 + CurrencyValue.getCurrencyValue(1d, "USD"),
83.75 + CurrencyValue.getCurrencyValue(currentRate, "CZK")));
83.76 +
83.77 + if (currentRate == 16d) {
83.78 + step = -0.01;
83.79 + }
83.80 + if (currentRate == 15d) {
83.81 + step = 0.01;
83.82 + }
83.83 + currentRate += step;
83.84 + } else {
83.85 + throw new IllegalArgumentException("No exchange rate for requested currencies!");
83.86 + }
83.87 + }
83.88 + }));
83.89 + }
83.90 +
83.91 + public void testFewQueriesForOnlineConvertor() {
83.92 + Convertor<Double, String> c = createOnlineCZKUSDConvertor();
83.93 + doFewQueriesForOnlineConvertor(c);
83.94 + }
83.95 +
83.96 + static void doFewQueriesForOnlineConvertor(Convertor<Double, String> c) {
83.97 + CurrencyValue<Double, String> result;
83.98 + // convert $5 to CZK using c:
83.99 + //assertEquals("Result is 80 CZK");
83.100 + result = c.convert("CZK", CurrencyValue.getCurrencyValue(5d, "USD"));
83.101 + assertEquals(CurrencyValue.getCurrencyValue(80d, "CZK"), result);
83.102 +
83.103 + // convert $8 to CZK using c:
83.104 + //assertEquals("Result is 127.92 CZK");
83.105 + result = c.convert("CZK", CurrencyValue.getCurrencyValue(8d, "USD"));
83.106 + assertEquals(CurrencyValue.getCurrencyValue(127.92d, "CZK"), result);
83.107 +
83.108 + // convert $1 to CZK using c:
83.109 + //assertEquals("Result is 15.98 CZK");
83.110 + result = c.convert("CZK", CurrencyValue.getCurrencyValue(1d, "USD"));
83.111 + assertEquals(CurrencyValue.getCurrencyValue(15.98d, "CZK"), result);
83.112 +
83.113 + // convert 15.97CZK to USD using c:
83.114 + //assertEquals("Result is 1$");
83.115 + result = c.convert("USD", CurrencyValue.getCurrencyValue(15.97d, "CZK"));
83.116 + assertEquals(CurrencyValue.getCurrencyValue(1d, "USD"), result);
83.117 + }
83.118 +
83.119 + /** Join the convertors and show they behave sane.
83.120 + */
83.121 + public void testOnlineConvertorComposition() throws Exception {
83.122 + Convertor<Double, String> c = Task2Test.merge(
83.123 + createOnlineCZKUSDConvertor(),
83.124 + Task1Test.createSKKtoCZK());
83.125 +
83.126 + CurrencyValue<Double, String> result;
83.127 + // convert 16CZK to SKK using c:
83.128 + // assertEquals("Result is 20 SKK");
83.129 + result = c.convert("SKK", CurrencyValue.getCurrencyValue(16d, "CZK"));
83.130 + assertEquals(CurrencyValue.getCurrencyValue(20d, "SKK"), result);
83.131 +
83.132 + // convert 500SKK to CZK using c:
83.133 + // assertEquals("Result is 400 CZK");
83.134 + result = c.convert("CZK", CurrencyValue.getCurrencyValue(500d, "SKK"));
83.135 + assertEquals(CurrencyValue.getCurrencyValue(400d, "CZK"), result);
83.136 +
83.137 + doFewQueriesForOnlineConvertor(c);
83.138 + }
83.139 +}
84.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
84.2 +++ b/task4/solution12/build.xml Sat Oct 11 23:38:46 2008 +0200
84.3 @@ -0,0 +1,69 @@
84.4 +<?xml version="1.0" encoding="UTF-8"?>
84.5 +<!-- You may freely edit this file. See commented blocks below for -->
84.6 +<!-- some examples of how to customize the build. -->
84.7 +<!-- (If you delete it and reopen the project it will be recreated.) -->
84.8 +<project name="currency" default="default" basedir=".">
84.9 + <description>Builds, tests, and runs the project.</description>
84.10 + <import file="nbproject/build-impl.xml"/>
84.11 + <!--
84.12 +
84.13 + There exist several targets which are by default empty and which can be
84.14 + used for execution of your tasks. These targets are usually executed
84.15 + before and after some main targets. They are:
84.16 +
84.17 + -pre-init: called before initialization of project properties
84.18 + -post-init: called after initialization of project properties
84.19 + -pre-compile: called before javac compilation
84.20 + -post-compile: called after javac compilation
84.21 + -pre-compile-single: called before javac compilation of single file
84.22 + -post-compile-single: called after javac compilation of single file
84.23 + -pre-compile-test: called before javac compilation of JUnit tests
84.24 + -post-compile-test: called after javac compilation of JUnit tests
84.25 + -pre-compile-test-single: called before javac compilation of single JUnit test
84.26 + -post-compile-test-single: called after javac compilation of single JUunit test
84.27 + -pre-jar: called before JAR building
84.28 + -post-jar: called after JAR building
84.29 + -post-clean: called after cleaning build products
84.30 +
84.31 + (Targets beginning with '-' are not intended to be called on their own.)
84.32 +
84.33 + Example of inserting an obfuscator after compilation could look like this:
84.34 +
84.35 + <target name="-post-compile">
84.36 + <obfuscate>
84.37 + <fileset dir="${build.classes.dir}"/>
84.38 + </obfuscate>
84.39 + </target>
84.40 +
84.41 + For list of available properties check the imported
84.42 + nbproject/build-impl.xml file.
84.43 +
84.44 +
84.45 + Another way to customize the build is by overriding existing main targets.
84.46 + The targets of interest are:
84.47 +
84.48 + -init-macrodef-javac: defines macro for javac compilation
84.49 + -init-macrodef-junit: defines macro for junit execution
84.50 + -init-macrodef-debug: defines macro for class debugging
84.51 + -init-macrodef-java: defines macro for class execution
84.52 + -do-jar-with-manifest: JAR building (if you are using a manifest)
84.53 + -do-jar-without-manifest: JAR building (if you are not using a manifest)
84.54 + run: execution of project
84.55 + -javadoc-build: Javadoc generation
84.56 + test-report: JUnit report generation
84.57 +
84.58 + An example of overriding the target for project execution could look like this:
84.59 +
84.60 + <target name="run" depends="currency-impl.jar">
84.61 + <exec dir="bin" executable="launcher.exe">
84.62 + <arg file="${dist.jar}"/>
84.63 + </exec>
84.64 + </target>
84.65 +
84.66 + Notice that the overridden target depends on the jar target and not only on
84.67 + the compile target as the regular run target does. Again, for a list of available
84.68 + properties which you can use, check the target you are overriding in the
84.69 + nbproject/build-impl.xml file.
84.70 +
84.71 + -->
84.72 +</project>
85.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
85.2 +++ b/task4/solution12/nbproject/build-impl.xml Sat Oct 11 23:38:46 2008 +0200
85.3 @@ -0,0 +1,642 @@
85.4 +<?xml version="1.0" encoding="UTF-8"?>
85.5 +<!--
85.6 +*** GENERATED FROM project.xml - DO NOT EDIT ***
85.7 +*** EDIT ../build.xml INSTEAD ***
85.8 +
85.9 +For the purpose of easier reading the script
85.10 +is divided into following sections:
85.11 +
85.12 + - initialization
85.13 + - compilation
85.14 + - jar
85.15 + - execution
85.16 + - debugging
85.17 + - javadoc
85.18 + - junit compilation
85.19 + - junit execution
85.20 + - junit debugging
85.21 + - applet
85.22 + - cleanup
85.23 +
85.24 + -->
85.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">
85.26 + <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
85.27 + <!--
85.28 + ======================
85.29 + INITIALIZATION SECTION
85.30 + ======================
85.31 + -->
85.32 + <target name="-pre-init">
85.33 + <!-- Empty placeholder for easier customization. -->
85.34 + <!-- You can override this target in the ../build.xml file. -->
85.35 + </target>
85.36 + <target depends="-pre-init" name="-init-private">
85.37 + <property file="nbproject/private/config.properties"/>
85.38 + <property file="nbproject/private/configs/${config}.properties"/>
85.39 + <property file="nbproject/private/private.properties"/>
85.40 + </target>
85.41 + <target depends="-pre-init,-init-private" name="-init-user">
85.42 + <property file="${user.properties.file}"/>
85.43 + <!-- The two properties below are usually overridden -->
85.44 + <!-- by the active platform. Just a fallback. -->
85.45 + <property name="default.javac.source" value="1.4"/>
85.46 + <property name="default.javac.target" value="1.4"/>
85.47 + </target>
85.48 + <target depends="-pre-init,-init-private,-init-user" name="-init-project">
85.49 + <property file="nbproject/configs/${config}.properties"/>
85.50 + <property file="nbproject/project.properties"/>
85.51 + </target>
85.52 + <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
85.53 + <available file="${manifest.file}" property="manifest.available"/>
85.54 + <condition property="manifest.available+main.class">
85.55 + <and>
85.56 + <isset property="manifest.available"/>
85.57 + <isset property="main.class"/>
85.58 + <not>
85.59 + <equals arg1="${main.class}" arg2="" trim="true"/>
85.60 + </not>
85.61 + </and>
85.62 + </condition>
85.63 + <condition property="manifest.available+main.class+mkdist.available">
85.64 + <and>
85.65 + <istrue value="${manifest.available+main.class}"/>
85.66 + <isset property="libs.CopyLibs.classpath"/>
85.67 + </and>
85.68 + </condition>
85.69 + <condition property="have.tests">
85.70 + <or>
85.71 + <available file="${test.src.dir}"/>
85.72 + </or>
85.73 + </condition>
85.74 + <condition property="have.sources">
85.75 + <or>
85.76 + <available file="${src.dir}"/>
85.77 + </or>
85.78 + </condition>
85.79 + <condition property="netbeans.home+have.tests">
85.80 + <and>
85.81 + <isset property="netbeans.home"/>
85.82 + <isset property="have.tests"/>
85.83 + </and>
85.84 + </condition>
85.85 + <condition property="no.javadoc.preview">
85.86 + <and>
85.87 + <isset property="javadoc.preview"/>
85.88 + <isfalse value="${javadoc.preview}"/>
85.89 + </and>
85.90 + </condition>
85.91 + <property name="run.jvmargs" value=""/>
85.92 + <property name="javac.compilerargs" value=""/>
85.93 + <property name="work.dir" value="${basedir}"/>
85.94 + <condition property="no.deps">
85.95 + <and>
85.96 + <istrue value="${no.dependencies}"/>
85.97 + </and>
85.98 + </condition>
85.99 + <property name="javac.debug" value="true"/>
85.100 + <property name="javadoc.preview" value="true"/>
85.101 + <property name="application.args" value=""/>
85.102 + <property name="source.encoding" value="${file.encoding}"/>
85.103 + <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
85.104 + <and>
85.105 + <isset property="javadoc.encoding"/>
85.106 + <not>
85.107 + <equals arg1="${javadoc.encoding}" arg2=""/>
85.108 + </not>
85.109 + </and>
85.110 + </condition>
85.111 + <property name="javadoc.encoding.used" value="${source.encoding}"/>
85.112 + <property name="includes" value="**"/>
85.113 + <property name="excludes" value=""/>
85.114 + <property name="do.depend" value="false"/>
85.115 + <condition property="do.depend.true">
85.116 + <istrue value="${do.depend}"/>
85.117 + </condition>
85.118 + <condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
85.119 + <and>
85.120 + <isset property="jaxws.endorsed.dir"/>
85.121 + <available file="nbproject/jaxws-build.xml"/>
85.122 + </and>
85.123 + </condition>
85.124 + </target>
85.125 + <target name="-post-init">
85.126 + <!-- Empty placeholder for easier customization. -->
85.127 + <!-- You can override this target in the ../build.xml file. -->
85.128 + </target>
85.129 + <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
85.130 + <fail unless="src.dir">Must set src.dir</fail>
85.131 + <fail unless="test.src.dir">Must set test.src.dir</fail>
85.132 + <fail unless="build.dir">Must set build.dir</fail>
85.133 + <fail unless="dist.dir">Must set dist.dir</fail>
85.134 + <fail unless="build.classes.dir">Must set build.classes.dir</fail>
85.135 + <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
85.136 + <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
85.137 + <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
85.138 + <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
85.139 + <fail unless="dist.jar">Must set dist.jar</fail>
85.140 + </target>
85.141 + <target name="-init-macrodef-property">
85.142 + <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
85.143 + <attribute name="name"/>
85.144 + <attribute name="value"/>
85.145 + <sequential>
85.146 + <property name="@{name}" value="${@{value}}"/>
85.147 + </sequential>
85.148 + </macrodef>
85.149 + </target>
85.150 + <target name="-init-macrodef-javac">
85.151 + <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
85.152 + <attribute default="${src.dir}" name="srcdir"/>
85.153 + <attribute default="${build.classes.dir}" name="destdir"/>
85.154 + <attribute default="${javac.classpath}" name="classpath"/>
85.155 + <attribute default="${includes}" name="includes"/>
85.156 + <attribute default="${excludes}" name="excludes"/>
85.157 + <attribute default="${javac.debug}" name="debug"/>
85.158 + <attribute default="" name="sourcepath"/>
85.159 + <element name="customize" optional="true"/>
85.160 + <sequential>
85.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}">
85.162 + <classpath>
85.163 + <path path="@{classpath}"/>
85.164 + </classpath>
85.165 + <compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
85.166 + <customize/>
85.167 + </javac>
85.168 + </sequential>
85.169 + </macrodef>
85.170 + <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
85.171 + <attribute default="${src.dir}" name="srcdir"/>
85.172 + <attribute default="${build.classes.dir}" name="destdir"/>
85.173 + <attribute default="${javac.classpath}" name="classpath"/>
85.174 + <sequential>
85.175 + <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
85.176 + <classpath>
85.177 + <path path="@{classpath}"/>
85.178 + </classpath>
85.179 + </depend>
85.180 + </sequential>
85.181 + </macrodef>
85.182 + <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
85.183 + <attribute default="${build.classes.dir}" name="destdir"/>
85.184 + <sequential>
85.185 + <fail unless="javac.includes">Must set javac.includes</fail>
85.186 + <pathconvert pathsep="," property="javac.includes.binary">
85.187 + <path>
85.188 + <filelist dir="@{destdir}" files="${javac.includes}"/>
85.189 + </path>
85.190 + <globmapper from="*.java" to="*.class"/>
85.191 + </pathconvert>
85.192 + <delete>
85.193 + <files includes="${javac.includes.binary}"/>
85.194 + </delete>
85.195 + </sequential>
85.196 + </macrodef>
85.197 + </target>
85.198 + <target name="-init-macrodef-junit">
85.199 + <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
85.200 + <attribute default="${includes}" name="includes"/>
85.201 + <attribute default="${excludes}" name="excludes"/>
85.202 + <attribute default="**" name="testincludes"/>
85.203 + <sequential>
85.204 + <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
85.205 + <batchtest todir="${build.test.results.dir}">
85.206 + <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
85.207 + <filename name="@{testincludes}"/>
85.208 + </fileset>
85.209 + </batchtest>
85.210 + <classpath>
85.211 + <path path="${run.test.classpath}"/>
85.212 + </classpath>
85.213 + <syspropertyset>
85.214 + <propertyref prefix="test-sys-prop."/>
85.215 + <mapper from="test-sys-prop.*" to="*" type="glob"/>
85.216 + </syspropertyset>
85.217 + <formatter type="brief" usefile="false"/>
85.218 + <formatter type="xml"/>
85.219 + <jvmarg line="${run.jvmargs}"/>
85.220 + </junit>
85.221 + </sequential>
85.222 + </macrodef>
85.223 + </target>
85.224 + <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
85.225 + <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
85.226 + <attribute default="${main.class}" name="name"/>
85.227 + <attribute default="${debug.classpath}" name="classpath"/>
85.228 + <attribute default="" name="stopclassname"/>
85.229 + <sequential>
85.230 + <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
85.231 + <classpath>
85.232 + <path path="@{classpath}"/>
85.233 + </classpath>
85.234 + </nbjpdastart>
85.235 + </sequential>
85.236 + </macrodef>
85.237 + <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
85.238 + <attribute default="${build.classes.dir}" name="dir"/>
85.239 + <sequential>
85.240 + <nbjpdareload>
85.241 + <fileset dir="@{dir}" includes="${fix.classes}">
85.242 + <include name="${fix.includes}*.class"/>
85.243 + </fileset>
85.244 + </nbjpdareload>
85.245 + </sequential>
85.246 + </macrodef>
85.247 + </target>
85.248 + <target name="-init-debug-args">
85.249 + <property name="version-output" value="java version "${ant.java.version}"/>
85.250 + <condition property="have-jdk-older-than-1.4">
85.251 + <or>
85.252 + <contains string="${version-output}" substring="java version "1.0"/>
85.253 + <contains string="${version-output}" substring="java version "1.1"/>
85.254 + <contains string="${version-output}" substring="java version "1.2"/>
85.255 + <contains string="${version-output}" substring="java version "1.3"/>
85.256 + </or>
85.257 + </condition>
85.258 + <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
85.259 + <istrue value="${have-jdk-older-than-1.4}"/>
85.260 + </condition>
85.261 + <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
85.262 + <os family="windows"/>
85.263 + </condition>
85.264 + <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
85.265 + <isset property="debug.transport"/>
85.266 + </condition>
85.267 + </target>
85.268 + <target depends="-init-debug-args" name="-init-macrodef-debug">
85.269 + <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
85.270 + <attribute default="${main.class}" name="classname"/>
85.271 + <attribute default="${debug.classpath}" name="classpath"/>
85.272 + <element name="customize" optional="true"/>
85.273 + <sequential>
85.274 + <java classname="@{classname}" dir="${work.dir}" fork="true">
85.275 + <jvmarg line="${debug-args-line}"/>
85.276 + <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
85.277 + <jvmarg line="${run.jvmargs}"/>
85.278 + <classpath>
85.279 + <path path="@{classpath}"/>
85.280 + </classpath>
85.281 + <syspropertyset>
85.282 + <propertyref prefix="run-sys-prop."/>
85.283 + <mapper from="run-sys-prop.*" to="*" type="glob"/>
85.284 + </syspropertyset>
85.285 + <customize/>
85.286 + </java>
85.287 + </sequential>
85.288 + </macrodef>
85.289 + </target>
85.290 + <target name="-init-macrodef-java">
85.291 + <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
85.292 + <attribute default="${main.class}" name="classname"/>
85.293 + <element name="customize" optional="true"/>
85.294 + <sequential>
85.295 + <java classname="@{classname}" dir="${work.dir}" fork="true">
85.296 + <jvmarg line="${run.jvmargs}"/>
85.297 + <classpath>
85.298 + <path path="${run.classpath}"/>
85.299 + </classpath>
85.300 + <syspropertyset>
85.301 + <propertyref prefix="run-sys-prop."/>
85.302 + <mapper from="run-sys-prop.*" to="*" type="glob"/>
85.303 + </syspropertyset>
85.304 + <customize/>
85.305 + </java>
85.306 + </sequential>
85.307 + </macrodef>
85.308 + </target>
85.309 + <target name="-init-presetdef-jar">
85.310 + <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
85.311 + <jar compress="${jar.compress}" jarfile="${dist.jar}">
85.312 + <j2seproject1:fileset dir="${build.classes.dir}"/>
85.313 + </jar>
85.314 + </presetdef>
85.315 + </target>
85.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"/>
85.317 + <!--
85.318 + ===================
85.319 + COMPILATION SECTION
85.320 + ===================
85.321 + -->
85.322 + <target depends="init" name="deps-jar" unless="no.deps"/>
85.323 + <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
85.324 + <target depends="init" name="-check-automatic-build">
85.325 + <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
85.326 + </target>
85.327 + <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
85.328 + <antcall target="clean"/>
85.329 + </target>
85.330 + <target depends="init,deps-jar" name="-pre-pre-compile">
85.331 + <mkdir dir="${build.classes.dir}"/>
85.332 + </target>
85.333 + <target name="-pre-compile">
85.334 + <!-- Empty placeholder for easier customization. -->
85.335 + <!-- You can override this target in the ../build.xml file. -->
85.336 + </target>
85.337 + <target if="do.depend.true" name="-compile-depend">
85.338 + <j2seproject3:depend/>
85.339 + </target>
85.340 + <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
85.341 + <j2seproject3:javac/>
85.342 + <copy todir="${build.classes.dir}">
85.343 + <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
85.344 + </copy>
85.345 + </target>
85.346 + <target name="-post-compile">
85.347 + <!-- Empty placeholder for easier customization. -->
85.348 + <!-- You can override this target in the ../build.xml file. -->
85.349 + </target>
85.350 + <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
85.351 + <target name="-pre-compile-single">
85.352 + <!-- Empty placeholder for easier customization. -->
85.353 + <!-- You can override this target in the ../build.xml file. -->
85.354 + </target>
85.355 + <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
85.356 + <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
85.357 + <j2seproject3:force-recompile/>
85.358 + <j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
85.359 + </target>
85.360 + <target name="-post-compile-single">
85.361 + <!-- Empty placeholder for easier customization. -->
85.362 + <!-- You can override this target in the ../build.xml file. -->
85.363 + </target>
85.364 + <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
85.365 + <!--
85.366 + ====================
85.367 + JAR BUILDING SECTION
85.368 + ====================
85.369 + -->
85.370 + <target depends="init" name="-pre-pre-jar">
85.371 + <dirname file="${dist.jar}" property="dist.jar.dir"/>
85.372 + <mkdir dir="${dist.jar.dir}"/>
85.373 + </target>
85.374 + <target name="-pre-jar">
85.375 + <!-- Empty placeholder for easier customization. -->
85.376 + <!-- You can override this target in the ../build.xml file. -->
85.377 + </target>
85.378 + <target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
85.379 + <j2seproject1:jar/>
85.380 + </target>
85.381 + <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
85.382 + <j2seproject1:jar manifest="${manifest.file}"/>
85.383 + </target>
85.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">
85.385 + <j2seproject1:jar manifest="${manifest.file}">
85.386 + <j2seproject1:manifest>
85.387 + <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
85.388 + </j2seproject1:manifest>
85.389 + </j2seproject1:jar>
85.390 + <echo>To run this application from the command line without Ant, try:</echo>
85.391 + <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
85.392 + <property location="${dist.jar}" name="dist.jar.resolved"/>
85.393 + <pathconvert property="run.classpath.with.dist.jar">
85.394 + <path path="${run.classpath}"/>
85.395 + <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
85.396 + </pathconvert>
85.397 + <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
85.398 + </target>
85.399 + <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
85.400 + <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
85.401 + <pathconvert property="run.classpath.without.build.classes.dir">
85.402 + <path path="${run.classpath}"/>
85.403 + <map from="${build.classes.dir.resolved}" to=""/>
85.404 + </pathconvert>
85.405 + <pathconvert pathsep=" " property="jar.classpath">
85.406 + <path path="${run.classpath.without.build.classes.dir}"/>
85.407 + <chainedmapper>
85.408 + <flattenmapper/>
85.409 + <globmapper from="*" to="lib/*"/>
85.410 + </chainedmapper>
85.411 + </pathconvert>
85.412 + <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
85.413 + <copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
85.414 + <fileset dir="${build.classes.dir}"/>
85.415 + <manifest>
85.416 + <attribute name="Main-Class" value="${main.class}"/>
85.417 + <attribute name="Class-Path" value="${jar.classpath}"/>
85.418 + </manifest>
85.419 + </copylibs>
85.420 + <echo>To run this application from the command line without Ant, try:</echo>
85.421 + <property location="${dist.jar}" name="dist.jar.resolved"/>
85.422 + <echo>java -jar "${dist.jar.resolved}"</echo>
85.423 + </target>
85.424 + <target name="-post-jar">
85.425 + <!-- Empty placeholder for easier customization. -->
85.426 + <!-- You can override this target in the ../build.xml file. -->
85.427 + </target>
85.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"/>
85.429 + <!--
85.430 + =================
85.431 + EXECUTION SECTION
85.432 + =================
85.433 + -->
85.434 + <target depends="init,compile" description="Run a main class." name="run">
85.435 + <j2seproject1:java>
85.436 + <customize>
85.437 + <arg line="${application.args}"/>
85.438 + </customize>
85.439 + </j2seproject1:java>
85.440 + </target>
85.441 + <target name="-do-not-recompile">
85.442 + <property name="javac.includes.binary" value=""/>
85.443 + </target>
85.444 + <target depends="init,-do-not-recompile,compile-single" name="run-single">
85.445 + <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
85.446 + <j2seproject1:java classname="${run.class}"/>
85.447 + </target>
85.448 + <!--
85.449 + =================
85.450 + DEBUGGING SECTION
85.451 + =================
85.452 + -->
85.453 + <target depends="init" if="netbeans.home" name="-debug-start-debugger">
85.454 + <j2seproject1:nbjpdastart name="${debug.class}"/>
85.455 + </target>
85.456 + <target depends="init,compile" name="-debug-start-debuggee">
85.457 + <j2seproject3:debug>
85.458 + <customize>
85.459 + <arg line="${application.args}"/>
85.460 + </customize>
85.461 + </j2seproject3:debug>
85.462 + </target>
85.463 + <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
85.464 + <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
85.465 + <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
85.466 + </target>
85.467 + <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
85.468 + <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
85.469 + <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
85.470 + <j2seproject3:debug classname="${debug.class}"/>
85.471 + </target>
85.472 + <target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
85.473 + <target depends="init" name="-pre-debug-fix">
85.474 + <fail unless="fix.includes">Must set fix.includes</fail>
85.475 + <property name="javac.includes" value="${fix.includes}.java"/>
85.476 + </target>
85.477 + <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
85.478 + <j2seproject1:nbjpdareload/>
85.479 + </target>
85.480 + <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
85.481 + <!--
85.482 + ===============
85.483 + JAVADOC SECTION
85.484 + ===============
85.485 + -->
85.486 + <target depends="init" name="-javadoc-build">
85.487 + <mkdir dir="${dist.javadoc.dir}"/>
85.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}">
85.489 + <classpath>
85.490 + <path path="${javac.classpath}"/>
85.491 + </classpath>
85.492 + <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
85.493 + <filename name="**/*.java"/>
85.494 + </fileset>
85.495 + </javadoc>
85.496 + </target>
85.497 + <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
85.498 + <nbbrowse file="${dist.javadoc.dir}/index.html"/>
85.499 + </target>
85.500 + <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
85.501 + <!--
85.502 + =========================
85.503 + JUNIT COMPILATION SECTION
85.504 + =========================
85.505 + -->
85.506 + <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
85.507 + <mkdir dir="${build.test.classes.dir}"/>
85.508 + </target>
85.509 + <target name="-pre-compile-test">
85.510 + <!-- Empty placeholder for easier customization. -->
85.511 + <!-- You can override this target in the ../build.xml file. -->
85.512 + </target>
85.513 + <target if="do.depend.true" name="-compile-test-depend">
85.514 + <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
85.515 + </target>
85.516 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
85.517 + <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
85.518 + <copy todir="${build.test.classes.dir}">
85.519 + <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
85.520 + </copy>
85.521 + </target>
85.522 + <target name="-post-compile-test">
85.523 + <!-- Empty placeholder for easier customization. -->
85.524 + <!-- You can override this target in the ../build.xml file. -->
85.525 + </target>
85.526 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
85.527 + <target name="-pre-compile-test-single">
85.528 + <!-- Empty placeholder for easier customization. -->
85.529 + <!-- You can override this target in the ../build.xml file. -->
85.530 + </target>
85.531 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
85.532 + <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
85.533 + <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
85.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}"/>
85.535 + <copy todir="${build.test.classes.dir}">
85.536 + <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
85.537 + </copy>
85.538 + </target>
85.539 + <target name="-post-compile-test-single">
85.540 + <!-- Empty placeholder for easier customization. -->
85.541 + <!-- You can override this target in the ../build.xml file. -->
85.542 + </target>
85.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"/>
85.544 + <!--
85.545 + =======================
85.546 + JUNIT EXECUTION SECTION
85.547 + =======================
85.548 + -->
85.549 + <target depends="init" if="have.tests" name="-pre-test-run">
85.550 + <mkdir dir="${build.test.results.dir}"/>
85.551 + </target>
85.552 + <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
85.553 + <j2seproject3:junit testincludes="**/*Test.java"/>
85.554 + </target>
85.555 + <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
85.556 + <fail if="tests.failed">Some tests failed; see details above.</fail>
85.557 + </target>
85.558 + <target depends="init" if="have.tests" name="test-report"/>
85.559 + <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
85.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"/>
85.561 + <target depends="init" if="have.tests" name="-pre-test-run-single">
85.562 + <mkdir dir="${build.test.results.dir}"/>
85.563 + </target>
85.564 + <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
85.565 + <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
85.566 + <j2seproject3:junit excludes="" includes="${test.includes}"/>
85.567 + </target>
85.568 + <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
85.569 + <fail if="tests.failed">Some tests failed; see details above.</fail>
85.570 + </target>
85.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"/>
85.572 + <!--
85.573 + =======================
85.574 + JUNIT DEBUGGING SECTION
85.575 + =======================
85.576 + -->
85.577 + <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
85.578 + <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
85.579 + <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
85.580 + <delete file="${test.report.file}"/>
85.581 + <mkdir dir="${build.test.results.dir}"/>
85.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}">
85.583 + <customize>
85.584 + <syspropertyset>
85.585 + <propertyref prefix="test-sys-prop."/>
85.586 + <mapper from="test-sys-prop.*" to="*" type="glob"/>
85.587 + </syspropertyset>
85.588 + <arg value="${test.class}"/>
85.589 + <arg value="showoutput=true"/>
85.590 + <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
85.591 + <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
85.592 + </customize>
85.593 + </j2seproject3:debug>
85.594 + </target>
85.595 + <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
85.596 + <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
85.597 + </target>
85.598 + <target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
85.599 + <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
85.600 + <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
85.601 + </target>
85.602 + <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
85.603 + <!--
85.604 + =========================
85.605 + APPLET EXECUTION SECTION
85.606 + =========================
85.607 + -->
85.608 + <target depends="init,compile-single" name="run-applet">
85.609 + <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
85.610 + <j2seproject1:java classname="sun.applet.AppletViewer">
85.611 + <customize>
85.612 + <arg value="${applet.url}"/>
85.613 + </customize>
85.614 + </j2seproject1:java>
85.615 + </target>
85.616 + <!--
85.617 + =========================
85.618 + APPLET DEBUGGING SECTION
85.619 + =========================
85.620 + -->
85.621 + <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
85.622 + <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
85.623 + <j2seproject3:debug classname="sun.applet.AppletViewer">
85.624 + <customize>
85.625 + <arg value="${applet.url}"/>
85.626 + </customize>
85.627 + </j2seproject3:debug>
85.628 + </target>
85.629 + <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
85.630 + <!--
85.631 + ===============
85.632 + CLEANUP SECTION
85.633 + ===============
85.634 + -->
85.635 + <target depends="init" name="deps-clean" unless="no.deps"/>
85.636 + <target depends="init" name="-do-clean">
85.637 + <delete dir="${build.dir}"/>
85.638 + <delete dir="${dist.dir}"/>
85.639 + </target>
85.640 + <target name="-post-clean">
85.641 + <!-- Empty placeholder for easier customization. -->
85.642 + <!-- You can override this target in the ../build.xml file. -->
85.643 + </target>
85.644 + <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
85.645 +</project>
86.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
86.2 +++ b/task4/solution12/nbproject/genfiles.properties Sat Oct 11 23:38:46 2008 +0200
86.3 @@ -0,0 +1,8 @@
86.4 +build.xml.data.CRC32=2ab820eb
86.5 +build.xml.script.CRC32=58a52595
86.6 +build.xml.stylesheet.CRC32=be360661
86.7 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
86.8 +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
86.9 +nbproject/build-impl.xml.data.CRC32=b63e115b
86.10 +nbproject/build-impl.xml.script.CRC32=3bdfc4fa
86.11 +nbproject/build-impl.xml.stylesheet.CRC32=e55b27f5
87.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
87.2 +++ b/task4/solution12/nbproject/project.properties Sat Oct 11 23:38:46 2008 +0200
87.3 @@ -0,0 +1,68 @@
87.4 +application.title=currency
87.5 +application.vendor=apidesign.org
87.6 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
87.7 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
87.8 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=default
87.9 +build.classes.dir=${build.dir}/classes
87.10 +build.classes.excludes=**/*.java,**/*.form
87.11 +# This directory is removed when the project is cleaned:
87.12 +build.dir=build
87.13 +build.generated.dir=${build.dir}/generated
87.14 +# Only compile against the classpath explicitly listed here:
87.15 +build.sysclasspath=ignore
87.16 +build.test.classes.dir=${build.dir}/test/classes
87.17 +build.test.results.dir=${build.dir}/test/results
87.18 +debug.classpath=\
87.19 + ${run.classpath}
87.20 +debug.test.classpath=\
87.21 + ${run.test.classpath}
87.22 +# This directory is removed when the project is cleaned:
87.23 +dist.dir=dist
87.24 +dist.jar=${dist.dir}/currency.jar
87.25 +dist.javadoc.dir=${dist.dir}/javadoc
87.26 +excludes=
87.27 +file.reference.junit-4.4.jar=../../libs/junit-4.4.jar
87.28 +file.reference.src-apifest08=..
87.29 +includes=**
87.30 +jar.compress=false
87.31 +javac.classpath=
87.32 +# Space-separated list of extra javac options
87.33 +javac.compilerargs=
87.34 +javac.deprecation=false
87.35 +javac.source=1.5
87.36 +javac.target=1.5
87.37 +javac.test.classpath=\
87.38 + ${javac.classpath}:\
87.39 + ${build.classes.dir}:\
87.40 + ${file.reference.junit-4.4.jar}
87.41 +javadoc.additionalparam=
87.42 +javadoc.author=false
87.43 +javadoc.encoding=
87.44 +javadoc.noindex=false
87.45 +javadoc.nonavbar=false
87.46 +javadoc.notree=false
87.47 +javadoc.private=false
87.48 +javadoc.splitindex=true
87.49 +javadoc.use=true
87.50 +javadoc.version=false
87.51 +javadoc.windowtitle=
87.52 +jnlp.codebase.type=local
87.53 +jnlp.codebase.url=file:/home/jarda/src/apifest08/currency/dist
87.54 +jnlp.descriptor=application
87.55 +jnlp.enabled=false
87.56 +jnlp.offline-allowed=false
87.57 +jnlp.signed=false
87.58 +meta.inf.dir=${src.dir}/META-INF
87.59 +platform.active=default_platform
87.60 +run.classpath=\
87.61 + ${javac.classpath}:\
87.62 + ${build.classes.dir}
87.63 +# Space-separated list of JVM arguments used when running the project
87.64 +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
87.65 +# or test-sys-prop.name=value to set system properties for unit tests):
87.66 +run.jvmargs=
87.67 +run.test.classpath=\
87.68 + ${javac.test.classpath}:\
87.69 + ${build.test.classes.dir}
87.70 +src.dir=src
87.71 +test.src.dir=test
88.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
88.2 +++ b/task4/solution12/nbproject/project.xml Sat Oct 11 23:38:46 2008 +0200
88.3 @@ -0,0 +1,16 @@
88.4 +<?xml version="1.0" encoding="UTF-8"?>
88.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
88.6 + <type>org.netbeans.modules.java.j2seproject</type>
88.7 + <configuration>
88.8 + <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
88.9 + <name>Currency Convertor Solution 12</name>
88.10 + <minimum-ant-version>1.6.5</minimum-ant-version>
88.11 + <source-roots>
88.12 + <root id="src.dir"/>
88.13 + </source-roots>
88.14 + <test-roots>
88.15 + <root id="test.src.dir"/>
88.16 + </test-roots>
88.17 + </data>
88.18 + </configuration>
88.19 +</project>
89.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
89.2 +++ b/task4/solution12/src/org/apidesign/apifest08/currency/Convertor.java Sat Oct 11 23:38:46 2008 +0200
89.3 @@ -0,0 +1,183 @@
89.4 +package org.apidesign.apifest08.currency;
89.5 +
89.6 +import java.util.ArrayList;
89.7 +import java.util.Currency;
89.8 +import java.util.Hashtable;
89.9 +import java.util.List;
89.10 +
89.11 +import org.apidesign.apifest08.currency.exceptions.ConvertorException;
89.12 +import org.apidesign.apifest08.currency.exceptions.InvalidCurrencyException;
89.13 +import org.apidesign.apifest08.currency.exceptions.UnknownConvertorException;
89.14 +
89.15 +/**
89.16 + * This is the skeleton class for your API. You need to make it public, so it is accessible to your client code
89.17 + * (currently in Task1Test.java) file.
89.18 + * <p>
89.19 + * Feel free to create additional classes or rename this one, just keep all the API and its implementation in this
89.20 + * package. Do not spread it outside to other packages.
89.21 + */
89.22 +public class Convertor {
89.23 +
89.24 + private static Hashtable<String, ExchangeRate> exchangeRates;
89.25 +
89.26 + private List<String> currencyConvertors;
89.27 +
89.28 + /**
89.29 + * Constructor. Checks if all selected currencies are not null and has defined exchange rates for both
89.30 + * directions.
89.31 + * @param currencies currencies for new instance of convertor
89.32 + * @throws UnknownConvertorException if there are not defined exchange rates for both directions for each
89.33 + * pair of currencies
89.34 + */
89.35 + private Convertor(Currency[] currencies) throws UnknownConvertorException {
89.36 + currencyConvertors = new ArrayList<String>();
89.37 +
89.38 + for (Currency currency1 : currencies) {
89.39 + for (Currency currency2 : currencies) {
89.40 + if(currency1 == null || currency2 == null) {
89.41 + throw new ConvertorException("None of the currencies should be null!!!");
89.42 + }
89.43 +
89.44 + if(!currency1.getCurrencyCode().equals(currency2.getCurrencyCode())) {
89.45 + String key = currency1.getCurrencyCode() + currency2.getCurrencyCode();
89.46 + if (!exchangeRates.containsKey(key)) {
89.47 + throw new UnknownConvertorException("Selected convertor (" + currency1.getCurrencyCode() + "->"
89.48 + + currency2.getCurrencyCode() + ") has not defined exchange rates!!!");
89.49 + }
89.50 +
89.51 + currencyConvertors.add(key);
89.52 + }
89.53 + }
89.54 + }
89.55 + }
89.56 +
89.57 + /**
89.58 + * Sets convertor rate for selected currencies.
89.59 + * @param currency1
89.60 + * one of the currencies we want to convert to/from
89.61 + * @param currency2
89.62 + * the other currency
89.63 + * @param rate
89.64 + * exchange rate from currency1 to currency2
89.65 + * @param unit
89.66 + * unit of exchangeRate (USD->CZK - unit=1, you exchange one dollar, SKK->CZK unit=100, exchange rate is for
89.67 + * 100SKK)
89.68 + */
89.69 + public static void setConvertorRates(Currency currency1, Currency currency2, double rate, double unit) {
89.70 + if (currency1 == null || currency2 == null) {
89.71 + throw new ConvertorException("None of the currencies should be null!!!");
89.72 + }
89.73 +
89.74 + if (rate <= 0 || unit <= 0) {
89.75 + throw new ConvertorException("Rate(" + rate + ") and unit(" + unit + ") has to be grater then zero!!!");
89.76 + }
89.77 +
89.78 + if (exchangeRates == null) {
89.79 + exchangeRates = new Hashtable<String, ExchangeRate>();
89.80 + }
89.81 +
89.82 + String key12 = currency1.getCurrencyCode() + currency2.getCurrencyCode();
89.83 + String key21 = currency2.getCurrencyCode() + currency1.getCurrencyCode();
89.84 + double recountedRate = (unit / rate) * unit;
89.85 +
89.86 + exchangeRates.put(key12, new ExchangeRate(currency1, currency2, rate, unit));
89.87 + exchangeRates.put(key21, new ExchangeRate(currency2, currency1, recountedRate, unit));
89.88 +
89.89 + }
89.90 +
89.91 + /**
89.92 + * Merge exchange rates of actual convertor with exchange rates from selected
89.93 + * convertor. If there are same currencies in both convertors, these from selected
89.94 + * convertor rewrites these in actual convertor.
89.95 + * @param convertor convertor to merge with actual one
89.96 + * @return convertor with merged exchange rates
89.97 + */
89.98 + public Convertor merge(Convertor convertor) {
89.99 + if(convertor == null) {
89.100 + throw new ConvertorException("It's impossible to merge with null convertor!!!");
89.101 + }
89.102 +
89.103 + currencyConvertors.addAll(convertor.getCurrencyConvertors());
89.104 + return this;
89.105 + }
89.106 +
89.107 + /**
89.108 + * Creates new instance of convertor.
89.109 + * @param currency1
89.110 + * one of the currencies we want to convert to/from
89.111 + * @param currency2
89.112 + * the other currency
89.113 + * @return new instance of convertor
89.114 + * @throws UnknownConvertorException
89.115 + * thrown if convertor for selected currencies has not been defined
89.116 + */
89.117 + public static Convertor getConvertorInstance(Currency... currencies) throws UnknownConvertorException {
89.118 + if(currencies.length < 2) {
89.119 + throw new ConvertorException("To get convertor instance, you have to select at least two currencies!!!");
89.120 + }
89.121 +
89.122 + return new Convertor(currencies);
89.123 + }
89.124 +
89.125 + /**
89.126 + * Converts selected amout of selected currency to other currency of this convertor instance.
89.127 + * @param amount
89.128 + * amount to convert
89.129 + * @param originalCurrency
89.130 + * currency of this amount
89.131 + * @param newCurrency
89.132 + * currency to which we want convert
89.133 + * @return converted amount
89.134 + * @throws InvalidCurrencyException
89.135 + * while one or both currencies doesn't fit for this convertor
89.136 + */
89.137 + public double convert(double amount, Currency originalCurrency, Currency newCurrency) throws InvalidCurrencyException {
89.138 + ExchangeRate actualyUsedExchangeRate = null;
89.139 +
89.140 + if (originalCurrency == null) {
89.141 + throw new ConvertorException("Original currency is null!!!");
89.142 + }
89.143 +
89.144 + if (newCurrency == null) {
89.145 + throw new ConvertorException("Destination currency is null!!!");
89.146 + }
89.147 +
89.148 + actualyUsedExchangeRate = getExchangeRate(originalCurrency, newCurrency);
89.149 +
89.150 + return countResult(actualyUsedExchangeRate, amount);
89.151 + }
89.152 +
89.153 + private double countResult(ExchangeRate actualyUsedExchangeRate, double amount) {
89.154 + return amount * actualyUsedExchangeRate.getRate() / actualyUsedExchangeRate.getUnit();
89.155 + }
89.156 +
89.157 + /**
89.158 + * Decides the direction of conversion and returns instance of actual exchange rate.
89.159 + * @param actualCurrency
89.160 + * actual currency we want to convert
89.161 + * @return actual exchange rate of this convertor for selected currency
89.162 + */
89.163 + private ExchangeRate getExchangeRate(Currency originalCurrency, Currency newCurrency) throws InvalidCurrencyException {
89.164 + ExchangeRate actualyUsedExchangeRate = null;
89.165 +
89.166 + String key = originalCurrency.getCurrencyCode() + newCurrency.getCurrencyCode();
89.167 +
89.168 + if(currencyConvertors.contains(key)) {
89.169 + actualyUsedExchangeRate = exchangeRates.get(key);
89.170 + } else {
89.171 + throw new InvalidCurrencyException("This convertor could not be used for converting selected currencies (" + originalCurrency.getCurrencyCode() + "->"
89.172 + + newCurrency.getCurrencyCode() + ") !!!");
89.173 + }
89.174 +
89.175 + return actualyUsedExchangeRate;
89.176 + }
89.177 +
89.178 + /**
89.179 + * Returns currency convertors for actual instance of convertor.
89.180 + * @return currency convertors for actual instance of convertor
89.181 + */
89.182 + List<String> getCurrencyConvertors() {
89.183 + return currencyConvertors;
89.184 + }
89.185 +
89.186 +}
90.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
90.2 +++ b/task4/solution12/src/org/apidesign/apifest08/currency/ExchangeRate.java Sat Oct 11 23:38:46 2008 +0200
90.3 @@ -0,0 +1,35 @@
90.4 +package org.apidesign.apifest08.currency;
90.5 +
90.6 +import java.util.Currency;
90.7 +
90.8 +public class ExchangeRate {
90.9 +
90.10 + private Currency originalCurrency;
90.11 + private Currency newCurrency;
90.12 + private double unit;
90.13 + private double rate;
90.14 +
90.15 + public ExchangeRate(Currency originalCurrency, Currency newCurrency, double rate, double unit) {
90.16 + this.newCurrency = newCurrency;
90.17 + this.originalCurrency = originalCurrency;
90.18 + this.rate = rate;
90.19 + this.unit = unit;
90.20 + }
90.21 +
90.22 + public Currency getOriginalCurrency() {
90.23 + return originalCurrency;
90.24 + }
90.25 +
90.26 + public Currency getNewCurrency() {
90.27 + return newCurrency;
90.28 + }
90.29 +
90.30 + public double getUnit() {
90.31 + return unit;
90.32 + }
90.33 +
90.34 + public double getRate() {
90.35 + return rate;
90.36 + }
90.37 +
90.38 +}
91.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
91.2 +++ b/task4/solution12/src/org/apidesign/apifest08/currency/exceptions/ConvertorException.java Sat Oct 11 23:38:46 2008 +0200
91.3 @@ -0,0 +1,20 @@
91.4 +package org.apidesign.apifest08.currency.exceptions;
91.5 +
91.6 +public class ConvertorException extends RuntimeException {
91.7 +
91.8 + public ConvertorException() {
91.9 + }
91.10 +
91.11 + public ConvertorException(String message) {
91.12 + super(message);
91.13 + }
91.14 +
91.15 + public ConvertorException(Throwable cause) {
91.16 + super(cause);
91.17 + }
91.18 +
91.19 + public ConvertorException(String message, Throwable cause) {
91.20 + super(message, cause);
91.21 + }
91.22 +
91.23 +}
92.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
92.2 +++ b/task4/solution12/src/org/apidesign/apifest08/currency/exceptions/InvalidCurrencyException.java Sat Oct 11 23:38:46 2008 +0200
92.3 @@ -0,0 +1,20 @@
92.4 +package org.apidesign.apifest08.currency.exceptions;
92.5 +
92.6 +public class InvalidCurrencyException extends Exception {
92.7 +
92.8 + public InvalidCurrencyException() {
92.9 + }
92.10 +
92.11 + public InvalidCurrencyException(String message) {
92.12 + super(message);
92.13 + }
92.14 +
92.15 + public InvalidCurrencyException(Throwable cause) {
92.16 + super(cause);
92.17 + }
92.18 +
92.19 + public InvalidCurrencyException(String message, Throwable cause) {
92.20 + super(message, cause);
92.21 + }
92.22 +
92.23 +}
93.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
93.2 +++ b/task4/solution12/src/org/apidesign/apifest08/currency/exceptions/UnknownConvertorException.java Sat Oct 11 23:38:46 2008 +0200
93.3 @@ -0,0 +1,20 @@
93.4 +package org.apidesign.apifest08.currency.exceptions;
93.5 +
93.6 +public class UnknownConvertorException extends Exception {
93.7 +
93.8 + public UnknownConvertorException() {
93.9 + }
93.10 +
93.11 + public UnknownConvertorException(String message) {
93.12 + super(message);
93.13 + }
93.14 +
93.15 + public UnknownConvertorException(Throwable cause) {
93.16 + super(cause);
93.17 + }
93.18 +
93.19 + public UnknownConvertorException(String message, Throwable cause) {
93.20 + super(message, cause);
93.21 + }
93.22 +
93.23 +}
94.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
94.2 +++ b/task4/solution12/test/org/apidesign/apifest08/test/Task1Test.java Sat Oct 11 23:38:46 2008 +0200
94.3 @@ -0,0 +1,174 @@
94.4 +package org.apidesign.apifest08.test;
94.5 +
94.6 +import java.util.Currency;
94.7 +
94.8 +import junit.framework.TestCase;
94.9 +
94.10 +import org.apidesign.apifest08.currency.Convertor;
94.11 +import org.apidesign.apifest08.currency.exceptions.InvalidCurrencyException;
94.12 +import org.apidesign.apifest08.currency.exceptions.UnknownConvertorException;
94.13 +
94.14 +/**
94.15 + * Finish the Convertor API, and then write bodies of methods inside of this class to match the given tasks. To fullfil
94.16 + * your task, use the API define in the <code>org.apidesign.apifest08.currency</code> package. Do not you reflection, or
94.17 + * other hacks as your code shall run without any runtime permissions.
94.18 + */
94.19 +public class Task1Test extends TestCase {
94.20 + public Task1Test(String testName) {
94.21 + super(testName);
94.22 + }
94.23 +
94.24 + @Override
94.25 + protected void setUp() throws Exception {
94.26 + }
94.27 +
94.28 + @Override
94.29 + protected void tearDown() throws Exception {
94.30 + }
94.31 +
94.32 + //
94.33 + // Imagine that there are three parts of the whole system:
94.34 + // 1. there is someone who knows the current exchange rate
94.35 + // 2. there is someone who wants to do the conversion
94.36 + // 3. there is the API between 1. and 2. which allows them to communicate
94.37 + // Please design such API
94.38 + //
94.39 +
94.40 + /**
94.41 + * Create convertor that understands two currencies, CZK and USD. Make 1 USD == 17 CZK. This is a method provided for
94.42 + * #1 group - e.g. those that know the exchange rate. They somehow need to create the objects from the API and tell
94.43 + * them the exchange rate. The API itself knows nothing about any rates, before the createCZKtoUSD method is called.
94.44 + * Creation of the convertor shall not require subclassing of any class or interface on the client side.
94.45 + * @return prepared convertor ready for converting USD to CZK and CZK to USD
94.46 + */
94.47 + public static Convertor createCZKtoUSD() {
94.48 + // set exchange rates
94.49 + Convertor.setConvertorRates(Currency.getInstance("USD"), Currency.getInstance("CZK"), 17d, 1d);
94.50 +
94.51 + // create new instance
94.52 + Convertor convertor = null;
94.53 + try {
94.54 + convertor = Convertor.getConvertorInstance(Currency.getInstance("USD"), Currency.getInstance("CZK"));
94.55 + } catch (UnknownConvertorException e) {
94.56 + e.printStackTrace();
94.57 + }
94.58 +
94.59 + return convertor;
94.60 + }
94.61 +
94.62 + /**
94.63 + * Create convertor that understands two currencies, CZK and SKK. Make 100 SKK == 80 CZK. Again this is method for the
94.64 + * #1 group - it knows the exchange rate, and needs to use the API to create objects with the exchange rate. Anyone
94.65 + * shall be ready to call this method without any other method being called previously. The API itself shall know
94.66 + * nothing about any rates, before this method is called. Creation of the convertor shall not require subclassing of
94.67 + * any class or interface on the client side.
94.68 + * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
94.69 + */
94.70 + public static Convertor createSKKtoCZK() {
94.71 + // set exchange rates
94.72 + Convertor.setConvertorRates(Currency.getInstance("SKK"), Currency.getInstance("CZK"), 80d, 100d);
94.73 +
94.74 + // create new instance
94.75 + Convertor convertor = null;
94.76 + try {
94.77 + convertor = Convertor.getConvertorInstance(Currency.getInstance("SKK"), Currency.getInstance("CZK"));
94.78 + } catch (UnknownConvertorException e) {
94.79 + e.printStackTrace();
94.80 + }
94.81 +
94.82 + return convertor;
94.83 + }
94.84 +
94.85 + //
94.86 + // now the methods for group #2 follow:
94.87 + // this group knows nothing about exchange rates, but knows how to use
94.88 + // the API to do conversions. It somehow (by calling one of the factory
94.89 + // methods) gets objects from the API and uses them to do the conversions.
94.90 + //
94.91 +
94.92 + /**
94.93 + * Use the convertor from <code>createCZKtoUSD</code> method and do few conversions with it.
94.94 + */
94.95 + public void testCurrencyCZKUSD() throws Exception {
94.96 + Convertor c = createCZKtoUSD();
94.97 + // convert $5 to CZK using c:
94.98 + double result = c.convert(5, Currency.getInstance("USD"), Currency.getInstance("CZK"));
94.99 + assertEquals("Result is not 85 CZK", 85.0, result);
94.100 +
94.101 + // convert $8 to CZK
94.102 + result = c.convert(8, Currency.getInstance("USD"), Currency.getInstance("CZK"));
94.103 + assertEquals("Result is not 136 CZK", 136.0, result);
94.104 +
94.105 + // convert 1003CZK to USD
94.106 + result = c.convert(1003, Currency.getInstance("CZK"), Currency.getInstance("USD"));
94.107 + assertEquals("Result is not 59 USD", 59.0, result);
94.108 + }
94.109 +
94.110 + /**
94.111 + * Use the convertor from <code>createSKKtoCZK</code> method and do few conversions with it.
94.112 + */
94.113 + public void testCurrencySKKCZK() throws Exception {
94.114 + Convertor c = createSKKtoCZK();
94.115 +
94.116 + // convert 16CZK using c:
94.117 + double result = c.convert(16, Currency.getInstance("CZK"), Currency.getInstance("SKK"));
94.118 + assertEquals("Result is not 20 SKK", 20.0, result);
94.119 +
94.120 + // convert 500SKK to CZK
94.121 + result = c.convert(500, Currency.getInstance("SKK"), Currency.getInstance("CZK"));
94.122 + assertEquals("Result is not 400 CZK", 400.0, result);
94.123 + }
94.124 +
94.125 + /**
94.126 + * Verify that the CZK to USD convertor knows nothing about SKK.
94.127 + */
94.128 + public void testCannotConvertToSKKwithCZKUSDConvertor() throws Exception {
94.129 + Convertor c = createCZKtoUSD();
94.130 + boolean exceptionThrown = false;
94.131 +
94.132 + // convert $5 to SKK, the API shall say this is not possible
94.133 + try {
94.134 + c.convert(5, Currency.getInstance("USD"), Currency.getInstance("SKK"));
94.135 + exceptionThrown = false;
94.136 + } catch (InvalidCurrencyException e) {
94.137 + exceptionThrown = true;
94.138 + }
94.139 + assertEquals("It should be impossible to convert to SKK with USD->CZK convertor", true, exceptionThrown);
94.140 +
94.141 + // convert 500 SKK to CZK, the API shall say this is not possible
94.142 + try {
94.143 + c.convert(500, Currency.getInstance("SKK"), Currency.getInstance("CZK"));
94.144 + exceptionThrown = false;
94.145 + } catch (InvalidCurrencyException e) {
94.146 + exceptionThrown = true;
94.147 + }
94.148 + assertEquals("It should be impossible to convert from SKK with USD->CZK convertor", true, exceptionThrown);
94.149 +
94.150 + }
94.151 +
94.152 + /**
94.153 + * Verify that the CZK to SKK convertor knows nothing about USD.
94.154 + */
94.155 + public void testCannotConvertToSKKwithSKKCZKConvertor() throws Exception {
94.156 + Convertor c = createSKKtoCZK();
94.157 + boolean exceptionThrown = false;
94.158 +
94.159 + // convert $5 to SKK, the API shall say this is not possible
94.160 + try {
94.161 + c.convert(5, Currency.getInstance("USD"), Currency.getInstance("SKK"));
94.162 + exceptionThrown = false;
94.163 + } catch (InvalidCurrencyException e) {
94.164 + exceptionThrown = true;
94.165 + }
94.166 + assertEquals("It should be impossible to convert form USD with SKK->CZK convertor", true, exceptionThrown);
94.167 +
94.168 + // convert 500 CZK to USD, the API shall say this is not possible
94.169 + try {
94.170 + c.convert(500, Currency.getInstance("CZK"), Currency.getInstance("USD"));
94.171 + exceptionThrown = false;
94.172 + } catch (InvalidCurrencyException e) {
94.173 + exceptionThrown = true;
94.174 + }
94.175 + assertEquals("It should be impossible to convert to USD with SKK->CZK convertor", true, exceptionThrown);
94.176 + }
94.177 +}
95.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
95.2 +++ b/task4/solution12/test/org/apidesign/apifest08/test/Task2Test.java Sat Oct 11 23:38:46 2008 +0200
95.3 @@ -0,0 +1,132 @@
95.4 +package org.apidesign.apifest08.test;
95.5 +
95.6 +import java.util.Currency;
95.7 +
95.8 +import junit.framework.TestCase;
95.9 +
95.10 +import org.apidesign.apifest08.currency.Convertor;
95.11 +import org.apidesign.apifest08.currency.exceptions.UnknownConvertorException;
95.12 +
95.13 +/** There are many currencies around the world and many banks manipulate
95.14 + * with more than one or two at the same time. As banks are usually the
95.15 + * best paying clients, which is true even in case of your Convertor API,
95.16 + * it is reasonable to listen to their requests.
95.17 + * <p>
95.18 + * The quest for today is to enhance your existing convertor API to hold
95.19 + * information about many currencies and allow conversions between any of them.
95.20 + * Also, as conversion rates for diferent currencies usually arise from various
95.21 + * bank departments, there is another important need. There is a need to
95.22 + * compose two convertors into one by merging all the information about
95.23 + * currencies they know about.
95.24 + */
95.25 +public class Task2Test extends TestCase {
95.26 + public Task2Test(String testName) {
95.27 + super(testName);
95.28 + }
95.29 +
95.30 + @Override
95.31 + protected void setUp() throws Exception {
95.32 + }
95.33 +
95.34 + @Override
95.35 + protected void tearDown() throws Exception {
95.36 + }
95.37 +
95.38 + // As in Task1Test, keep in mind, that there are three parts
95.39 + // of the whole system:
95.40 + // 1. there is someone who knows the current exchange rate
95.41 + // 2. there is someone who wants to do the conversion
95.42 + // 3. there is the API between 1. and 2. which allows them to communicate
95.43 + //
95.44 + // Please backward compatibly enhance your existing API to support following
95.45 + // usecases:
95.46 + //
95.47 +
95.48 + /** Create convertor that understands two currencies, CZK and
95.49 + * SKK. Make 100 SKK == 75 CZK. This is method for the group of users that
95.50 + * knows the exchange rate, and needs to use the API to create objects
95.51 + * with the exchange rate. Anyone shall be ready to call this method without
95.52 + * any other method being called previously. The API itself shall know
95.53 + * nothing about any rates, before this method is called.
95.54 + */
95.55 + public static Convertor createTripleConvertor() {
95.56 + // Rates: 1USD = 15CZK
95.57 + // Rates: 1USD = 20SKK
95.58 + // Rates: 75CZK = 100SKK
95.59 + // set exchange rates
95.60 + Convertor.setConvertorRates(Currency.getInstance("USD"), Currency.getInstance("CZK"), 15, 1);
95.61 + Convertor.setConvertorRates(Currency.getInstance("USD"), Currency.getInstance("SKK"), 20, 1);
95.62 + Convertor.setConvertorRates(Currency.getInstance("SKK"), Currency.getInstance("CZK"), 75, 100);
95.63 +
95.64 + // create new instance
95.65 + Convertor convertor = null;
95.66 + try {
95.67 + convertor = Convertor.getConvertorInstance(Currency.getInstance("USD"), Currency.getInstance("SKK"), Currency.getInstance("CZK"));
95.68 + } catch (UnknownConvertorException e) {
95.69 + e.printStackTrace();
95.70 + }
95.71 + return convertor;
95.72 + }
95.73 +
95.74 + /** Define convertor that understands three currencies. Use it.
95.75 + */
95.76 + public void testConvertorForUSDandCZKandSKK() throws Exception {
95.77 + Convertor c = createTripleConvertor();
95.78 +
95.79 + // convert $5 to CZK using c:
95.80 + double result = c.convert(5d, Currency.getInstance("USD"), Currency.getInstance("CZK"));
95.81 + assertEquals("Result is not 75 CZK", 75.0, result);
95.82 +
95.83 + // convert $5 to SKK using c:
95.84 + result = c.convert(5d, Currency.getInstance("USD"), Currency.getInstance("SKK"));
95.85 + assertEquals("Result is not 100 SKK", 100.0, result);
95.86 +
95.87 + // convert 200SKK to CZK using c:
95.88 + result = c.convert(200d, Currency.getInstance("SKK"), Currency.getInstance("CZK"));
95.89 + assertEquals("Result is not 150 CZK", 150.0, result);
95.90 +
95.91 + // convert 200SKK to USK using c:
95.92 + result = c.convert(200d, Currency.getInstance("SKK"), Currency.getInstance("USD"));
95.93 + assertEquals("Result is not 10 USD", 10.0, result);
95.94 + }
95.95 +
95.96 + /** Merge all currency rates of convertor 1 with convertor 2.
95.97 + * Implement this using your API, preferably this method just delegates
95.98 + * into some API method which does the actual work, without requiring
95.99 + * API clients to code anything complex.
95.100 + */
95.101 + public static Convertor merge(Convertor one, Convertor two) {
95.102 + return one.merge(two);
95.103 + }
95.104 +
95.105 + /** Join the convertors from previous task, Task1Test and show that it
95.106 + * can be used to do reasonable conversions.
95.107 + */
95.108 + public void testConvertorComposition() throws Exception {
95.109 + Convertor c = merge(
95.110 + Task1Test.createCZKtoUSD(),
95.111 + Task1Test.createSKKtoCZK()
95.112 + );
95.113 +
95.114 + // convert $5 to CZK using c:
95.115 + double result = c.convert(5d, Currency.getInstance("USD"), Currency.getInstance("CZK"));
95.116 + assertEquals("Result is not 85 CZK", 85.0, result);
95.117 +
95.118 + // convert $8 to CZK using c:
95.119 + result = c.convert(8d, Currency.getInstance("USD"), Currency.getInstance("CZK"));
95.120 + assertEquals("Result is not 136 CZK", 136.0, result);
95.121 +
95.122 + // convert 1003CZK to USD using c:
95.123 + result = c.convert(1003d, Currency.getInstance("CZK"), Currency.getInstance("USD"));
95.124 + assertEquals("Result is not 59 USD", 59.0, result);
95.125 +
95.126 + // convert 16CZK using c:
95.127 + result = c.convert(16d, Currency.getInstance("CZK"), Currency.getInstance("SKK"));
95.128 + assertEquals("Result is not 20 SKK", 20.0, result);
95.129 +
95.130 + // convert 500SKK to CZK using c:
95.131 + result = c.convert(500d, Currency.getInstance("SKK"), Currency.getInstance("CZK"));
95.132 + assertEquals("Result is not 400 CZK", 400.0, result);
95.133 +
95.134 + }
95.135 +}
96.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
96.2 +++ b/task4/solution12/test/org/apidesign/apifest08/test/Task3Test.java Sat Oct 11 23:38:46 2008 +0200
96.3 @@ -0,0 +1,145 @@
96.4 +package org.apidesign.apifest08.test;
96.5 +
96.6 +import java.util.Currency;
96.7 +
96.8 +import junit.framework.TestCase;
96.9 +import org.apidesign.apifest08.currency.Convertor;
96.10 +import org.apidesign.apifest08.currency.exceptions.UnknownConvertorException;
96.11 +
96.12 +/** The exchange rates are not always the same. They are changing. Day by day,
96.13 + * hour by hour, minute by minute. For every bank it is important to always
96.14 + * have the actual exchange rate available in the system. That is why let's
96.15 + * create a pluggable convertor that will always have up to date value of its
96.16 + * exchange rate.
96.17 + * <p>
96.18 + * The quest for today is to allow 3rd party developer to write a convertor
96.19 + * that adjusts its exchange rate everytime it is queried. This convertor is
96.20 + * written by independent vendor, the vendor knows only your Convertor API,
96.21 + * he does not know how the whole system looks and how the convertor is supposed
96.22 + * to be used.
96.23 + */
96.24 +public class Task3Test extends TestCase {
96.25 +
96.26 + private static double actualRate;
96.27 + private static boolean increasing;
96.28 +
96.29 + private static final double EXCHANGE_RATE_MAX = 16.0;
96.30 + private static final double EXCHANGE_RATE_MIN = 15.0;
96.31 +
96.32 + public Task3Test(String testName) {
96.33 + super(testName);
96.34 + }
96.35 +
96.36 + @Override
96.37 + protected void setUp() throws Exception {
96.38 + }
96.39 +
96.40 + @Override
96.41 + protected void tearDown() throws Exception {
96.42 + }
96.43 +
96.44 + // Backward compatibly enhance your existing API to support following
96.45 + // usecases:
96.46 + //
96.47 +
96.48 +
96.49 + /** Without knowing anything about the surrounding system, write an
96.50 + * implementation of convertor that will return different rates everytime
96.51 + * it is queried. Convert USD to CZK and vice versa. Start with the rate of
96.52 + * 1USD = 16CZK and adjust it in favor of CZK by 0.01 CZK with every query.
96.53 + * As soon as you reach 1USD = 15CZK adjust it by 0.01 CZK in favor of USD
96.54 + * until you reach 1USD = 16CZK
96.55 + *
96.56 + * @return new instance of "online" USD and CZK convertor starting with rate 1USD = 16CZK
96.57 + */
96.58 + public static Convertor createOnlineCZKUSDConvertor() {
96.59 + actualRate = 16.01;
96.60 + increasing = false;
96.61 +
96.62 + // sets actual exchange rates
96.63 + setRates();
96.64 +
96.65 + // create new instance
96.66 + Convertor convertor = null;
96.67 + try {
96.68 + convertor = Convertor.getConvertorInstance(Currency.getInstance("USD"), Currency.getInstance("CZK"));
96.69 + } catch (UnknownConvertorException e) {
96.70 + e.printStackTrace();
96.71 + }
96.72 +
96.73 + return convertor;
96.74 + }
96.75 +
96.76 + public void testFewQueriesForOnlineConvertor() throws Exception {
96.77 + Convertor c = createOnlineCZKUSDConvertor();
96.78 + doFewQueriesForOnlineConvertor(c);
96.79 + }
96.80 +
96.81 + static void doFewQueriesForOnlineConvertor(Convertor c) throws Exception {
96.82 + // convert $5 to CZK using c:
96.83 + double result = c.convert(5d, Currency.getInstance("USD"), Currency.getInstance("CZK"));
96.84 + double expectedResult = actualRate * 5;
96.85 + assertEquals("Result is not " + expectedResult + " CZK", expectedResult, result);
96.86 +
96.87 + // change exchange rates
96.88 + setRates();
96.89 +
96.90 + // convert $8 to CZK using c:
96.91 + result = c.convert(8d, Currency.getInstance("USD"), Currency.getInstance("CZK"));
96.92 + expectedResult = actualRate * 8;
96.93 + assertEquals("Result is not " + expectedResult + " CZK", expectedResult, result);
96.94 +
96.95 + // change exchange rates
96.96 + setRates();
96.97 +
96.98 + // convert $1 to CZK using c:
96.99 + result = c.convert(1d, Currency.getInstance("USD"), Currency.getInstance("CZK"));
96.100 + expectedResult = actualRate * 1;
96.101 + assertEquals("Result is not " + expectedResult + " CZK", expectedResult, result);
96.102 +
96.103 + // change exchange rates
96.104 + setRates();
96.105 +
96.106 + // convert 15.97CZK to USD using c:
96.107 + result = c.convert(15.97d, Currency.getInstance("CZK"), Currency.getInstance("USD"));
96.108 + expectedResult = 15.97 / actualRate ;
96.109 + assertEquals("Result is not " + expectedResult + " USD", expectedResult, result);
96.110 + }
96.111 +
96.112 + /** Join the convertors and show they behave sane.
96.113 + */
96.114 + public void testOnlineConvertorComposition() throws Exception {
96.115 + Convertor c = Task2Test.merge(
96.116 + createOnlineCZKUSDConvertor(),
96.117 + Task1Test.createSKKtoCZK()
96.118 + );
96.119 +
96.120 + // convert 16CZK to SKK using c:
96.121 + double result = c.convert(16d, Currency.getInstance("CZK"), Currency.getInstance("SKK"));
96.122 + assertEquals("Result is not 20 SKK", 20d, result);
96.123 +
96.124 + // convert 500SKK to CZK using c:
96.125 + result = c.convert(500d, Currency.getInstance("SKK"), Currency.getInstance("CZK"));
96.126 + assertEquals("Result is not 400 CZK", 400d, result);
96.127 +
96.128 + doFewQueriesForOnlineConvertor(c);
96.129 + }
96.130 +
96.131 + private static void setRates() {
96.132 + // logic for change of actual exchange rate
96.133 + if(increasing) {
96.134 + actualRate += 0.01;
96.135 + if(actualRate == EXCHANGE_RATE_MAX){
96.136 + increasing = false;
96.137 + }
96.138 + } else {
96.139 + actualRate -= 0.01;
96.140 + if(actualRate == EXCHANGE_RATE_MIN){
96.141 + increasing = true;
96.142 + }
96.143 + }
96.144 +
96.145 + // set exchange rates
96.146 + Convertor.setConvertorRates(Currency.getInstance("USD"), Currency.getInstance("CZK"), actualRate, 1d);
96.147 + }
96.148 +}
97.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
97.2 +++ b/task4/solution13/build.xml Sat Oct 11 23:38:46 2008 +0200
97.3 @@ -0,0 +1,69 @@
97.4 +<?xml version="1.0" encoding="UTF-8"?>
97.5 +<!-- You may freely edit this file. See commented blocks below for -->
97.6 +<!-- some examples of how to customize the build. -->
97.7 +<!-- (If you delete it and reopen the project it will be recreated.) -->
97.8 +<project name="currency" default="default" basedir=".">
97.9 + <description>Builds, tests, and runs the project.</description>
97.10 + <import file="nbproject/build-impl.xml"/>
97.11 + <!--
97.12 +
97.13 + There exist several targets which are by default empty and which can be
97.14 + used for execution of your tasks. These targets are usually executed
97.15 + before and after some main targets. They are:
97.16 +
97.17 + -pre-init: called before initialization of project properties
97.18 + -post-init: called after initialization of project properties
97.19 + -pre-compile: called before javac compilation
97.20 + -post-compile: called after javac compilation
97.21 + -pre-compile-single: called before javac compilation of single file
97.22 + -post-compile-single: called after javac compilation of single file
97.23 + -pre-compile-test: called before javac compilation of JUnit tests
97.24 + -post-compile-test: called after javac compilation of JUnit tests
97.25 + -pre-compile-test-single: called before javac compilation of single JUnit test
97.26 + -post-compile-test-single: called after javac compilation of single JUunit test
97.27 + -pre-jar: called before JAR building
97.28 + -post-jar: called after JAR building
97.29 + -post-clean: called after cleaning build products
97.30 +
97.31 + (Targets beginning with '-' are not intended to be called on their own.)
97.32 +
97.33 + Example of inserting an obfuscator after compilation could look like this:
97.34 +
97.35 + <target name="-post-compile">
97.36 + <obfuscate>
97.37 + <fileset dir="${build.classes.dir}"/>
97.38 + </obfuscate>
97.39 + </target>
97.40 +
97.41 + For list of available properties check the imported
97.42 + nbproject/build-impl.xml file.
97.43 +
97.44 +
97.45 + Another way to customize the build is by overriding existing main targets.
97.46 + The targets of interest are:
97.47 +
97.48 + -init-macrodef-javac: defines macro for javac compilation
97.49 + -init-macrodef-junit: defines macro for junit execution
97.50 + -init-macrodef-debug: defines macro for class debugging
97.51 + -init-macrodef-java: defines macro for class execution
97.52 + -do-jar-with-manifest: JAR building (if you are using a manifest)
97.53 + -do-jar-without-manifest: JAR building (if you are not using a manifest)
97.54 + run: execution of project
97.55 + -javadoc-build: Javadoc generation
97.56 + test-report: JUnit report generation
97.57 +
97.58 + An example of overriding the target for project execution could look like this:
97.59 +
97.60 + <target name="run" depends="currency-impl.jar">
97.61 + <exec dir="bin" executable="launcher.exe">
97.62 + <arg file="${dist.jar}"/>
97.63 + </exec>
97.64 + </target>
97.65 +
97.66 + Notice that the overridden target depends on the jar target and not only on
97.67 + the compile target as the regular run target does. Again, for a list of available
97.68 + properties which you can use, check the target you are overriding in the
97.69 + nbproject/build-impl.xml file.
97.70 +
97.71 + -->
97.72 +</project>
98.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
98.2 +++ b/task4/solution13/nbproject/build-impl.xml Sat Oct 11 23:38:46 2008 +0200
98.3 @@ -0,0 +1,642 @@
98.4 +<?xml version="1.0" encoding="UTF-8"?>
98.5 +<!--
98.6 +*** GENERATED FROM project.xml - DO NOT EDIT ***
98.7 +*** EDIT ../build.xml INSTEAD ***
98.8 +
98.9 +For the purpose of easier reading the script
98.10 +is divided into following sections:
98.11 +
98.12 + - initialization
98.13 + - compilation
98.14 + - jar
98.15 + - execution
98.16 + - debugging
98.17 + - javadoc
98.18 + - junit compilation
98.19 + - junit execution
98.20 + - junit debugging
98.21 + - applet
98.22 + - cleanup
98.23 +
98.24 + -->
98.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">
98.26 + <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
98.27 + <!--
98.28 + ======================
98.29 + INITIALIZATION SECTION
98.30 + ======================
98.31 + -->
98.32 + <target name="-pre-init">
98.33 + <!-- Empty placeholder for easier customization. -->
98.34 + <!-- You can override this target in the ../build.xml file. -->
98.35 + </target>
98.36 + <target depends="-pre-init" name="-init-private">
98.37 + <property file="nbproject/private/config.properties"/>
98.38 + <property file="nbproject/private/configs/${config}.properties"/>
98.39 + <property file="nbproject/private/private.properties"/>
98.40 + </target>
98.41 + <target depends="-pre-init,-init-private" name="-init-user">
98.42 + <property file="${user.properties.file}"/>
98.43 + <!-- The two properties below are usually overridden -->
98.44 + <!-- by the active platform. Just a fallback. -->
98.45 + <property name="default.javac.source" value="1.4"/>
98.46 + <property name="default.javac.target" value="1.4"/>
98.47 + </target>
98.48 + <target depends="-pre-init,-init-private,-init-user" name="-init-project">
98.49 + <property file="nbproject/configs/${config}.properties"/>
98.50 + <property file="nbproject/project.properties"/>
98.51 + </target>
98.52 + <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
98.53 + <available file="${manifest.file}" property="manifest.available"/>
98.54 + <condition property="manifest.available+main.class">
98.55 + <and>
98.56 + <isset property="manifest.available"/>
98.57 + <isset property="main.class"/>
98.58 + <not>
98.59 + <equals arg1="${main.class}" arg2="" trim="true"/>
98.60 + </not>
98.61 + </and>
98.62 + </condition>
98.63 + <condition property="manifest.available+main.class+mkdist.available">
98.64 + <and>
98.65 + <istrue value="${manifest.available+main.class}"/>
98.66 + <isset property="libs.CopyLibs.classpath"/>
98.67 + </and>
98.68 + </condition>
98.69 + <condition property="have.tests">
98.70 + <or>
98.71 + <available file="${test.src.dir}"/>
98.72 + </or>
98.73 + </condition>
98.74 + <condition property="have.sources">
98.75 + <or>
98.76 + <available file="${src.dir}"/>
98.77 + </or>
98.78 + </condition>
98.79 + <condition property="netbeans.home+have.tests">
98.80 + <and>
98.81 + <isset property="netbeans.home"/>
98.82 + <isset property="have.tests"/>
98.83 + </and>
98.84 + </condition>
98.85 + <condition property="no.javadoc.preview">
98.86 + <and>
98.87 + <isset property="javadoc.preview"/>
98.88 + <isfalse value="${javadoc.preview}"/>
98.89 + </and>
98.90 + </condition>
98.91 + <property name="run.jvmargs" value=""/>
98.92 + <property name="javac.compilerargs" value=""/>
98.93 + <property name="work.dir" value="${basedir}"/>
98.94 + <condition property="no.deps">
98.95 + <and>
98.96 + <istrue value="${no.dependencies}"/>
98.97 + </and>
98.98 + </condition>
98.99 + <property name="javac.debug" value="true"/>
98.100 + <property name="javadoc.preview" value="true"/>
98.101 + <property name="application.args" value=""/>
98.102 + <property name="source.encoding" value="${file.encoding}"/>
98.103 + <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
98.104 + <and>
98.105 + <isset property="javadoc.encoding"/>
98.106 + <not>
98.107 + <equals arg1="${javadoc.encoding}" arg2=""/>
98.108 + </not>
98.109 + </and>
98.110 + </condition>
98.111 + <property name="javadoc.encoding.used" value="${source.encoding}"/>
98.112 + <property name="includes" value="**"/>
98.113 + <property name="excludes" value=""/>
98.114 + <property name="do.depend" value="false"/>
98.115 + <condition property="do.depend.true">
98.116 + <istrue value="${do.depend}"/>
98.117 + </condition>
98.118 + <condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
98.119 + <and>
98.120 + <isset property="jaxws.endorsed.dir"/>
98.121 + <available file="nbproject/jaxws-build.xml"/>
98.122 + </and>
98.123 + </condition>
98.124 + </target>
98.125 + <target name="-post-init">
98.126 + <!-- Empty placeholder for easier customization. -->
98.127 + <!-- You can override this target in the ../build.xml file. -->
98.128 + </target>
98.129 + <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
98.130 + <fail unless="src.dir">Must set src.dir</fail>
98.131 + <fail unless="test.src.dir">Must set test.src.dir</fail>
98.132 + <fail unless="build.dir">Must set build.dir</fail>
98.133 + <fail unless="dist.dir">Must set dist.dir</fail>
98.134 + <fail unless="build.classes.dir">Must set build.classes.dir</fail>
98.135 + <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
98.136 + <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
98.137 + <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
98.138 + <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
98.139 + <fail unless="dist.jar">Must set dist.jar</fail>
98.140 + </target>
98.141 + <target name="-init-macrodef-property">
98.142 + <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
98.143 + <attribute name="name"/>
98.144 + <attribute name="value"/>
98.145 + <sequential>
98.146 + <property name="@{name}" value="${@{value}}"/>
98.147 + </sequential>
98.148 + </macrodef>
98.149 + </target>
98.150 + <target name="-init-macrodef-javac">
98.151 + <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
98.152 + <attribute default="${src.dir}" name="srcdir"/>
98.153 + <attribute default="${build.classes.dir}" name="destdir"/>
98.154 + <attribute default="${javac.classpath}" name="classpath"/>
98.155 + <attribute default="${includes}" name="includes"/>
98.156 + <attribute default="${excludes}" name="excludes"/>
98.157 + <attribute default="${javac.debug}" name="debug"/>
98.158 + <attribute default="" name="sourcepath"/>
98.159 + <element name="customize" optional="true"/>
98.160 + <sequential>
98.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}">
98.162 + <classpath>
98.163 + <path path="@{classpath}"/>
98.164 + </classpath>
98.165 + <compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
98.166 + <customize/>
98.167 + </javac>
98.168 + </sequential>
98.169 + </macrodef>
98.170 + <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
98.171 + <attribute default="${src.dir}" name="srcdir"/>
98.172 + <attribute default="${build.classes.dir}" name="destdir"/>
98.173 + <attribute default="${javac.classpath}" name="classpath"/>
98.174 + <sequential>
98.175 + <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
98.176 + <classpath>
98.177 + <path path="@{classpath}"/>
98.178 + </classpath>
98.179 + </depend>
98.180 + </sequential>
98.181 + </macrodef>
98.182 + <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
98.183 + <attribute default="${build.classes.dir}" name="destdir"/>
98.184 + <sequential>
98.185 + <fail unless="javac.includes">Must set javac.includes</fail>
98.186 + <pathconvert pathsep="," property="javac.includes.binary">
98.187 + <path>
98.188 + <filelist dir="@{destdir}" files="${javac.includes}"/>
98.189 + </path>
98.190 + <globmapper from="*.java" to="*.class"/>
98.191 + </pathconvert>
98.192 + <delete>
98.193 + <files includes="${javac.includes.binary}"/>
98.194 + </delete>
98.195 + </sequential>
98.196 + </macrodef>
98.197 + </target>
98.198 + <target name="-init-macrodef-junit">
98.199 + <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
98.200 + <attribute default="${includes}" name="includes"/>
98.201 + <attribute default="${excludes}" name="excludes"/>
98.202 + <attribute default="**" name="testincludes"/>
98.203 + <sequential>
98.204 + <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
98.205 + <batchtest todir="${build.test.results.dir}">
98.206 + <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
98.207 + <filename name="@{testincludes}"/>
98.208 + </fileset>
98.209 + </batchtest>
98.210 + <classpath>
98.211 + <path path="${run.test.classpath}"/>
98.212 + </classpath>
98.213 + <syspropertyset>
98.214 + <propertyref prefix="test-sys-prop."/>
98.215 + <mapper from="test-sys-prop.*" to="*" type="glob"/>
98.216 + </syspropertyset>
98.217 + <formatter type="brief" usefile="false"/>
98.218 + <formatter type="xml"/>
98.219 + <jvmarg line="${run.jvmargs}"/>
98.220 + </junit>
98.221 + </sequential>
98.222 + </macrodef>
98.223 + </target>
98.224 + <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
98.225 + <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
98.226 + <attribute default="${main.class}" name="name"/>
98.227 + <attribute default="${debug.classpath}" name="classpath"/>
98.228 + <attribute default="" name="stopclassname"/>
98.229 + <sequential>
98.230 + <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
98.231 + <classpath>
98.232 + <path path="@{classpath}"/>
98.233 + </classpath>
98.234 + </nbjpdastart>
98.235 + </sequential>
98.236 + </macrodef>
98.237 + <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
98.238 + <attribute default="${build.classes.dir}" name="dir"/>
98.239 + <sequential>
98.240 + <nbjpdareload>
98.241 + <fileset dir="@{dir}" includes="${fix.classes}">
98.242 + <include name="${fix.includes}*.class"/>
98.243 + </fileset>
98.244 + </nbjpdareload>
98.245 + </sequential>
98.246 + </macrodef>
98.247 + </target>
98.248 + <target name="-init-debug-args">
98.249 + <property name="version-output" value="java version "${ant.java.version}"/>
98.250 + <condition property="have-jdk-older-than-1.4">
98.251 + <or>
98.252 + <contains string="${version-output}" substring="java version "1.0"/>
98.253 + <contains string="${version-output}" substring="java version "1.1"/>
98.254 + <contains string="${version-output}" substring="java version "1.2"/>
98.255 + <contains string="${version-output}" substring="java version "1.3"/>
98.256 + </or>
98.257 + </condition>
98.258 + <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
98.259 + <istrue value="${have-jdk-older-than-1.4}"/>
98.260 + </condition>
98.261 + <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
98.262 + <os family="windows"/>
98.263 + </condition>
98.264 + <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
98.265 + <isset property="debug.transport"/>
98.266 + </condition>
98.267 + </target>
98.268 + <target depends="-init-debug-args" name="-init-macrodef-debug">
98.269 + <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
98.270 + <attribute default="${main.class}" name="classname"/>
98.271 + <attribute default="${debug.classpath}" name="classpath"/>
98.272 + <element name="customize" optional="true"/>
98.273 + <sequential>
98.274 + <java classname="@{classname}" dir="${work.dir}" fork="true">
98.275 + <jvmarg line="${debug-args-line}"/>
98.276 + <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
98.277 + <jvmarg line="${run.jvmargs}"/>
98.278 + <classpath>
98.279 + <path path="@{classpath}"/>
98.280 + </classpath>
98.281 + <syspropertyset>
98.282 + <propertyref prefix="run-sys-prop."/>
98.283 + <mapper from="run-sys-prop.*" to="*" type="glob"/>
98.284 + </syspropertyset>
98.285 + <customize/>
98.286 + </java>
98.287 + </sequential>
98.288 + </macrodef>
98.289 + </target>
98.290 + <target name="-init-macrodef-java">
98.291 + <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
98.292 + <attribute default="${main.class}" name="classname"/>
98.293 + <element name="customize" optional="true"/>
98.294 + <sequential>
98.295 + <java classname="@{classname}" dir="${work.dir}" fork="true">
98.296 + <jvmarg line="${run.jvmargs}"/>
98.297 + <classpath>
98.298 + <path path="${run.classpath}"/>
98.299 + </classpath>
98.300 + <syspropertyset>
98.301 + <propertyref prefix="run-sys-prop."/>
98.302 + <mapper from="run-sys-prop.*" to="*" type="glob"/>
98.303 + </syspropertyset>
98.304 + <customize/>
98.305 + </java>
98.306 + </sequential>
98.307 + </macrodef>
98.308 + </target>
98.309 + <target name="-init-presetdef-jar">
98.310 + <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
98.311 + <jar compress="${jar.compress}" jarfile="${dist.jar}">
98.312 + <j2seproject1:fileset dir="${build.classes.dir}"/>
98.313 + </jar>
98.314 + </presetdef>
98.315 + </target>
98.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"/>
98.317 + <!--
98.318 + ===================
98.319 + COMPILATION SECTION
98.320 + ===================
98.321 + -->
98.322 + <target depends="init" name="deps-jar" unless="no.deps"/>
98.323 + <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
98.324 + <target depends="init" name="-check-automatic-build">
98.325 + <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
98.326 + </target>
98.327 + <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
98.328 + <antcall target="clean"/>
98.329 + </target>
98.330 + <target depends="init,deps-jar" name="-pre-pre-compile">
98.331 + <mkdir dir="${build.classes.dir}"/>
98.332 + </target>
98.333 + <target name="-pre-compile">
98.334 + <!-- Empty placeholder for easier customization. -->
98.335 + <!-- You can override this target in the ../build.xml file. -->
98.336 + </target>
98.337 + <target if="do.depend.true" name="-compile-depend">
98.338 + <j2seproject3:depend/>
98.339 + </target>
98.340 + <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
98.341 + <j2seproject3:javac/>
98.342 + <copy todir="${build.classes.dir}">
98.343 + <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
98.344 + </copy>
98.345 + </target>
98.346 + <target name="-post-compile">
98.347 + <!-- Empty placeholder for easier customization. -->
98.348 + <!-- You can override this target in the ../build.xml file. -->
98.349 + </target>
98.350 + <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
98.351 + <target name="-pre-compile-single">
98.352 + <!-- Empty placeholder for easier customization. -->
98.353 + <!-- You can override this target in the ../build.xml file. -->
98.354 + </target>
98.355 + <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
98.356 + <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
98.357 + <j2seproject3:force-recompile/>
98.358 + <j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
98.359 + </target>
98.360 + <target name="-post-compile-single">
98.361 + <!-- Empty placeholder for easier customization. -->
98.362 + <!-- You can override this target in the ../build.xml file. -->
98.363 + </target>
98.364 + <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
98.365 + <!--
98.366 + ====================
98.367 + JAR BUILDING SECTION
98.368 + ====================
98.369 + -->
98.370 + <target depends="init" name="-pre-pre-jar">
98.371 + <dirname file="${dist.jar}" property="dist.jar.dir"/>
98.372 + <mkdir dir="${dist.jar.dir}"/>
98.373 + </target>
98.374 + <target name="-pre-jar">
98.375 + <!-- Empty placeholder for easier customization. -->
98.376 + <!-- You can override this target in the ../build.xml file. -->
98.377 + </target>
98.378 + <target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
98.379 + <j2seproject1:jar/>
98.380 + </target>
98.381 + <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
98.382 + <j2seproject1:jar manifest="${manifest.file}"/>
98.383 + </target>
98.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">
98.385 + <j2seproject1:jar manifest="${manifest.file}">
98.386 + <j2seproject1:manifest>
98.387 + <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
98.388 + </j2seproject1:manifest>
98.389 + </j2seproject1:jar>
98.390 + <echo>To run this application from the command line without Ant, try:</echo>
98.391 + <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
98.392 + <property location="${dist.jar}" name="dist.jar.resolved"/>
98.393 + <pathconvert property="run.classpath.with.dist.jar">
98.394 + <path path="${run.classpath}"/>
98.395 + <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
98.396 + </pathconvert>
98.397 + <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
98.398 + </target>
98.399 + <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
98.400 + <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
98.401 + <pathconvert property="run.classpath.without.build.classes.dir">
98.402 + <path path="${run.classpath}"/>
98.403 + <map from="${build.classes.dir.resolved}" to=""/>
98.404 + </pathconvert>
98.405 + <pathconvert pathsep=" " property="jar.classpath">
98.406 + <path path="${run.classpath.without.build.classes.dir}"/>
98.407 + <chainedmapper>
98.408 + <flattenmapper/>
98.409 + <globmapper from="*" to="lib/*"/>
98.410 + </chainedmapper>
98.411 + </pathconvert>
98.412 + <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
98.413 + <copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
98.414 + <fileset dir="${build.classes.dir}"/>
98.415 + <manifest>
98.416 + <attribute name="Main-Class" value="${main.class}"/>
98.417 + <attribute name="Class-Path" value="${jar.classpath}"/>
98.418 + </manifest>
98.419 + </copylibs>
98.420 + <echo>To run this application from the command line without Ant, try:</echo>
98.421 + <property location="${dist.jar}" name="dist.jar.resolved"/>
98.422 + <echo>java -jar "${dist.jar.resolved}"</echo>
98.423 + </target>
98.424 + <target name="-post-jar">
98.425 + <!-- Empty placeholder for easier customization. -->
98.426 + <!-- You can override this target in the ../build.xml file. -->
98.427 + </target>
98.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"/>
98.429 + <!--
98.430 + =================
98.431 + EXECUTION SECTION
98.432 + =================
98.433 + -->
98.434 + <target depends="init,compile" description="Run a main class." name="run">
98.435 + <j2seproject1:java>
98.436 + <customize>
98.437 + <arg line="${application.args}"/>
98.438 + </customize>
98.439 + </j2seproject1:java>
98.440 + </target>
98.441 + <target name="-do-not-recompile">
98.442 + <property name="javac.includes.binary" value=""/>
98.443 + </target>
98.444 + <target depends="init,-do-not-recompile,compile-single" name="run-single">
98.445 + <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
98.446 + <j2seproject1:java classname="${run.class}"/>
98.447 + </target>
98.448 + <!--
98.449 + =================
98.450 + DEBUGGING SECTION
98.451 + =================
98.452 + -->
98.453 + <target depends="init" if="netbeans.home" name="-debug-start-debugger">
98.454 + <j2seproject1:nbjpdastart name="${debug.class}"/>
98.455 + </target>
98.456 + <target depends="init,compile" name="-debug-start-debuggee">
98.457 + <j2seproject3:debug>
98.458 + <customize>
98.459 + <arg line="${application.args}"/>
98.460 + </customize>
98.461 + </j2seproject3:debug>
98.462 + </target>
98.463 + <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
98.464 + <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
98.465 + <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
98.466 + </target>
98.467 + <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
98.468 + <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
98.469 + <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
98.470 + <j2seproject3:debug classname="${debug.class}"/>
98.471 + </target>
98.472 + <target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
98.473 + <target depends="init" name="-pre-debug-fix">
98.474 + <fail unless="fix.includes">Must set fix.includes</fail>
98.475 + <property name="javac.includes" value="${fix.includes}.java"/>
98.476 + </target>
98.477 + <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
98.478 + <j2seproject1:nbjpdareload/>
98.479 + </target>
98.480 + <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
98.481 + <!--
98.482 + ===============
98.483 + JAVADOC SECTION
98.484 + ===============
98.485 + -->
98.486 + <target depends="init" name="-javadoc-build">
98.487 + <mkdir dir="${dist.javadoc.dir}"/>
98.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}">
98.489 + <classpath>
98.490 + <path path="${javac.classpath}"/>
98.491 + </classpath>
98.492 + <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
98.493 + <filename name="**/*.java"/>
98.494 + </fileset>
98.495 + </javadoc>
98.496 + </target>
98.497 + <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
98.498 + <nbbrowse file="${dist.javadoc.dir}/index.html"/>
98.499 + </target>
98.500 + <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
98.501 + <!--
98.502 + =========================
98.503 + JUNIT COMPILATION SECTION
98.504 + =========================
98.505 + -->
98.506 + <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
98.507 + <mkdir dir="${build.test.classes.dir}"/>
98.508 + </target>
98.509 + <target name="-pre-compile-test">
98.510 + <!-- Empty placeholder for easier customization. -->
98.511 + <!-- You can override this target in the ../build.xml file. -->
98.512 + </target>
98.513 + <target if="do.depend.true" name="-compile-test-depend">
98.514 + <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
98.515 + </target>
98.516 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
98.517 + <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
98.518 + <copy todir="${build.test.classes.dir}">
98.519 + <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
98.520 + </copy>
98.521 + </target>
98.522 + <target name="-post-compile-test">
98.523 + <!-- Empty placeholder for easier customization. -->
98.524 + <!-- You can override this target in the ../build.xml file. -->
98.525 + </target>
98.526 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
98.527 + <target name="-pre-compile-test-single">
98.528 + <!-- Empty placeholder for easier customization. -->
98.529 + <!-- You can override this target in the ../build.xml file. -->
98.530 + </target>
98.531 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
98.532 + <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
98.533 + <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
98.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}"/>
98.535 + <copy todir="${build.test.classes.dir}">
98.536 + <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
98.537 + </copy>
98.538 + </target>
98.539 + <target name="-post-compile-test-single">
98.540 + <!-- Empty placeholder for easier customization. -->
98.541 + <!-- You can override this target in the ../build.xml file. -->
98.542 + </target>
98.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"/>
98.544 + <!--
98.545 + =======================
98.546 + JUNIT EXECUTION SECTION
98.547 + =======================
98.548 + -->
98.549 + <target depends="init" if="have.tests" name="-pre-test-run">
98.550 + <mkdir dir="${build.test.results.dir}"/>
98.551 + </target>
98.552 + <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
98.553 + <j2seproject3:junit testincludes="**/*Test.java"/>
98.554 + </target>
98.555 + <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
98.556 + <fail if="tests.failed">Some tests failed; see details above.</fail>
98.557 + </target>
98.558 + <target depends="init" if="have.tests" name="test-report"/>
98.559 + <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
98.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"/>
98.561 + <target depends="init" if="have.tests" name="-pre-test-run-single">
98.562 + <mkdir dir="${build.test.results.dir}"/>
98.563 + </target>
98.564 + <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
98.565 + <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
98.566 + <j2seproject3:junit excludes="" includes="${test.includes}"/>
98.567 + </target>
98.568 + <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
98.569 + <fail if="tests.failed">Some tests failed; see details above.</fail>
98.570 + </target>
98.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"/>
98.572 + <!--
98.573 + =======================
98.574 + JUNIT DEBUGGING SECTION
98.575 + =======================
98.576 + -->
98.577 + <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
98.578 + <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
98.579 + <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
98.580 + <delete file="${test.report.file}"/>
98.581 + <mkdir dir="${build.test.results.dir}"/>
98.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}">
98.583 + <customize>
98.584 + <syspropertyset>
98.585 + <propertyref prefix="test-sys-prop."/>
98.586 + <mapper from="test-sys-prop.*" to="*" type="glob"/>
98.587 + </syspropertyset>
98.588 + <arg value="${test.class}"/>
98.589 + <arg value="showoutput=true"/>
98.590 + <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
98.591 + <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
98.592 + </customize>
98.593 + </j2seproject3:debug>
98.594 + </target>
98.595 + <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
98.596 + <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
98.597 + </target>
98.598 + <target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
98.599 + <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
98.600 + <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
98.601 + </target>
98.602 + <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
98.603 + <!--
98.604 + =========================
98.605 + APPLET EXECUTION SECTION
98.606 + =========================
98.607 + -->
98.608 + <target depends="init,compile-single" name="run-applet">
98.609 + <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
98.610 + <j2seproject1:java classname="sun.applet.AppletViewer">
98.611 + <customize>
98.612 + <arg value="${applet.url}"/>
98.613 + </customize>
98.614 + </j2seproject1:java>
98.615 + </target>
98.616 + <!--
98.617 + =========================
98.618 + APPLET DEBUGGING SECTION
98.619 + =========================
98.620 + -->
98.621 + <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
98.622 + <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
98.623 + <j2seproject3:debug classname="sun.applet.AppletViewer">
98.624 + <customize>
98.625 + <arg value="${applet.url}"/>
98.626 + </customize>
98.627 + </j2seproject3:debug>
98.628 + </target>
98.629 + <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
98.630 + <!--
98.631 + ===============
98.632 + CLEANUP SECTION
98.633 + ===============
98.634 + -->
98.635 + <target depends="init" name="deps-clean" unless="no.deps"/>
98.636 + <target depends="init" name="-do-clean">
98.637 + <delete dir="${build.dir}"/>
98.638 + <delete dir="${dist.dir}"/>
98.639 + </target>
98.640 + <target name="-post-clean">
98.641 + <!-- Empty placeholder for easier customization. -->
98.642 + <!-- You can override this target in the ../build.xml file. -->
98.643 + </target>
98.644 + <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
98.645 +</project>
99.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
99.2 +++ b/task4/solution13/nbproject/genfiles.properties Sat Oct 11 23:38:46 2008 +0200
99.3 @@ -0,0 +1,8 @@
99.4 +build.xml.data.CRC32=2ab820eb
99.5 +build.xml.script.CRC32=58a52595
99.6 +build.xml.stylesheet.CRC32=be360661
99.7 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
99.8 +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
99.9 +nbproject/build-impl.xml.data.CRC32=de21ce77
99.10 +nbproject/build-impl.xml.script.CRC32=0903858a
99.11 +nbproject/build-impl.xml.stylesheet.CRC32=e55b27f5
100.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
100.2 +++ b/task4/solution13/nbproject/project.properties Sat Oct 11 23:38:46 2008 +0200
100.3 @@ -0,0 +1,68 @@
100.4 +application.title=currency
100.5 +application.vendor=apidesign.org
100.6 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
100.7 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
100.8 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=default
100.9 +build.classes.dir=${build.dir}/classes
100.10 +build.classes.excludes=**/*.java,**/*.form
100.11 +# This directory is removed when the project is cleaned:
100.12 +build.dir=build
100.13 +build.generated.dir=${build.dir}/generated
100.14 +# Only compile against the classpath explicitly listed here:
100.15 +build.sysclasspath=ignore
100.16 +build.test.classes.dir=${build.dir}/test/classes
100.17 +build.test.results.dir=${build.dir}/test/results
100.18 +debug.classpath=\
100.19 + ${run.classpath}
100.20 +debug.test.classpath=\
100.21 + ${run.test.classpath}
100.22 +# This directory is removed when the project is cleaned:
100.23 +dist.dir=dist
100.24 +dist.jar=${dist.dir}/currency.jar
100.25 +dist.javadoc.dir=${dist.dir}/javadoc
100.26 +excludes=
100.27 +file.reference.junit-4.4.jar=../../libs/junit-4.4.jar
100.28 +file.reference.src-apifest08=..
100.29 +includes=**
100.30 +jar.compress=false
100.31 +javac.classpath=
100.32 +# Space-separated list of extra javac options
100.33 +javac.compilerargs=-Xlint:unchecked
100.34 +javac.deprecation=false
100.35 +javac.source=1.5
100.36 +javac.target=1.5
100.37 +javac.test.classpath=\
100.38 + ${javac.classpath}:\
100.39 + ${build.classes.dir}:\
100.40 + ${file.reference.junit-4.4.jar}
100.41 +javadoc.additionalparam=
100.42 +javadoc.author=false
100.43 +javadoc.encoding=
100.44 +javadoc.noindex=false
100.45 +javadoc.nonavbar=false
100.46 +javadoc.notree=false
100.47 +javadoc.private=false
100.48 +javadoc.splitindex=true
100.49 +javadoc.use=true
100.50 +javadoc.version=false
100.51 +javadoc.windowtitle=
100.52 +jnlp.codebase.type=local
100.53 +jnlp.codebase.url=file:/home/jarda/src/apifest08/currency/dist
100.54 +jnlp.descriptor=application
100.55 +jnlp.enabled=false
100.56 +jnlp.offline-allowed=false
100.57 +jnlp.signed=false
100.58 +meta.inf.dir=${src.dir}/META-INF
100.59 +platform.active=default_platform
100.60 +run.classpath=\
100.61 + ${javac.classpath}:\
100.62 + ${build.classes.dir}
100.63 +# Space-separated list of JVM arguments used when running the project
100.64 +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
100.65 +# or test-sys-prop.name=value to set system properties for unit tests):
100.66 +run.jvmargs=
100.67 +run.test.classpath=\
100.68 + ${javac.test.classpath}:\
100.69 + ${build.test.classes.dir}
100.70 +src.dir=src
100.71 +test.src.dir=test
101.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
101.2 +++ b/task4/solution13/nbproject/project.xml Sat Oct 11 23:38:46 2008 +0200
101.3 @@ -0,0 +1,16 @@
101.4 +<?xml version="1.0" encoding="UTF-8"?>
101.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
101.6 + <type>org.netbeans.modules.java.j2seproject</type>
101.7 + <configuration>
101.8 + <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
101.9 + <name>Currency Convertor Solution 13</name>
101.10 + <minimum-ant-version>1.6.5</minimum-ant-version>
101.11 + <source-roots>
101.12 + <root id="src.dir"/>
101.13 + </source-roots>
101.14 + <test-roots>
101.15 + <root id="test.src.dir"/>
101.16 + </test-roots>
101.17 + </data>
101.18 + </configuration>
101.19 +</project>
102.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
102.2 +++ b/task4/solution13/src/org/apidesign/apifest08/currency/ConversionNotSupportedException.java Sat Oct 11 23:38:46 2008 +0200
102.3 @@ -0,0 +1,85 @@
102.4 +package org.apidesign.apifest08.currency;
102.5 +
102.6 +/**
102.7 + * Conversion not suported exception. This expecption may optionaly describe which conversion was required and failed.
102.8 + * Required conversion can be found in {@link #getFromCurrecyCode() } and {@link #getToCurrecyCode() }.
102.9 + *
102.10 + * @author arnostvalicek
102.11 + * @since version2
102.12 + */
102.13 +public class ConversionNotSupportedException extends ConvertorException {
102.14 + String from;
102.15 + String to;
102.16 + boolean reversed;
102.17 +
102.18 + public ConversionNotSupportedException() {
102.19 + super();
102.20 + }
102.21 +
102.22 + public ConversionNotSupportedException(String message) {
102.23 + super(message);
102.24 + }
102.25 +
102.26 + public ConversionNotSupportedException(String message, Throwable cause) {
102.27 + super(message, cause);
102.28 + }
102.29 +
102.30 + public ConversionNotSupportedException(Throwable cause) {
102.31 + super(cause);
102.32 + }
102.33 +
102.34 + /**
102.35 + * Create exception witd additional information about currencies which are not supported in coversion.
102.36 + * @param from Code of source currency.
102.37 + * @param to Code of target currency.
102.38 + * @param twoWay Set to <code>false</code> if <em>From->To</em> is not supported.
102.39 + * Set to <code>true</code> if both ways <em>From->To</em> and <em>To->From</em> conversions are not supported.
102.40 + *
102.41 + */
102.42 + public ConversionNotSupportedException(String from, String to, boolean twoWay) {
102.43 + this.from = from;
102.44 + this.to = to;
102.45 + this.reversed = true;
102.46 + }
102.47 +
102.48 + @Override
102.49 + public String toString() {
102.50 + if (from!=null && to !=null) {
102.51 + if (reversed) {
102.52 + return "Neither onversion nor reverted conversion from " + from + " to " + to + " is not supported,";
102.53 + } else {
102.54 + return "Conversion from " + from + " to " + to + " is not supported,";
102.55 + }
102.56 + } else {
102.57 + return super.toString();
102.58 + }
102.59 + }
102.60 +
102.61 + /**
102.62 + * Returns code of source currency. This value may be null.
102.63 + * @return Returns code of source currency.
102.64 + */
102.65 + public String getFromCurrecyCode() {
102.66 + return from;
102.67 + }
102.68 +
102.69 + /**
102.70 + * Returns code of target currency. This value may be null.
102.71 + * @return Returns code of target currency.
102.72 + */ public String getToCurrecyCode() {
102.73 + return to;
102.74 + }
102.75 +
102.76 + /**
102.77 + * Returns if one way or two way conversion is not supported.
102.78 + *
102.79 + * Value <code>false</code> means one way conversion is not supported.
102.80 + * Value <code>true</code> means that neither direct nor back conversion is not supported.
102.81 + *
102.82 + * @return Returs <code>false</code> for one way conversion, <code>true</code> for two way conversion.
102.83 + */
102.84 + public boolean getTwoWayConversion() {
102.85 + return reversed;
102.86 + }
102.87 +
102.88 +}
103.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
103.2 +++ b/task4/solution13/src/org/apidesign/apifest08/currency/ConversionResult.java Sat Oct 11 23:38:46 2008 +0200
103.3 @@ -0,0 +1,49 @@
103.4 +
103.5 +package org.apidesign.apifest08.currency;
103.6 +
103.7 +import java.math.BigDecimal;
103.8 +
103.9 +/**
103.10 + * Result of currency conversion. Holds converted value and remainder.
103.11 + * <p>
103.12 + * <em>Converted</em> describes value converted to <em>target</em> currenty. <em>Remainder</em> describes
103.13 + * how much from original <em>amount</em> was not possible to convert. Convertor never loses any (small) money
103.14 + * in conversion error (rounding), but instead of rounding is converts only as much as possible and keeps rest as remainder.
103.15 + *
103.16 + * @author arnostvalicek
103.17 + */
103.18 +public class ConversionResult {
103.19 + private BigDecimal converted;
103.20 + private BigDecimal remainder;
103.21 +
103.22 + /**
103.23 + * Get converted value.
103.24 + * @return Returns converted value.
103.25 + */
103.26 + public BigDecimal getConverted() {
103.27 + return converted;
103.28 + }
103.29 +
103.30 + void setConverted(BigDecimal converted) {
103.31 + this.converted = converted;
103.32 + }
103.33 +
103.34 +
103.35 + /**
103.36 + * Get remainder of conversion. Remainder is set if part of converted amount which can't be converted
103.37 + * because this target currency precision can't handle small numbers. Remainder value is in <em>from currency</em>
103.38 + * <p>
103.39 + * Converter never loses any precision in conversion. Remainer describes how much of amount can't be converted.
103.40 + * If we substract <em>remainder</em> from <em>amount</em> we will be able to get exact conversion.
103.41 + *
103.42 + * @return Returns remainder of conversion.
103.43 + */
103.44 + public BigDecimal getRemainder() {
103.45 + return remainder;
103.46 + }
103.47 +
103.48 + void setRemainder(BigDecimal remainder) {
103.49 + this.remainder = remainder;
103.50 + }
103.51 +
103.52 +}
104.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
104.2 +++ b/task4/solution13/src/org/apidesign/apifest08/currency/Convertor.java Sat Oct 11 23:38:46 2008 +0200
104.3 @@ -0,0 +1,218 @@
104.4 +package org.apidesign.apifest08.currency;
104.5 +
104.6 +import java.math.BigDecimal;
104.7 +import java.math.MathContext;
104.8 +import java.math.RoundingMode;
104.9 +
104.10 +/** Convertor able to convert amount from one currency to other currency.
104.11 + * <p>
104.12 + * Conversion method are:
104.13 + * <ul>
104.14 + * <li>{@link #convert(ConvertorCurrency, ConvertorCurrency, BigDecimal)} - convert
104.15 + * using exchange rate specified in exchange rate provide. This method is not try
104.16 + * use reverted excahnage rate.
104.17 + * <li>{@link #convertWithReversibleRates(ConvertorCurrency, ConvertorCurrency, BigDecimal)} -
104.18 + * convert using exchange rate specified in exchange rate provide. This method
104.19 + * is not trying to use reverted exchange rate.
104.20 + * </ul>
104.21 + *
104.22 + * Exchange rate is provided by {@link ExchangeRateProvider}.
104.23 + */
104.24 +public class Convertor {
104.25 + private Convertor[] convertors;
104.26 +
104.27 + /** Create new <code>Convertor</code> as merge of provided convertors. Merged convertor will use
104.28 + * provided convertors to convert between currencies.
104.29 + * <p>
104.30 + * Only one should be able to provide conversion between currencies. If more than one convertos
104.31 + * are able to convert currency, one of conversions will be used (it is not defined which).
104.32 + *
104.33 + * @since version 2
104.34 + * @param convertors Convertor used to create merge-convertor.
104.35 + * @return Returns new convertor instance.
104.36 + */
104.37 + public static Convertor createConvertorAsMerge(Convertor[] convertors) {
104.38 + return new Convertor(convertors);
104.39 + }
104.40 +
104.41 + boolean remainderAllowed = true; //if false, remained is not allowed (should be true ideally, but can't handle it now)
104.42 + ExchangeRateProvider exchangeRateProvider;
104.43 +
104.44 + /** Create simle convertor.
104.45 + */
104.46 + private Convertor() {
104.47 + this.convertors=new Convertor[0];
104.48 + }
104.49 +
104.50 + /** Create merge convertor.
104.51 + */
104.52 + private Convertor(Convertor[] convertors) {
104.53 + this.convertors = convertors;
104.54 + }
104.55 +
104.56 + /**
104.57 + * Create new <code>Convertor</code> using <code>ExchangeRateProvider</code>.
104.58 + *
104.59 + * @param exchangeRateProvider {@link ExchangeRateProvider} used to get exchange rate.
104.60 + *
104.61 + * @return Returns <code>Convertor</code> which can be used to convert money.
104.62 + * @since version1
104.63 + */
104.64 + public static Convertor createConvertor(ExchangeRateProvider exchangeRateProvider) {
104.65 + Convertor c = new Convertor();
104.66 +
104.67 + c.exchangeRateProvider = exchangeRateProvider;
104.68 + return c;
104.69 + }
104.70 +
104.71 + /**
104.72 + * Convert <code>amount</code> from <code>fromCurrency</code> to <code>toCurrency</code> as specified
104.73 + * in <code>ExchangeRateProvider</code>.
104.74 + *
104.75 + * @param amount Amount which should be converted. Can't be negative value (can be zero or positive).
104.76 + * @return Return <code>ConversionResult</code> which holds conversion result.
104.77 + * @since version1
104.78 + * @deprecated since version2. Use {@link #convert(ConvertorCurrency, ConvertorCurrency, BigDecimal) } - explicitly specify conversion currencies.
104.79 + */
104.80 + public ConversionResult convert(BigDecimal amount) {
104.81 + return convertValue(exchangeRateProvider.getFromCurrency(), exchangeRateProvider.getToCurrency(),amount, false,false);
104.82 + }
104.83 +
104.84 + /**
104.85 + * Convert <code>amount</code> from <code>toCurrency</code> to <code>fromCurrency</code> as specified
104.86 + * in <code>ExchangeRateProvider</code>. This is <em>reverted</em> order than suggested by names of currency fields in <code>ExchangeRate</code>.
104.87 + *
104.88 + * @param amount Amount which should be converted. Can't be negative value (can be zero or positive).
104.89 + * @return Return <code>ConversionResult</code> which holds conversion result.
104.90 + * @since version1
104.91 + * @deprecated since version2. Use {@link #convert(ConvertorCurrency, ConvertorCurrency, BigDecimal) } - explicitly specify conversion currencies.
104.92 + */
104.93 + public ConversionResult convertBack(BigDecimal amount) {
104.94 + return convertValue(exchangeRateProvider.getFromCurrency(), exchangeRateProvider.getToCurrency(),amount, true,false);
104.95 + }
104.96 +
104.97 + private ConversionResult convertUsingSimpleConvertor(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency, boolean reversibleExRate, BigDecimal amount, boolean convertBack) throws ConversionNotSupportedException, RuntimeException {
104.98 + ConversionResult result = new ConversionResult();
104.99 +
104.100 + //ExchangeRate rate = exchangeRateProvider.getExchangeRate();
104.101 + ExchangeRate rate;
104.102 + if (reversibleExRate) {
104.103 + rate = exchangeRateProvider.getReversibleExchangeRate(fromCurrency, toCurrency);
104.104 + } else {
104.105 + rate = exchangeRateProvider.getExchangeRate(fromCurrency, toCurrency);
104.106 + }
104.107 + if (rate == null) {
104.108 + return null;
104.109 + }
104.110 +
104.111 + int fromFranctionDigits = fromCurrency.getDefaultFractionDigits();
104.112 + int toFractionDigits = toCurrency.getDefaultFractionDigits();
104.113 +
104.114 + if (toFractionDigits != 2) {
104.115 + throw new ConvertorException("Can't process currency with defaultFractionDigits!=2, " + exchangeRateProvider.getToCurrency() + " has " + toFractionDigits + " defaultFractionDigits");
104.116 + }
104.117 + if (fromFranctionDigits != 2) {
104.118 + throw new ConvertorException("Can't process currency with defaultFractionDigits!=2, " + exchangeRateProvider.getFromCurrency() + " has " + fromFranctionDigits + " defaultFractionDigits");
104.119 + }
104.120 +
104.121 + if (amount.signum() == -1) {
104.122 + throw new RuntimeException("Can convert only non-negative value, current value is " + amount);
104.123 + }
104.124 +
104.125 +
104.126 + MathContext context = new MathContext(0, RoundingMode.DOWN);
104.127 +
104.128 + BigDecimal from;
104.129 + BigDecimal to;
104.130 + if (convertBack) {
104.131 + //converting in reverted way
104.132 + to = rate.getFromValue();
104.133 + from = rate.getToValue();
104.134 + } else {
104.135 + //converting in normal way
104.136 + from = rate.getFromValue();
104.137 + to = rate.getToValue();
104.138 + }
104.139 +
104.140 + BigDecimal amountCent = amount.movePointRight(toFractionDigits);
104.141 +
104.142 + final BigDecimal multiplied = amountCent.multiply(to, context);
104.143 + BigDecimal[] division = multiplied.divideAndRemainder(from, context);
104.144 +
104.145 + if (!remainderAllowed && !(BigDecimal.ZERO.equals(division[1]))) {
104.146 + throw new RuntimeException("Remained is not allowed - remaining amount is " + division[1] + " cents");
104.147 + } else {
104.148 + result.setRemainder(BigDecimal.ZERO);
104.149 + }
104.150 +
104.151 + BigDecimal converted = division[0].movePointLeft(toFractionDigits);
104.152 + converted = converted.setScale(toFractionDigits); //XXX ugly
104.153 + result.setConverted(converted);
104.154 + //result.setRemainder(...);
104.155 + return result;
104.156 + }
104.157 +
104.158 +
104.159 + private ConversionResult convertValue(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency,BigDecimal amount, boolean convertBack,boolean reversibleExRate) throws RuntimeException {
104.160 + //result.setRemainder(...);
104.161 + if (convertors.length==0) {
104.162 + return convertUsingSimpleConvertor(fromCurrency, toCurrency, reversibleExRate, amount, convertBack);
104.163 + } else {
104.164 + ConversionResult result = null;
104.165 + for (int i = 0;i<convertors.length;i++) {
104.166 + Convertor subConvertor = convertors[i];
104.167 + result = subConvertor.convertValue(fromCurrency, toCurrency, amount, convertBack, reversibleExRate);
104.168 + if (result!=null) {
104.169 + break;
104.170 + }
104.171 + }
104.172 + return result;
104.173 + }
104.174 + }
104.175 +
104.176 + /**
104.177 + * Convert <code>value</code> from <code>fromCurrency</code> to <code>toCurrency</code>.
104.178 + * <p>
104.179 + * Exchange rate is provided by exchange rate provider which was specified when Convertor was created.
104.180 + * This method is using only exchange rate from->to and not trying to use reverted excange rate to->from.
104.181 + *
104.182 + * @param fromCurrency Source currency to convert from.
104.183 + * @param toCurrency Target currency to convert to.
104.184 + * @param value Value in source currency which should be converted.
104.185 + * @return Return conversion result.
104.186 + * @since version2
104.187 + * @throws ConversionNotSupportedException If conversion from <code>fromCurrency</code> to <code>toCurrency</code> is not supported.
104.188 + */
104.189 + public ConversionResult convert(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency, BigDecimal value) {
104.190 + ConversionResult result = convertValue(fromCurrency, toCurrency, value, false,false);
104.191 + if (result==null) {
104.192 + //throw new ConversionNotSupportedException("Conversion from " + fromCurrency + " to " + toCurrency + " is not supported");
104.193 + throw new ConversionNotSupportedException(fromCurrency.getCurrencyCode(),toCurrency.getCurrencyCode(),false);
104.194 + }
104.195 + return result;
104.196 + }
104.197 +
104.198 + /**
104.199 + * Convert <code>value</code> from <code>fromCurrency</code> to <code>toCurrency</code>.
104.200 + * Exchange rate is provided by exchange rate provider which was specified when Convertor was created.
104.201 + * <p>
104.202 + * This method is using only exchange rate from->to and if not found, it is trying to use reverted excange rate to->from.
104.203 + *
104.204 + * @param fromCurrency Source currency to convert from.
104.205 + * @param toCurrency Target currency to convert to.
104.206 + * @param value Value in source currency which should be converted.
104.207 + * @return Return conversion result.
104.208 + * @since version2
104.209 + * @throws ConversionNotSupportedException If conversion from <code>fromCurrency</code> to <code>toCurrency</code>
104.210 + * is not supported and neither conversion from <code>toCurrency</code> to <code>fromCurrency</code> is not supported.
104.211 + */
104.212 + public ConversionResult convertWithReversibleRates(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency, BigDecimal value) {
104.213 + ConversionResult result = convertValue(fromCurrency, toCurrency, value, false,true);
104.214 + if (result==null) {
104.215 + //throw new ConversionNotSupportedException("Neither onversion nor reverted conversion from " + fromCurrency + " to " + toCurrency + " is not supported,");
104.216 + throw new ConversionNotSupportedException(fromCurrency.getCurrencyCode(),toCurrency.getCurrencyCode(),true);
104.217 + }
104.218 + return result;
104.219 + }
104.220 +
104.221 +}
105.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
105.2 +++ b/task4/solution13/src/org/apidesign/apifest08/currency/ConvertorCurrency.java Sat Oct 11 23:38:46 2008 +0200
105.3 @@ -0,0 +1,70 @@
105.4 +
105.5 +package org.apidesign.apifest08.currency;
105.6 +
105.7 +import java.util.Currency;
105.8 +
105.9 +/**
105.10 + * Desription of currency.
105.11 + *
105.12 + * Java has similar class {@link java.util.Currency}, but original class is not flexible
105.13 + * enough, we use our own implementation of currency.
105.14 + *
105.15 + * @author arnostvalicek
105.16 + */
105.17 +public class ConvertorCurrency {
105.18 +
105.19 + private Currency currency;
105.20 +
105.21 + private void setJavaCurrency(Currency javaCurrency) {
105.22 + this.currency = javaCurrency;
105.23 + }
105.24 +
105.25 + /**
105.26 + * Static method providing instance of <code>ConvertorCurrency</code> base of currency code.
105.27 + *
105.28 + * @param currencyCode Code of required currency.
105.29 + * @return Returns required <code>ConvertorCurrency</code>
105.30 + */
105.31 + public static ConvertorCurrency getInstance(String currencyCode) {
105.32 + ConvertorCurrency convertorCurrency = new ConvertorCurrency();
105.33 + convertorCurrency.setJavaCurrency(Currency.getInstance(currencyCode));
105.34 + return convertorCurrency;
105.35 + }
105.36 +
105.37 + /**
105.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.
105.39 + * @return Returns the default number of fraction digits used with this currency.
105.40 + */
105.41 + public int getDefaultFractionDigits() {
105.42 + return currency.getDefaultFractionDigits();
105.43 + }
105.44 +
105.45 + @Override
105.46 + public boolean equals(Object obj) {
105.47 + boolean result;
105.48 + if (obj instanceof ConvertorCurrency) {
105.49 + ConvertorCurrency that = (ConvertorCurrency) obj;
105.50 + result = currency.equals(that.currency);
105.51 + } else {
105.52 + result = false;
105.53 + }
105.54 + return result;
105.55 + }
105.56 +
105.57 + @Override
105.58 + public int hashCode() {
105.59 + return currency==null ? 47/*??*/ : currency.hashCode();
105.60 + }
105.61 +
105.62 +
105.63 +
105.64 +
105.65 + @Override
105.66 + public String toString() {
105.67 + return "ConvertorCurrency[" + (currency != null ? currency.toString() : "NO-BASE-CURRENCY")+"]";
105.68 + }
105.69 +
105.70 + String getCurrencyCode() {
105.71 + return currency.getCurrencyCode();
105.72 + }
105.73 +}
106.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
106.2 +++ b/task4/solution13/src/org/apidesign/apifest08/currency/ConvertorException.java Sat Oct 11 23:38:46 2008 +0200
106.3 @@ -0,0 +1,25 @@
106.4 +package org.apidesign.apifest08.currency;
106.5 +
106.6 +/**
106.7 + * Common Convertor exception.
106.8 + *
106.9 + * @author arnostvalicek
106.10 + */
106.11 +public class ConvertorException extends RuntimeException {
106.12 +
106.13 + public ConvertorException(Throwable cause) {
106.14 + super(cause);
106.15 + }
106.16 +
106.17 + public ConvertorException(String message, Throwable cause) {
106.18 + super(message, cause);
106.19 + }
106.20 +
106.21 + public ConvertorException(String message) {
106.22 + super(message);
106.23 + }
106.24 +
106.25 + public ConvertorException() {
106.26 + }
106.27 +
106.28 +}
107.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
107.2 +++ b/task4/solution13/src/org/apidesign/apifest08/currency/ExchangeRate.java Sat Oct 11 23:38:46 2008 +0200
107.3 @@ -0,0 +1,68 @@
107.4 +
107.5 +package org.apidesign.apifest08.currency;
107.6 +
107.7 +import java.math.BigDecimal;
107.8 +
107.9 +/**
107.10 + * Exchange rate value. Contains <code>from</code> and <code>to</code> value.
107.11 + *
107.12 + * @author arnostvalicek
107.13 + */
107.14 +public class ExchangeRate {
107.15 + private BigDecimal numberFor;
107.16 + private BigDecimal numberGet;
107.17 +
107.18 + /**
107.19 + * Constructor for new exchange rate holding two values - <em>from value</em> and <em>to value</em>
107.20 + * @param fromValue Exchange rate <em>from value</em>
107.21 + * @param toValue Exchange rate <em>to value</em>
107.22 + */
107.23 + public ExchangeRate(BigDecimal fromValue, BigDecimal toValue) {
107.24 + this.numberFor = fromValue;
107.25 + this.numberGet = toValue;
107.26 + }
107.27 +
107.28 + /**
107.29 + * Create new instance of <code>ExchangeRate</code> based on provided exchange rate, but swapping its
107.30 + * <em>from</em> and <em>to</em> value.
107.31 + * <p>
107.32 + * Provided exchange rate is not chaged, this method returns different instance describing reverted exchange rate.
107.33 + *
107.34 + * @param rate Exchange rate which describes rate to be reverted.
107.35 + * @return Instance of reverted rate.
107.36 + */
107.37 + public static ExchangeRate createRevertedRate(ExchangeRate rate) {
107.38 + ExchangeRate reverted = new ExchangeRate(rate.getToValue(), rate.getFromValue());
107.39 + return reverted;
107.40 + }
107.41 +
107.42 + @Override
107.43 + public String toString() {
107.44 + return "for "+numberFor+" recieve "+numberGet+" @"+getClass().getName();
107.45 + }
107.46 +
107.47 + /**
107.48 + * Return exchange rate <em>from</em> value stored in this object.
107.49 + * @return Returns <em>from</em> value for this exchange rate.
107.50 + */
107.51 + public BigDecimal getFromValue() {
107.52 + return numberFor;
107.53 + }
107.54 +
107.55 + /**
107.56 + * Return exchange rate <em>to</em> value stored in this object.
107.57 + * @return Returns <em>to</em> value for this exchange rate.
107.58 + */
107.59 + public BigDecimal getToValue() {
107.60 + return numberGet;
107.61 + }
107.62 +
107.63 +
107.64 +// public ExchangeRate createExchangeRate(BigDecimal forValue, BigDecimal getValue) {
107.65 +// ExchangeRate rate = new ExchangeRate(forValue, getValue);
107.66 +// return rate;
107.67 +// }
107.68 +
107.69 +
107.70 +
107.71 +}
108.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
108.2 +++ b/task4/solution13/src/org/apidesign/apifest08/currency/ExchangeRateProvider.java Sat Oct 11 23:38:46 2008 +0200
108.3 @@ -0,0 +1,267 @@
108.4 +package org.apidesign.apifest08.currency;
108.5 +
108.6 +import java.math.BigDecimal;
108.7 +import java.util.Date;
108.8 +import java.util.HashMap;
108.9 +import java.util.Map;
108.10 +
108.11 +/**
108.12 + * Exchange rate provider. Provides exchange rate for two currencies (method {@link #getExchangeRate(ConvertorCurrency, ConvertorCurrency)} ).
108.13 + * <p>
108.14 + * Several method can be created to create <code>ExchangeRateProvider</code>:
108.15 + * <ul>
108.16 + * <li>{@link #createExchangeRateProvider() } - create <em>simple</em> exchange rate provider using fixed echange rate.
108.17 + * <li>{@link #createExchangeRateProvider(IExchangeRateEngine) } - create exchange rate provider using custom {@link IExchangeRateEngine}.
108.18 + * </ul>
108.19 + * <p>
108.20 + * Date dependend exchange rate to be implemented.
108.21 + *
108.22 + * @author arnostvalicek
108.23 + */
108.24 +public class ExchangeRateProvider {
108.25 +
108.26 + IExchangeRateEngine exrateEngine;
108.27 +
108.28 + /**
108.29 + * Simple constructor for <code>ExchangeRateProviderM</code> which can provide fixed exchange rate.
108.30 + *
108.31 + * Describes conversion <em>from ONE</em> to <em>to ONE</em> currency.
108.32 + *
108.33 + * @param fromValue From value. BigDecimal value, precision should be set to currency precision.
108.34 + * @param fromCurrency From currency.
108.35 + * @param toValue To value. BigDecimal value, precision should be set to currency precision.
108.36 + * @param toCurrency To currency.
108.37 + * @deprecated deprecated since task2. Use {@link #createExchangeRateProvider() } instead of this constructor.
108.38 + */
108.39 + public ExchangeRateProvider(BigDecimal fromValue, ConvertorCurrency fromCurrency, BigDecimal toValue, ConvertorCurrency toCurrency) {
108.40 + this.exrateEngine = FixedOneExchangeRateEngine.createEngine(fromValue, fromCurrency, toValue, toCurrency);
108.41 + }
108.42 +
108.43 + private ExchangeRateProvider() {
108.44 + }
108.45 +
108.46 + /**
108.47 + * Static method to create new exchange rate provider. This exchange rate provider does not contain
108.48 + * any exchange rates (this is difference to public constructor).
108.49 + * @return New <code>ExchangeRateProvider</code>
108.50 + */
108.51 + public static ExchangeRateProvider createExchangeRateProvider() {
108.52 + ExchangeRateProvider provider = new ExchangeRateProvider();
108.53 + provider.exrateEngine = FixedExchangeRateEngine.createEngine();
108.54 + return provider;
108.55 + }
108.56 +
108.57 + /**
108.58 + * Static method to create exchange rate provider which is using provided <code>IExchangeRateEngine</code>. This exchange rate provider is using
108.59 + * <code>IExchangeRateEngine</code> to get actual exchange rate.
108.60 + * @param exchangeRateEngine <code>IExchangeRateEngine</code> used to get exchange rate.
108.61 + * @return Returns instance of <code>ExchangeRateProvider</code>
108.62 + */
108.63 + public static ExchangeRateProvider createExchangeRateProvider(IExchangeRateEngine exchangeRateEngine) {
108.64 + ExchangeRateProvider provider = new ExchangeRateProvider();
108.65 + provider.exrateEngine = exchangeRateEngine;
108.66 + return provider;
108.67 + }
108.68 +
108.69 + /**
108.70 + * Add new exchange rate to <code></code> to this <em>simple</em> exchange rate provider.
108.71 + * <p>
108.72 + * Example of specifiing conversion rate: 100 SKK == 80 CZK:<br>
108.73 + * <code>addFixedCurencyRate(ConvertorCurrency.getInstance("SKK"), new BigDecimal(100), ConvertorCurrency.getInstance("CZK"), new BigDecimal(80));</code>
108.74 + * <p>
108.75 + * This method may be used <em>only</em> when <code>ExchangeRateProvider</code> is created using {@link #createExchangeRateProvider() } - creating exchange rate provider without external <code>IExchangeRateEngine</code>.
108.76 + *
108.77 + * @param fromCurrency Source currency.
108.78 + * @param fromValue Valye for from currency.
108.79 + * @param toCurrency Target currency.
108.80 + * @param toValue Value for target currency.
108.81 + * @throws IllegalStateException Throws exception when adding fixed currency rate to exchange rate provider which is not created using {@link #createExchangeRateProvider() }.
108.82 + */
108.83 + public synchronized void addFixedCurencyRate(ConvertorCurrency fromCurrency, BigDecimal fromValue, ConvertorCurrency toCurrency, BigDecimal toValue) {
108.84 + if (exrateEngine instanceof FixedExchangeRateEngine) {
108.85 + ((FixedExchangeRateEngine) exrateEngine).addFixedCurencyRate(fromCurrency, fromValue, toCurrency, toValue);
108.86 + } else {
108.87 + throw new IllegalStateException("Cuurency rate can be added only to ExchangeRateProvider created with FixedExchangeRateEngine - using method createExchangeRateProvider()");
108.88 + }
108.89 + }
108.90 +
108.91 + /**
108.92 + * Get fixed exange rate for currencies (from->to).
108.93 + * @return Returns exchange rate.
108.94 + * @deprecated deprecated since task2. Use {@link #getExchangeRate(ConvertorCurrency, ConvertorCurrency) }
108.95 + */
108.96 + public ExchangeRate getExchangeRate() {
108.97 + //works only for FixedExchangeRateEngine
108.98 + if (exrateEngine instanceof FixedOneExchangeRateEngine) {
108.99 + FixedOneExchangeRateEngine engine = (FixedOneExchangeRateEngine) exrateEngine;
108.100 + return new ExchangeRate(engine.getFromValue(), engine.getToValue());
108.101 + } else {
108.102 + throw new IllegalStateException("Method supported only for MinimalFixedExchangeRateEngine. This method is deprecated");
108.103 + }
108.104 +
108.105 + }
108.106 +
108.107 + /**
108.108 + * Get fixed exange rate for currencies (from->to).
108.109 + * @return Returns exchange rate or <code>null</code> if exchange rate not found.
108.110 + */
108.111 + public ExchangeRate getExchangeRate(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency) {
108.112 + return getExchangeRateImpl(fromCurrency, toCurrency);
108.113 + }
108.114 +
108.115 + /**
108.116 + * Get fixed exange rate for currencies (from->to) or reversed exchange rate (to->from).
108.117 + * @return Returns exchange rate or <code>null</code> if exchange rate not found.
108.118 + */
108.119 + public ExchangeRate getReversibleExchangeRate(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency) {
108.120 + ExchangeRate rate = getExchangeRateImpl(fromCurrency, toCurrency);
108.121 + if (rate == null) {
108.122 + ExchangeRate revertedRate = getExchangeRateImpl(toCurrency, fromCurrency);
108.123 + if (revertedRate != null) {
108.124 + rate = ExchangeRate.createRevertedRate(revertedRate);
108.125 + }
108.126 + }
108.127 + return rate;
108.128 + }
108.129 +
108.130 + /**
108.131 + * Get exchange rate for currencies (from->to) based on provided date.
108.132 + * @param date Date for which exchange rate should be provided.
108.133 + * @return Returns exchange rate
108.134 + * @deprecated deprecated since task2. No real implementation in version2.
108.135 + */
108.136 + public ExchangeRate getExchangeRate(Date date) {
108.137 + //works only for FixedExchangeRateEngine
108.138 + if (exrateEngine instanceof FixedOneExchangeRateEngine) {
108.139 + FixedOneExchangeRateEngine engine = (FixedOneExchangeRateEngine) exrateEngine;
108.140 + return new ExchangeRate(engine.getFromValue(), engine.getToValue());
108.141 + } else {
108.142 + throw new IllegalStateException("Method supported only for FixedOneExchangeRateEngine. This method is deprecated");
108.143 + }
108.144 + }
108.145 +
108.146 + ConvertorCurrency getFromCurrency() {
108.147 + if (exrateEngine instanceof FixedOneExchangeRateEngine) {
108.148 + FixedOneExchangeRateEngine engine = (FixedOneExchangeRateEngine) exrateEngine;
108.149 + return engine.getFromCurrency();
108.150 + } else {
108.151 + throw new IllegalStateException("Method supported only for FixedOneExchangeRateEngine. This method is deprecated");
108.152 + }
108.153 + }
108.154 +
108.155 + ConvertorCurrency getToCurrency() {
108.156 + if (exrateEngine instanceof FixedOneExchangeRateEngine) {
108.157 + FixedOneExchangeRateEngine engine = (FixedOneExchangeRateEngine) exrateEngine;
108.158 + return engine.getToCurrency();
108.159 + } else {
108.160 + throw new IllegalStateException("Method supported only for FixedOneExchangeRateEngine. This method is deprecated");
108.161 + }
108.162 + }
108.163 +
108.164 + private ExchangeRate getExchangeRateImpl(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency) {
108.165 + ExchangeRate result = exrateEngine.getExchangeRate(fromCurrency, toCurrency);
108.166 + return result;
108.167 + }
108.168 +
108.169 + private static class FixedOneExchangeRateEngine implements IExchangeRateEngine {
108.170 +
108.171 + BigDecimal fromValue;
108.172 + ConvertorCurrency fromCurrency;
108.173 + BigDecimal toValue;
108.174 + ConvertorCurrency toCurrency;
108.175 +
108.176 + private FixedOneExchangeRateEngine(BigDecimal fromValue, ConvertorCurrency fromCurrency, BigDecimal toValue, ConvertorCurrency toCurrency) {
108.177 + this.fromValue = fromValue;
108.178 + this.toValue = toValue;
108.179 + this.fromCurrency = fromCurrency;
108.180 + this.toCurrency = toCurrency;
108.181 + }
108.182 +
108.183 + /**
108.184 + * Create IExchangeRateEngine conveting from <code>fromCurrency</code> to <code>toCurrency</code>
108.185 + * with echange rate <code>fromValue:toValue</code>
108.186 + * @param fromValue
108.187 + * @param fromCurrency
108.188 + * @param toValue
108.189 + * @param toCurrency
108.190 + * @return Returns instance of <code>FixedOneExchangeRateEngine</code>.
108.191 + */
108.192 + private static IExchangeRateEngine createEngine(BigDecimal fromValue, ConvertorCurrency fromCurrency, BigDecimal toValue, ConvertorCurrency toCurrency) {
108.193 + return new FixedOneExchangeRateEngine(fromValue, fromCurrency, toValue, toCurrency);
108.194 + }
108.195 +
108.196 + private BigDecimal getFromValue() {
108.197 + return fromValue;
108.198 + }
108.199 +
108.200 + private BigDecimal getToValue() {
108.201 + return toValue;
108.202 + }
108.203 +
108.204 + private ConvertorCurrency getFromCurrency() {
108.205 + return fromCurrency;
108.206 + }
108.207 +
108.208 + private ConvertorCurrency getToCurrency() {
108.209 + return toCurrency;
108.210 + }
108.211 +
108.212 + public ExchangeRate getExchangeRate(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency) {
108.213 + if (!fromCurrency.equals(this.fromCurrency)) {
108.214 + return null;
108.215 + }
108.216 + if (!toCurrency.equals(this.toCurrency)) {
108.217 + return null;
108.218 + }
108.219 + return new ExchangeRate(fromValue, toValue);
108.220 + }
108.221 + }
108.222 +
108.223 + /**
108.224 + * Exchange rate engine able to hold several fixed exchange rates.
108.225 + *
108.226 + * @author arnostvalicek
108.227 + */
108.228 + private static class FixedExchangeRateEngine implements IExchangeRateEngine {
108.229 +
108.230 + private Map exchangeRateMap = new HashMap();
108.231 +
108.232 + private FixedExchangeRateEngine() {
108.233 + }
108.234 +
108.235 + /**
108.236 + * Create instance of <code>FixedExchangeRateEngine</code>.
108.237 + * @return Returns instance of <code>FixedExchangeRateEngine</code>.
108.238 + */
108.239 + public static IExchangeRateEngine createEngine() {
108.240 + return new FixedExchangeRateEngine();
108.241 + }
108.242 +
108.243 + public ExchangeRate getExchangeRate(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency) {
108.244 + Map map2 = (Map) exchangeRateMap.get(fromCurrency);
108.245 + if (map2 == null) {
108.246 + return null;
108.247 + }
108.248 + ExchangeRate result = (ExchangeRate) map2.get(toCurrency);
108.249 + return result;
108.250 + }
108.251 +
108.252 + @SuppressWarnings("unchecked")
108.253 + public synchronized void addFixedCurencyRate(ConvertorCurrency fromCurrency, BigDecimal fromValue, ConvertorCurrency toCurrency, BigDecimal toValue) {
108.254 + if (fromValue == null) {
108.255 + throw new NullPointerException("fromValue can't be null");
108.256 + }
108.257 + if (toValue == null) {
108.258 + throw new NullPointerException("toValue can't be null");
108.259 + }
108.260 + Map map2 = (Map) exchangeRateMap.get(fromCurrency);
108.261 + if (map2 == null) {
108.262 + map2 = new HashMap();
108.263 + exchangeRateMap.put(fromCurrency, map2);
108.264 + }
108.265 +
108.266 + ExchangeRate rate = new ExchangeRate(fromValue, toValue);
108.267 + map2.put(toCurrency, rate);
108.268 + }
108.269 + }
108.270 +}
109.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
109.2 +++ b/task4/solution13/src/org/apidesign/apifest08/currency/IExchangeRateEngine.java Sat Oct 11 23:38:46 2008 +0200
109.3 @@ -0,0 +1,18 @@
109.4 +package org.apidesign.apifest08.currency;
109.5 +
109.6 +/**
109.7 + * Interface for exchange rate engine.
109.8 + *
109.9 + * @author arnostvalicek
109.10 + */
109.11 +public interface IExchangeRateEngine {
109.12 +
109.13 + /**
109.14 + * Get exchange rate for conversion from <code>fromCurrency</code> to <code>toCurrency</code>.
109.15 + *
109.16 + * @param fromCurrency From currency.
109.17 + * @param toCurrency To currency.
109.18 + * @return Returns <code>ExchangeRate</code> if exchange rate is known or <code>null</code> if exchanger rate is not known.
109.19 + */
109.20 + public ExchangeRate getExchangeRate(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency);
109.21 +}
110.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
110.2 +++ b/task4/solution13/test/org/apidesign/apifest08/test/BouncingExchangeRateEngine.java Sat Oct 11 23:38:46 2008 +0200
110.3 @@ -0,0 +1,79 @@
110.4 +package org.apidesign.apifest08.test;
110.5 +
110.6 +import java.math.BigDecimal;
110.7 +import org.apidesign.apifest08.currency.ConvertorCurrency;
110.8 +import org.apidesign.apifest08.currency.ExchangeRate;
110.9 +import org.apidesign.apifest08.currency.IExchangeRateEngine;
110.10 +
110.11 +/** Exchange rate engine which is periodicaly changing echange rate.
110.12 + * See <a href="http://wiki.apidesign.org/wiki/APIFest08:Task3">http://wiki.apidesign.org/wiki/APIFest08:Task3</a> for further description.
110.13 + *
110.14 + * @author arnostvalicek
110.15 + */
110.16 +public class BouncingExchangeRateEngine implements IExchangeRateEngine {
110.17 +
110.18 + ConvertorCurrency fromCurrency;
110.19 + BigDecimal fromValue;
110.20 + ConvertorCurrency toCurrency;
110.21 + BigDecimal toValueStart;
110.22 + BigDecimal toValueStop;
110.23 + BigDecimal step;
110.24 +
110.25 + BigDecimal toValue;
110.26 +
110.27 +
110.28 +
110.29 +
110.30 + private BouncingExchangeRateEngine(ConvertorCurrency fromCurrency, BigDecimal fromValue, ConvertorCurrency toCurrency, BigDecimal toValueStart, BigDecimal toValueStop, BigDecimal step) {
110.31 + this.fromCurrency = fromCurrency;
110.32 + this.fromValue = fromValue;
110.33 + this.toCurrency = toCurrency;
110.34 + this.toValueStart = toValueStart;
110.35 + this.toValueStop = toValueStop;
110.36 + this.step = step;
110.37 + this.toValue = toValueStart;
110.38 + }
110.39 +
110.40 +
110.41 + public static IExchangeRateEngine create(ConvertorCurrency fromCurrency, BigDecimal fromValue, ConvertorCurrency toCurrency, BigDecimal toValueStart, BigDecimal toValueStop, BigDecimal step) {
110.42 + return new BouncingExchangeRateEngine(fromCurrency, fromValue, toCurrency, toValueStart, toValueStop, step);
110.43 + }
110.44 +
110.45 + public ExchangeRate getExchangeRate(ConvertorCurrency fromCurrency, ConvertorCurrency toCurrency) {
110.46 + if (!fromCurrency.equals(this.fromCurrency)) {
110.47 + return null;
110.48 + }
110.49 + if (!toCurrency.equals(this.toCurrency)) {
110.50 + return null;
110.51 + }
110.52 +
110.53 + ExchangeRate result = new ExchangeRate(fromValue, toValue);
110.54 +
110.55 + toValue = toValue.add(step);
110.56 +
110.57 +// if (step.signum()==1 && toValueStop.compareTo(toValue)==0) {
110.58 +// System.out.println("A");
110.59 +// toValue=toValueStop;
110.60 +// step = step.negate();
110.61 +// BigDecimal x = toValueStart;
110.62 +// toValueStart=toValueStop;
110.63 +// toValueStop=x;
110.64 +// } else if (step.signum()==-1 && toValueStop.compareTo(toValue)==0) {
110.65 +// System.out.println("B");
110.66 +// toValue=toValueStop;
110.67 +// step = step.negate();
110.68 +// BigDecimal x = toValueStart;
110.69 +// toValueStart=toValueStop;
110.70 +// toValueStop=x;
110.71 +// }
110.72 + if (toValueStop.compareTo(toValue)==0) {
110.73 + toValue=toValueStop;
110.74 + step = step.negate();
110.75 + BigDecimal x = toValueStart;
110.76 + toValueStart=toValueStop;
110.77 + toValueStop=x;
110.78 + }
110.79 + return result;
110.80 + }
110.81 +
110.82 +}
111.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
111.2 +++ b/task4/solution13/test/org/apidesign/apifest08/test/Task1Test.java Sat Oct 11 23:38:46 2008 +0200
111.3 @@ -0,0 +1,223 @@
111.4 +package org.apidesign.apifest08.test;
111.5 +
111.6 +import java.math.BigDecimal;
111.7 +import junit.framework.TestCase;
111.8 +import org.apidesign.apifest08.currency.ConversionResult;
111.9 +import org.apidesign.apifest08.currency.Convertor;
111.10 +import org.apidesign.apifest08.currency.ConvertorCurrency;
111.11 +import org.apidesign.apifest08.currency.ExchangeRateProvider;
111.12 +import org.apidesign.apifest08.currency.ConversionNotSupportedException;
111.13 +
111.14 +/** Finish the Convertor API, and then write bodies of methods inside
111.15 + * of this class to match the given tasks. To fullfil your task, use the
111.16 + * API define in the <code>org.apidesign.apifest08.currency</code> package.
111.17 + * Do not you reflection, or other hacks as your code
111.18 + * shall run without any runtime permissions.
111.19 + */
111.20 +public class Task1Test extends TestCase {
111.21 + public Task1Test(String testName) {
111.22 + super(testName);
111.23 + }
111.24 +
111.25 + @Override
111.26 + protected void setUp() throws Exception {
111.27 + }
111.28 +
111.29 + @Override
111.30 + protected void tearDown() throws Exception {
111.31 + }
111.32 +
111.33 + /** Create convertor that understands two currencies, CZK and
111.34 + * USD. Make 1 USD == 17 CZK.
111.35 + *
111.36 + * Creation of the convertor shall not require subclassing of any class
111.37 + * or interface on the client side.
111.38 + *
111.39 + * @return prepared convertor ready for converting USD to CZK and CZK to USD
111.40 + */
111.41 + public static Convertor createCZKtoUSD() {
111.42 + ConvertorCurrency fromCurrency = ConvertorCurrency.getInstance("CZK");
111.43 + ConvertorCurrency toCurrency = ConvertorCurrency.getInstance("USD");
111.44 + ExchangeRateProvider exchangeRateProvider = new ExchangeRateProvider(new BigDecimal(17), fromCurrency, new BigDecimal(1), toCurrency);
111.45 +
111.46 + return Convertor.createConvertor(exchangeRateProvider);
111.47 + }
111.48 +
111.49 + /** Create convertor that understands two currencies, CZK and
111.50 + * SKK. Make 100 SKK == 80 CZK.
111.51 + *
111.52 + * Creation of the convertor shall not require subclassing of any class
111.53 + * or interface on the client side.
111.54 + *
111.55 + * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
111.56 + */
111.57 + public static Convertor createSKKtoCZK() {
111.58 + ConvertorCurrency fromCurrency = ConvertorCurrency.getInstance("SKK");
111.59 + ConvertorCurrency toCurrency = ConvertorCurrency.getInstance("CZK");
111.60 + ExchangeRateProvider exchangeRateProvider = new ExchangeRateProvider(new BigDecimal(100), fromCurrency, new BigDecimal(80), toCurrency);
111.61 +
111.62 + return Convertor.createConvertor(exchangeRateProvider);
111.63 + }
111.64 +
111.65 +
111.66 + public static Convertor createCZKtoYEN() {
111.67 + ConvertorCurrency fromCurrency = ConvertorCurrency.getInstance("CZK");
111.68 + ConvertorCurrency toCurrency = ConvertorCurrency.getInstance("JPY");
111.69 + ExchangeRateProvider exchangeRateProvider = new ExchangeRateProvider(new BigDecimal(1), fromCurrency, new BigDecimal(1), toCurrency);
111.70 +
111.71 + return Convertor.createConvertor(exchangeRateProvider);
111.72 + }
111.73 +
111.74 + /** Use the convertor from <code>createCZKtoUSD</code> method and do few conversions
111.75 + * with it.
111.76 + */
111.77 + public void testCurrencyCZKUSD() throws Exception {
111.78 + Convertor convertCzkUsd = createCZKtoUSD();
111.79 +
111.80 + {
111.81 + // convert $1 to CZK using c:
111.82 + ConversionResult result = convertCzkUsd.convertBack(new BigDecimal(1));
111.83 + assertEquals("Result is 17 CZK", new BigDecimal("17.00"), result.getConverted());
111.84 + assertEquals("No Remainer", BigDecimal.ZERO, result.getRemainder());
111.85 + }
111.86 +
111.87 + {
111.88 + // convert 17CKZ to $ using c:
111.89 + ConversionResult result = convertCzkUsd.convert(new BigDecimal(17));
111.90 + assertEquals("Result is 1 $", new BigDecimal("1.00"), result.getConverted());
111.91 + assertEquals("No Remainer", BigDecimal.ZERO, result.getRemainder());
111.92 + }
111.93 +
111.94 + {
111.95 + // convert $5 to CZK using c:
111.96 + ConversionResult result = convertCzkUsd.convertBack(new BigDecimal(5));
111.97 + assertEquals("Result is 85 CZK", new BigDecimal("85.00"), result.getConverted());
111.98 + assertEquals("No Remainer", BigDecimal.ZERO, result.getRemainder());
111.99 + }
111.100 +
111.101 + {
111.102 + // convert $8 to CZK
111.103 + ConversionResult result = convertCzkUsd.convertBack(new BigDecimal(8));
111.104 + assertEquals("Result is 136 CZK", new BigDecimal("136.00"), result.getConverted());
111.105 + assertEquals("No Remainer", BigDecimal.ZERO, result.getRemainder());
111.106 + }
111.107 +
111.108 + {
111.109 + // convert 1003CZK to USD
111.110 + ConversionResult result = convertCzkUsd.convert(new BigDecimal(1003));
111.111 + assertEquals("Result is 59 USD", new BigDecimal("59.00"), result.getConverted());
111.112 + assertEquals("No Remainer", BigDecimal.ZERO, result.getRemainder());
111.113 + }
111.114 + }
111.115 +
111.116 + /** Use the convertor from <code>createSKKtoCZK</code> method and do few conversions
111.117 + * with it.
111.118 + */
111.119 + public void testCurrencySKKCZK() throws Exception {
111.120 + Convertor convertSkkCzk = createSKKtoCZK();
111.121 + {
111.122 + // convert 100SKK using c:
111.123 + ConversionResult result = convertSkkCzk.convert(new BigDecimal(100));
111.124 + assertEquals("Result is 80 CZK", new BigDecimal("80.00"), result.getConverted());
111.125 + }
111.126 + {
111.127 + // convert 80CZK using c:
111.128 + ConversionResult result = convertSkkCzk.convertBack(new BigDecimal(80));
111.129 + assertEquals("Result is 100 SKK", new BigDecimal("100.00"), result.getConverted());
111.130 + }
111.131 +
111.132 + {
111.133 + // convert 16CZK using c:
111.134 + ConversionResult result = convertSkkCzk.convertBack(new BigDecimal(16));
111.135 + assertEquals("Result is 20 SKK", new BigDecimal("20.00"), result.getConverted());
111.136 + }
111.137 +
111.138 + {
111.139 + // convert 500SKK to CZK
111.140 + ConversionResult result = convertSkkCzk.convert(new BigDecimal(500));
111.141 + assertEquals("Result is 400 CZK", new BigDecimal("400.00"), result.getConverted());
111.142 + assertEquals("No Remainer", BigDecimal.ZERO, result.getRemainder());
111.143 + }
111.144 +
111.145 + {
111.146 + // convert 501SKK to CZK
111.147 + ConversionResult result = convertSkkCzk.convert(new BigDecimal(501));
111.148 + assertEquals("Result is 400 CZK", new BigDecimal("400.80"), result.getConverted());
111.149 + assertEquals("No Remainer", BigDecimal.ZERO, result.getRemainder());
111.150 +
111.151 + }
111.152 + }
111.153 +
111.154 + /**
111.155 + * Convert SKK to CZK. Convertor can't convert whole amout (can't convert one SKK cent to CZK). Remaining
111.156 + * amount is stored in remainder result.
111.157 + *
111.158 + * Test is currently failing, because implementation can't handle this case.
111.159 + */
111.160 +// public void testConvertSmallUnits_failing() {
111.161 +// Convertor convertSkkCzk = createSKKtoCZK();
111.162 +// {
111.163 +// // convert 501SKK to CZK
111.164 +// ConversionResult result = convertSkkCzk.convert(new BigDecimal("501.01"));
111.165 +// assertEquals("Result is 400 CZK", new BigDecimal("400.80"), result.getConverted());
111.166 +// assertEquals("No Remainer", new BigDecimal("0.01"), result.getRemainder());
111.167 +//
111.168 +// }
111.169 +//
111.170 +// }
111.171 +
111.172 + /**
111.173 + * Test converting from CZK to JPY. Remained has scale of CZK.
111.174 + *
111.175 + * This test is currently failing, because converter implementation currently can't handle conversion from "cent" to "no-cent" currency.
111.176 + */
111.177 +// public void testConvertCzkToJpy_failing() {
111.178 +// Convertor convertSkkCzk = createCZKtoYEN();
111.179 +// {
111.180 +// // convert 501SKK to CZK
111.181 +// ConversionResult result = convertSkkCzk.convert(new BigDecimal("120.00"));
111.182 +// assertEquals("Result is 120 YEN", new BigDecimal("120"), result.getConverted());
111.183 +// assertEquals("No Remainer", new BigDecimal("0.00"), result.getRemainder());
111.184 +//
111.185 +// }
111.186 +// }
111.187 +
111.188 + /**
111.189 + * Test converting from JPY to CZK. Remained has scale of JPY.
111.190 + *
111.191 + * This test is currently failing, because converter implementation currently can't handle conversion from "cent" to "no-cent" currency.
111.192 + */
111.193 +// public void testConvertJpyToCzk_failing() {
111.194 +// Convertor convertSkkCzk = createCZKtoYEN();
111.195 +// {
111.196 +// // convert 501SKK to CZK
111.197 +// ConversionResult result = convertSkkCzk.convert(new BigDecimal("120.00"));
111.198 +// assertEquals("Result is 120 YEN", new BigDecimal("120"), result.getConverted());
111.199 +// assertEquals("No Remainer", new BigDecimal("0"), result.getRemainder());
111.200 +//
111.201 +// }
111.202 +// }
111.203 +
111.204 + public void testCannotConvertToSKKwithCZKUSDConvertor() throws Exception {
111.205 + Convertor c = createCZKtoUSD();
111.206 + // convert $5 to SKK, the API shall say this is not possible
111.207 + try {
111.208 + c.convert(ConvertorCurrency.getInstance("USD"), ConvertorCurrency.getInstance("SKK"), new BigDecimal(5));
111.209 + fail();
111.210 + } catch (ConversionNotSupportedException e) {
111.211 + //expected error;
111.212 + assertEquals("Exception From USD", "USD",e.getFromCurrecyCode());
111.213 + assertEquals("Exception To SKK", "SKK",e.getToCurrecyCode());
111.214 + }
111.215 + // convert 500 SKK to CZK, the API shall say this is not possible
111.216 + try {
111.217 + c.convert(ConvertorCurrency.getInstance("SKK"), ConvertorCurrency.getInstance("CZK"), new BigDecimal(500));
111.218 + fail();
111.219 + } catch (ConversionNotSupportedException e) {
111.220 + assertEquals("Exception From USD", "SKK",e.getFromCurrecyCode());
111.221 + assertEquals("Exception To SKK", "CZK",e.getToCurrecyCode()); }
111.222 + }
111.223 +
111.224 +
111.225 +}
111.226 +
112.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
112.2 +++ b/task4/solution13/test/org/apidesign/apifest08/test/Task2Test.java Sat Oct 11 23:38:46 2008 +0200
112.3 @@ -0,0 +1,136 @@
112.4 +package org.apidesign.apifest08.test;
112.5 +
112.6 +import java.math.BigDecimal;
112.7 +import junit.framework.TestCase;
112.8 +import org.apidesign.apifest08.currency.Convertor;
112.9 +import org.apidesign.apifest08.currency.ConvertorCurrency;
112.10 +import org.apidesign.apifest08.currency.ExchangeRateProvider;
112.11 +
112.12 +/** There are many currencies around the world and many banks manipulate
112.13 + * with more than one or two at the same time. As banks are usually the
112.14 + * best paying clients, which is true even in case of your Convertor API,
112.15 + * it is reasonable to listen to their requests.
112.16 + * <p>
112.17 + * The quest for today is to enhance your existing convertor API to hold
112.18 + * information about many currencies and allow conversions between any of them.
112.19 + * Also, as conversion rates for diferent currencies usually arise from various
112.20 + * bank departments, there is another important need. There is a need to
112.21 + * compose two convertors into one by merging all the information about
112.22 + * currencies they know about.
112.23 + */
112.24 +public class Task2Test extends TestCase {
112.25 + private static ConvertorCurrency currencyCZK = ConvertorCurrency.getInstance("CZK");
112.26 + private static ConvertorCurrency currencySKK = ConvertorCurrency.getInstance("SKK");
112.27 + private static ConvertorCurrency currencyUSD = ConvertorCurrency.getInstance("USD");
112.28 +
112.29 + public Task2Test(String testName) {
112.30 + super(testName);
112.31 + }
112.32 +
112.33 + @Override
112.34 + protected void setUp() throws Exception {
112.35 +
112.36 + }
112.37 +
112.38 + @Override
112.39 + protected void tearDown() throws Exception {
112.40 + }
112.41 +
112.42 + public static Convertor createUsdToSkkConvertor() {
112.43 + ConvertorCurrency fromCurrency = currencyUSD;
112.44 + ConvertorCurrency toCurrency = currencyUSD;
112.45 + ExchangeRateProvider exchangeRateProvider = new ExchangeRateProvider(new BigDecimal(1), fromCurrency, new BigDecimal(20), toCurrency);
112.46 +
112.47 + return Convertor.createConvertor(exchangeRateProvider);
112.48 +
112.49 + }
112.50 +
112.51 + // As in Task1Test, keep in mind, that there are three parts
112.52 + // of the whole system:
112.53 + // 1. there is someone who knows the current exchange rate
112.54 + // 2. there is someone who wants to do the conversion
112.55 + // 3. there is the API between 1. and 2. which allows them to communicate
112.56 + //
112.57 + // Please backward compatibly enhance your existing API to support following
112.58 + // usecases:
112.59 + //
112.60 +
112.61 + /** Create convertor that understands two currencies, CZK and
112.62 + * SKK. Make 100 SKK == 75 CZK. This is method for the group of users that
112.63 + * knows the exchange rate, and needs to use the API to create objects
112.64 + * with the exchange rate. Anyone shall be ready to call this method without
112.65 + * any other method being called previously. The API itself shall know
112.66 + * nothing about any rates, before this method is called.
112.67 + */
112.68 + public static Convertor createTripleConvertor() {
112.69 + ExchangeRateProvider exRateProvider = ExchangeRateProvider.createExchangeRateProvider();
112.70 +
112.71 + // Rates: 1USD = 15CZK
112.72 + exRateProvider.addFixedCurencyRate(currencyUSD, new BigDecimal(1),currencyCZK, new BigDecimal(15));
112.73 +
112.74 + // Rates: 1USD = 20SKK
112.75 + exRateProvider.addFixedCurencyRate(currencyUSD, new BigDecimal(1), currencySKK, new BigDecimal(20));
112.76 +
112.77 + // Rates: 75CZK = 100SKK
112.78 + exRateProvider.addFixedCurencyRate(currencyCZK, new BigDecimal(75), currencySKK, new BigDecimal(100));
112.79 +
112.80 + Convertor c = Convertor.createConvertor(exRateProvider);
112.81 +
112.82 + return c;
112.83 + }
112.84 +
112.85 + /** Define convertor that understands three currencies. Use it.
112.86 + */
112.87 + public void testConvertorForUSDandCZKandSKK() throws Exception {
112.88 + Convertor c = createTripleConvertor();
112.89 +
112.90 + // convert $5 to CZK using c:
112.91 + assertEquals("Result is 75 CZK",new BigDecimal("75.00"),c.convertWithReversibleRates(currencyUSD, currencyCZK, new BigDecimal(5)).getConverted());
112.92 +
112.93 +
112.94 + // convert $5 to SKK using c:
112.95 + assertEquals("Result is 100 SKK",new BigDecimal("100.00"),c.convertWithReversibleRates(currencyUSD, currencySKK, new BigDecimal(5)).getConverted());
112.96 +
112.97 + // convert 200SKK to CZK using c:
112.98 + assertEquals("Result is 150 CZK",new BigDecimal("150.00"),c.convertWithReversibleRates(currencySKK, currencyCZK, new BigDecimal(200)).getConverted());
112.99 +
112.100 + // convert 200SKK to USK using c:
112.101 + // assertEquals("Result is 10 USD");
112.102 + }
112.103 +
112.104 + /** Merge all currency rates of convertor 1 with convertor 2.
112.105 + * Implement this using your API, preferably this method just delegates
112.106 + * into some API method which does the actual work, without requiring
112.107 + * API clients to code anything complex.
112.108 + */
112.109 + public static Convertor merge(Convertor one, Convertor two) {
112.110 + return Convertor.createConvertorAsMerge(new Convertor[]{one, two});
112.111 + }
112.112 +
112.113 + /** Join the convertors from previous task, Task1Test and show that it
112.114 + * can be used to do reasonable conversions.
112.115 + */
112.116 + public void testConvertorComposition() throws Exception {
112.117 + Convertor c = merge(
112.118 + Task1Test.createCZKtoUSD(),
112.119 + Task1Test.createSKKtoCZK()
112.120 + );
112.121 +
112.122 + // convert $5 to CZK using c:
112.123 + assertEquals("Result is 85 CZK",new BigDecimal("85.00"),c.convertWithReversibleRates(currencyUSD, currencyCZK, new BigDecimal(5)).getConverted());
112.124 +
112.125 + // convert $8 to CZK using c:
112.126 + // assertEquals("Result is 136 CZK");
112.127 + assertEquals("Result is 136 CZK",new BigDecimal("136.00"),c.convertWithReversibleRates(currencyUSD, currencyCZK, new BigDecimal(8)).getConverted());
112.128 +
112.129 + // convert 1003CZK to USD using c:
112.130 + assertEquals("Result is 59 USD",new BigDecimal("59.00"),c.convertWithReversibleRates(currencyCZK, currencyUSD, new BigDecimal(1003)).getConverted());
112.131 +
112.132 + // convert 16CZK using c:
112.133 + assertEquals("Result is 20 SKK",new BigDecimal("20.00"),c.convertWithReversibleRates(currencyCZK, currencySKK, new BigDecimal(16)).getConverted());
112.134 +
112.135 + // convert 500SKK to CZK using c:
112.136 + assertEquals("Result is 400 CZK",new BigDecimal("400.00"),c.convertWithReversibleRates(currencySKK, currencyCZK, new BigDecimal(500)).getConverted());
112.137 +
112.138 + }
112.139 +}
113.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
113.2 +++ b/task4/solution13/test/org/apidesign/apifest08/test/Task3Test.java Sat Oct 11 23:38:46 2008 +0200
113.3 @@ -0,0 +1,122 @@
113.4 +package org.apidesign.apifest08.test;
113.5 +
113.6 +import java.math.BigDecimal;
113.7 +import junit.framework.TestCase;
113.8 +import org.apidesign.apifest08.currency.Convertor;
113.9 +import org.apidesign.apifest08.currency.ConvertorCurrency;
113.10 +import org.apidesign.apifest08.currency.ExchangeRateProvider;
113.11 +import org.apidesign.apifest08.currency.IExchangeRateEngine;
113.12 +
113.13 +/** The exchange rates are not always the same. They are changing. Day by day,
113.14 + * hour by hour, minute by minute. For every bank it is important to always
113.15 + * have the actual exchange rate available in the system. That is why let's
113.16 + * create a pluggable convertor that will always have up to date value of its
113.17 + * exchange rate.
113.18 + * <p>
113.19 + * The quest for today is to allow 3rd party developer to write a convertor
113.20 + * that adjusts its exchange rate everytime it is queried. This convertor is
113.21 + * written by independent vendor, the vendor knows only your Convertor API,
113.22 + * he does not know how the whole system looks and how the convertor is supposed
113.23 + * to be used.
113.24 + */
113.25 +public class Task3Test extends TestCase {
113.26 +
113.27 + private static ConvertorCurrency currencyCZK = ConvertorCurrency.getInstance("CZK");
113.28 + private static ConvertorCurrency currencySKK = ConvertorCurrency.getInstance("SKK");
113.29 + private static ConvertorCurrency currencyUSD = ConvertorCurrency.getInstance("USD");
113.30 +
113.31 + public Task3Test(String testName) {
113.32 + super(testName);
113.33 + }
113.34 +
113.35 + @Override
113.36 + protected void setUp() throws Exception {
113.37 + }
113.38 +
113.39 + @Override
113.40 + protected void tearDown() throws Exception {
113.41 + }
113.42 +
113.43 + // Backward compatibly enhance your existing API to support following
113.44 + // usecases:
113.45 + //
113.46 +
113.47 +
113.48 + /** Without knowing anything about the surrounding system, write an
113.49 + * implementation of convertor that will return different rates everytime
113.50 + * it is queried. Convert USD to CZK and vice versa. Start with the rate of
113.51 + * 1USD = 16CZK and adjust it in favor of CZK by 0.01 CZK with every query.
113.52 + * As soon as you reach 1USD = 15CZK adjust it by 0.01 CZK in favor of USD
113.53 + * until you reach 1USD = 16CZK
113.54 + *
113.55 + * @return new instance of "online" USD and CZK convertor starting with rate 1USD = 16CZK
113.56 + */
113.57 + public static Convertor createOnlineCZKUSDConvertor() {
113.58 + // initial rate: 1USD = 16CZK
113.59 + // 2nd query 1USD = 15.99CZK
113.60 + // 3rd query 1USD = 15.98CZK
113.61 + // until 1USD = 15.00CZK
113.62 + // then 1USD = 15.01CZK
113.63 + // then 1USD = 15.02CZK
113.64 + // and so on and on up to 1USD = 16CZK
113.65 + // and then another round to 15, etc.
113.66 + IExchangeRateEngine engine = BouncingExchangeRateEngine.create(
113.67 + currencyUSD, new BigDecimal(1),
113.68 + currencyCZK,
113.69 + new BigDecimal(16),new BigDecimal(15),
113.70 + new BigDecimal("-0.01"));
113.71 + ExchangeRateProvider exRateProvider = ExchangeRateProvider.createExchangeRateProvider(engine);
113.72 + Convertor convertor = Convertor.createConvertor(exRateProvider);
113.73 + return convertor;
113.74 + }
113.75 +
113.76 + public void testFewQueriesForOnlineConvertor() {
113.77 + Convertor c = createOnlineCZKUSDConvertor();
113.78 + doFewQueriesForOnlineConvertor(c);
113.79 + }
113.80 +
113.81 + static void doFewQueriesForOnlineConvertor(Convertor c) {
113.82 + // convert $5 to CZK using c:
113.83 + assertEquals("Result is 80 CZK", new BigDecimal("80.00"), c.convertWithReversibleRates(currencyUSD, currencyCZK, new BigDecimal(5)).getConverted());
113.84 +
113.85 + // convert $8 to CZK using c:
113.86 + assertEquals("Result is 127.92 CZK", new BigDecimal("127.92"), c.convertWithReversibleRates(currencyUSD, currencyCZK, new BigDecimal(8)).getConverted());
113.87 +
113.88 + // convert $1 to CZK using c:
113.89 + assertEquals("Result is 15.98 CZK", new BigDecimal("15.98"), c.convertWithReversibleRates(currencyUSD, currencyCZK, new BigDecimal(1)).getConverted());
113.90 +
113.91 + // convert 15.97CZK to USD using c:
113.92 + assertEquals("Result is 15.98 CZK", new BigDecimal("1.00"), c.convertWithReversibleRates(currencyCZK, currencyUSD , new BigDecimal("15.97")).getConverted());
113.93 + }
113.94 +
113.95 + /** Join the convertors and show they behave sane.
113.96 + */
113.97 + public void testOnlineConvertorComposition() throws Exception {
113.98 + Convertor c = Task2Test.merge(
113.99 + createOnlineCZKUSDConvertor(),
113.100 + Task1Test.createSKKtoCZK()
113.101 + );
113.102 +
113.103 + // convert 16CZK to SKK using c:
113.104 + assertEquals("Result is 20 CZK", new BigDecimal("20.00"), c.convertWithReversibleRates(currencyCZK, currencySKK , new BigDecimal("16")).getConverted());
113.105 +
113.106 + // convert 500SKK to CZK using c:
113.107 + assertEquals("Result is 400 CZK", new BigDecimal("400.00"), c.convertWithReversibleRates(currencySKK, currencyCZK , new BigDecimal("500")).getConverted());
113.108 +
113.109 + doFewQueriesForOnlineConvertor(c);
113.110 + }
113.111 +
113.112 +// public void testBouncing() {
113.113 +// Convertor c=createOnlineCZKUSDConvertor();
113.114 +//
113.115 +// IExchangeRateEngine engine = BouncingExchangeRateEngine.create(
113.116 +// currencyUSD, new BigDecimal(1),
113.117 +// currencyCZK,
113.118 +// new BigDecimal("16.00"),new BigDecimal("15.00"),
113.119 +// new BigDecimal("-0.01"));
113.120 +//
113.121 +// for (int i=0;i<300;i++) {
113.122 +// System.out.println(engine.getExchangeRate(currencyUSD, currencyCZK).getToValue());
113.123 +// }
113.124 +// }
113.125 +}
114.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
114.2 +++ b/task4/solution14/build.xml Sat Oct 11 23:38:46 2008 +0200
114.3 @@ -0,0 +1,69 @@
114.4 +<?xml version="1.0" encoding="UTF-8"?>
114.5 +<!-- You may freely edit this file. See commented blocks below for -->
114.6 +<!-- some examples of how to customize the build. -->
114.7 +<!-- (If you delete it and reopen the project it will be recreated.) -->
114.8 +<project name="currency" default="default" basedir=".">
114.9 + <description>Builds, tests, and runs the project.</description>
114.10 + <import file="nbproject/build-impl.xml"/>
114.11 + <!--
114.12 +
114.13 + There exist several targets which are by default empty and which can be
114.14 + used for execution of your tasks. These targets are usually executed
114.15 + before and after some main targets. They are:
114.16 +
114.17 + -pre-init: called before initialization of project properties
114.18 + -post-init: called after initialization of project properties
114.19 + -pre-compile: called before javac compilation
114.20 + -post-compile: called after javac compilation
114.21 + -pre-compile-single: called before javac compilation of single file
114.22 + -post-compile-single: called after javac compilation of single file
114.23 + -pre-compile-test: called before javac compilation of JUnit tests
114.24 + -post-compile-test: called after javac compilation of JUnit tests
114.25 + -pre-compile-test-single: called before javac compilation of single JUnit test
114.26 + -post-compile-test-single: called after javac compilation of single JUunit test
114.27 + -pre-jar: called before JAR building
114.28 + -post-jar: called after JAR building
114.29 + -post-clean: called after cleaning build products
114.30 +
114.31 + (Targets beginning with '-' are not intended to be called on their own.)
114.32 +
114.33 + Example of inserting an obfuscator after compilation could look like this:
114.34 +
114.35 + <target name="-post-compile">
114.36 + <obfuscate>
114.37 + <fileset dir="${build.classes.dir}"/>
114.38 + </obfuscate>
114.39 + </target>
114.40 +
114.41 + For list of available properties check the imported
114.42 + nbproject/build-impl.xml file.
114.43 +
114.44 +
114.45 + Another way to customize the build is by overriding existing main targets.
114.46 + The targets of interest are:
114.47 +
114.48 + -init-macrodef-javac: defines macro for javac compilation
114.49 + -init-macrodef-junit: defines macro for junit execution
114.50 + -init-macrodef-debug: defines macro for class debugging
114.51 + -init-macrodef-java: defines macro for class execution
114.52 + -do-jar-with-manifest: JAR building (if you are using a manifest)
114.53 + -do-jar-without-manifest: JAR building (if you are not using a manifest)
114.54 + run: execution of project
114.55 + -javadoc-build: Javadoc generation
114.56 + test-report: JUnit report generation
114.57 +
114.58 + An example of overriding the target for project execution could look like this:
114.59 +
114.60 + <target name="run" depends="currency-impl.jar">
114.61 + <exec dir="bin" executable="launcher.exe">
114.62 + <arg file="${dist.jar}"/>
114.63 + </exec>
114.64 + </target>
114.65 +
114.66 + Notice that the overridden target depends on the jar target and not only on
114.67 + the compile target as the regular run target does. Again, for a list of available
114.68 + properties which you can use, check the target you are overriding in the
114.69 + nbproject/build-impl.xml file.
114.70 +
114.71 + -->
114.72 +</project>
115.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
115.2 +++ b/task4/solution14/nbproject/build-impl.xml Sat Oct 11 23:38:46 2008 +0200
115.3 @@ -0,0 +1,642 @@
115.4 +<?xml version="1.0" encoding="UTF-8"?>
115.5 +<!--
115.6 +*** GENERATED FROM project.xml - DO NOT EDIT ***
115.7 +*** EDIT ../build.xml INSTEAD ***
115.8 +
115.9 +For the purpose of easier reading the script
115.10 +is divided into following sections:
115.11 +
115.12 + - initialization
115.13 + - compilation
115.14 + - jar
115.15 + - execution
115.16 + - debugging
115.17 + - javadoc
115.18 + - junit compilation
115.19 + - junit execution
115.20 + - junit debugging
115.21 + - applet
115.22 + - cleanup
115.23 +
115.24 + -->
115.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_14-impl">
115.26 + <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
115.27 + <!--
115.28 + ======================
115.29 + INITIALIZATION SECTION
115.30 + ======================
115.31 + -->
115.32 + <target name="-pre-init">
115.33 + <!-- Empty placeholder for easier customization. -->
115.34 + <!-- You can override this target in the ../build.xml file. -->
115.35 + </target>
115.36 + <target depends="-pre-init" name="-init-private">
115.37 + <property file="nbproject/private/config.properties"/>
115.38 + <property file="nbproject/private/configs/${config}.properties"/>
115.39 + <property file="nbproject/private/private.properties"/>
115.40 + </target>
115.41 + <target depends="-pre-init,-init-private" name="-init-user">
115.42 + <property file="${user.properties.file}"/>
115.43 + <!-- The two properties below are usually overridden -->
115.44 + <!-- by the active platform. Just a fallback. -->
115.45 + <property name="default.javac.source" value="1.4"/>
115.46 + <property name="default.javac.target" value="1.4"/>
115.47 + </target>
115.48 + <target depends="-pre-init,-init-private,-init-user" name="-init-project">
115.49 + <property file="nbproject/configs/${config}.properties"/>
115.50 + <property file="nbproject/project.properties"/>
115.51 + </target>
115.52 + <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
115.53 + <available file="${manifest.file}" property="manifest.available"/>
115.54 + <condition property="manifest.available+main.class">
115.55 + <and>
115.56 + <isset property="manifest.available"/>
115.57 + <isset property="main.class"/>
115.58 + <not>
115.59 + <equals arg1="${main.class}" arg2="" trim="true"/>
115.60 + </not>
115.61 + </and>
115.62 + </condition>
115.63 + <condition property="manifest.available+main.class+mkdist.available">
115.64 + <and>
115.65 + <istrue value="${manifest.available+main.class}"/>
115.66 + <isset property="libs.CopyLibs.classpath"/>
115.67 + </and>
115.68 + </condition>
115.69 + <condition property="have.tests">
115.70 + <or>
115.71 + <available file="${test.src.dir}"/>
115.72 + </or>
115.73 + </condition>
115.74 + <condition property="have.sources">
115.75 + <or>
115.76 + <available file="${src.dir}"/>
115.77 + </or>
115.78 + </condition>
115.79 + <condition property="netbeans.home+have.tests">
115.80 + <and>
115.81 + <isset property="netbeans.home"/>
115.82 + <isset property="have.tests"/>
115.83 + </and>
115.84 + </condition>
115.85 + <condition property="no.javadoc.preview">
115.86 + <and>
115.87 + <isset property="javadoc.preview"/>
115.88 + <isfalse value="${javadoc.preview}"/>
115.89 + </and>
115.90 + </condition>
115.91 + <property name="run.jvmargs" value=""/>
115.92 + <property name="javac.compilerargs" value=""/>
115.93 + <property name="work.dir" value="${basedir}"/>
115.94 + <condition property="no.deps">
115.95 + <and>
115.96 + <istrue value="${no.dependencies}"/>
115.97 + </and>
115.98 + </condition>
115.99 + <property name="javac.debug" value="true"/>
115.100 + <property name="javadoc.preview" value="true"/>
115.101 + <property name="application.args" value=""/>
115.102 + <property name="source.encoding" value="${file.encoding}"/>
115.103 + <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
115.104 + <and>
115.105 + <isset property="javadoc.encoding"/>
115.106 + <not>
115.107 + <equals arg1="${javadoc.encoding}" arg2=""/>
115.108 + </not>
115.109 + </and>
115.110 + </condition>
115.111 + <property name="javadoc.encoding.used" value="${source.encoding}"/>
115.112 + <property name="includes" value="**"/>
115.113 + <property name="excludes" value=""/>
115.114 + <property name="do.depend" value="false"/>
115.115 + <condition property="do.depend.true">
115.116 + <istrue value="${do.depend}"/>
115.117 + </condition>
115.118 + <condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
115.119 + <and>
115.120 + <isset property="jaxws.endorsed.dir"/>
115.121 + <available file="nbproject/jaxws-build.xml"/>
115.122 + </and>
115.123 + </condition>
115.124 + </target>
115.125 + <target name="-post-init">
115.126 + <!-- Empty placeholder for easier customization. -->
115.127 + <!-- You can override this target in the ../build.xml file. -->
115.128 + </target>
115.129 + <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
115.130 + <fail unless="src.dir">Must set src.dir</fail>
115.131 + <fail unless="test.src.dir">Must set test.src.dir</fail>
115.132 + <fail unless="build.dir">Must set build.dir</fail>
115.133 + <fail unless="dist.dir">Must set dist.dir</fail>
115.134 + <fail unless="build.classes.dir">Must set build.classes.dir</fail>
115.135 + <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
115.136 + <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
115.137 + <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
115.138 + <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
115.139 + <fail unless="dist.jar">Must set dist.jar</fail>
115.140 + </target>
115.141 + <target name="-init-macrodef-property">
115.142 + <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
115.143 + <attribute name="name"/>
115.144 + <attribute name="value"/>
115.145 + <sequential>
115.146 + <property name="@{name}" value="${@{value}}"/>
115.147 + </sequential>
115.148 + </macrodef>
115.149 + </target>
115.150 + <target name="-init-macrodef-javac">
115.151 + <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
115.152 + <attribute default="${src.dir}" name="srcdir"/>
115.153 + <attribute default="${build.classes.dir}" name="destdir"/>
115.154 + <attribute default="${javac.classpath}" name="classpath"/>
115.155 + <attribute default="${includes}" name="includes"/>
115.156 + <attribute default="${excludes}" name="excludes"/>
115.157 + <attribute default="${javac.debug}" name="debug"/>
115.158 + <attribute default="" name="sourcepath"/>
115.159 + <element name="customize" optional="true"/>
115.160 + <sequential>
115.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}">
115.162 + <classpath>
115.163 + <path path="@{classpath}"/>
115.164 + </classpath>
115.165 + <compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
115.166 + <customize/>
115.167 + </javac>
115.168 + </sequential>
115.169 + </macrodef>
115.170 + <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
115.171 + <attribute default="${src.dir}" name="srcdir"/>
115.172 + <attribute default="${build.classes.dir}" name="destdir"/>
115.173 + <attribute default="${javac.classpath}" name="classpath"/>
115.174 + <sequential>
115.175 + <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
115.176 + <classpath>
115.177 + <path path="@{classpath}"/>
115.178 + </classpath>
115.179 + </depend>
115.180 + </sequential>
115.181 + </macrodef>
115.182 + <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
115.183 + <attribute default="${build.classes.dir}" name="destdir"/>
115.184 + <sequential>
115.185 + <fail unless="javac.includes">Must set javac.includes</fail>
115.186 + <pathconvert pathsep="," property="javac.includes.binary">
115.187 + <path>
115.188 + <filelist dir="@{destdir}" files="${javac.includes}"/>
115.189 + </path>
115.190 + <globmapper from="*.java" to="*.class"/>
115.191 + </pathconvert>
115.192 + <delete>
115.193 + <files includes="${javac.includes.binary}"/>
115.194 + </delete>
115.195 + </sequential>
115.196 + </macrodef>
115.197 + </target>
115.198 + <target name="-init-macrodef-junit">
115.199 + <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
115.200 + <attribute default="${includes}" name="includes"/>
115.201 + <attribute default="${excludes}" name="excludes"/>
115.202 + <attribute default="**" name="testincludes"/>
115.203 + <sequential>
115.204 + <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
115.205 + <batchtest todir="${build.test.results.dir}">
115.206 + <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
115.207 + <filename name="@{testincludes}"/>
115.208 + </fileset>
115.209 + </batchtest>
115.210 + <classpath>
115.211 + <path path="${run.test.classpath}"/>
115.212 + </classpath>
115.213 + <syspropertyset>
115.214 + <propertyref prefix="test-sys-prop."/>
115.215 + <mapper from="test-sys-prop.*" to="*" type="glob"/>
115.216 + </syspropertyset>
115.217 + <formatter type="brief" usefile="false"/>
115.218 + <formatter type="xml"/>
115.219 + <jvmarg line="${run.jvmargs}"/>
115.220 + </junit>
115.221 + </sequential>
115.222 + </macrodef>
115.223 + </target>
115.224 + <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
115.225 + <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
115.226 + <attribute default="${main.class}" name="name"/>
115.227 + <attribute default="${debug.classpath}" name="classpath"/>
115.228 + <attribute default="" name="stopclassname"/>
115.229 + <sequential>
115.230 + <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
115.231 + <classpath>
115.232 + <path path="@{classpath}"/>
115.233 + </classpath>
115.234 + </nbjpdastart>
115.235 + </sequential>
115.236 + </macrodef>
115.237 + <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
115.238 + <attribute default="${build.classes.dir}" name="dir"/>
115.239 + <sequential>
115.240 + <nbjpdareload>
115.241 + <fileset dir="@{dir}" includes="${fix.classes}">
115.242 + <include name="${fix.includes}*.class"/>
115.243 + </fileset>
115.244 + </nbjpdareload>
115.245 + </sequential>
115.246 + </macrodef>
115.247 + </target>
115.248 + <target name="-init-debug-args">
115.249 + <property name="version-output" value="java version "${ant.java.version}"/>
115.250 + <condition property="have-jdk-older-than-1.4">
115.251 + <or>
115.252 + <contains string="${version-output}" substring="java version "1.0"/>
115.253 + <contains string="${version-output}" substring="java version "1.1"/>
115.254 + <contains string="${version-output}" substring="java version "1.2"/>
115.255 + <contains string="${version-output}" substring="java version "1.3"/>
115.256 + </or>
115.257 + </condition>
115.258 + <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
115.259 + <istrue value="${have-jdk-older-than-1.4}"/>
115.260 + </condition>
115.261 + <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
115.262 + <os family="windows"/>
115.263 + </condition>
115.264 + <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
115.265 + <isset property="debug.transport"/>
115.266 + </condition>
115.267 + </target>
115.268 + <target depends="-init-debug-args" name="-init-macrodef-debug">
115.269 + <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
115.270 + <attribute default="${main.class}" name="classname"/>
115.271 + <attribute default="${debug.classpath}" name="classpath"/>
115.272 + <element name="customize" optional="true"/>
115.273 + <sequential>
115.274 + <java classname="@{classname}" dir="${work.dir}" fork="true">
115.275 + <jvmarg line="${debug-args-line}"/>
115.276 + <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
115.277 + <jvmarg line="${run.jvmargs}"/>
115.278 + <classpath>
115.279 + <path path="@{classpath}"/>
115.280 + </classpath>
115.281 + <syspropertyset>
115.282 + <propertyref prefix="run-sys-prop."/>
115.283 + <mapper from="run-sys-prop.*" to="*" type="glob"/>
115.284 + </syspropertyset>
115.285 + <customize/>
115.286 + </java>
115.287 + </sequential>
115.288 + </macrodef>
115.289 + </target>
115.290 + <target name="-init-macrodef-java">
115.291 + <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
115.292 + <attribute default="${main.class}" name="classname"/>
115.293 + <element name="customize" optional="true"/>
115.294 + <sequential>
115.295 + <java classname="@{classname}" dir="${work.dir}" fork="true">
115.296 + <jvmarg line="${run.jvmargs}"/>
115.297 + <classpath>
115.298 + <path path="${run.classpath}"/>
115.299 + </classpath>
115.300 + <syspropertyset>
115.301 + <propertyref prefix="run-sys-prop."/>
115.302 + <mapper from="run-sys-prop.*" to="*" type="glob"/>
115.303 + </syspropertyset>
115.304 + <customize/>
115.305 + </java>
115.306 + </sequential>
115.307 + </macrodef>
115.308 + </target>
115.309 + <target name="-init-presetdef-jar">
115.310 + <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
115.311 + <jar compress="${jar.compress}" jarfile="${dist.jar}">
115.312 + <j2seproject1:fileset dir="${build.classes.dir}"/>
115.313 + </jar>
115.314 + </presetdef>
115.315 + </target>
115.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"/>
115.317 + <!--
115.318 + ===================
115.319 + COMPILATION SECTION
115.320 + ===================
115.321 + -->
115.322 + <target depends="init" name="deps-jar" unless="no.deps"/>
115.323 + <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
115.324 + <target depends="init" name="-check-automatic-build">
115.325 + <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
115.326 + </target>
115.327 + <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
115.328 + <antcall target="clean"/>
115.329 + </target>
115.330 + <target depends="init,deps-jar" name="-pre-pre-compile">
115.331 + <mkdir dir="${build.classes.dir}"/>
115.332 + </target>
115.333 + <target name="-pre-compile">
115.334 + <!-- Empty placeholder for easier customization. -->
115.335 + <!-- You can override this target in the ../build.xml file. -->
115.336 + </target>
115.337 + <target if="do.depend.true" name="-compile-depend">
115.338 + <j2seproject3:depend/>
115.339 + </target>
115.340 + <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
115.341 + <j2seproject3:javac/>
115.342 + <copy todir="${build.classes.dir}">
115.343 + <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
115.344 + </copy>
115.345 + </target>
115.346 + <target name="-post-compile">
115.347 + <!-- Empty placeholder for easier customization. -->
115.348 + <!-- You can override this target in the ../build.xml file. -->
115.349 + </target>
115.350 + <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
115.351 + <target name="-pre-compile-single">
115.352 + <!-- Empty placeholder for easier customization. -->
115.353 + <!-- You can override this target in the ../build.xml file. -->
115.354 + </target>
115.355 + <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
115.356 + <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
115.357 + <j2seproject3:force-recompile/>
115.358 + <j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
115.359 + </target>
115.360 + <target name="-post-compile-single">
115.361 + <!-- Empty placeholder for easier customization. -->
115.362 + <!-- You can override this target in the ../build.xml file. -->
115.363 + </target>
115.364 + <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
115.365 + <!--
115.366 + ====================
115.367 + JAR BUILDING SECTION
115.368 + ====================
115.369 + -->
115.370 + <target depends="init" name="-pre-pre-jar">
115.371 + <dirname file="${dist.jar}" property="dist.jar.dir"/>
115.372 + <mkdir dir="${dist.jar.dir}"/>
115.373 + </target>
115.374 + <target name="-pre-jar">
115.375 + <!-- Empty placeholder for easier customization. -->
115.376 + <!-- You can override this target in the ../build.xml file. -->
115.377 + </target>
115.378 + <target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
115.379 + <j2seproject1:jar/>
115.380 + </target>
115.381 + <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
115.382 + <j2seproject1:jar manifest="${manifest.file}"/>
115.383 + </target>
115.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">
115.385 + <j2seproject1:jar manifest="${manifest.file}">
115.386 + <j2seproject1:manifest>
115.387 + <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
115.388 + </j2seproject1:manifest>
115.389 + </j2seproject1:jar>
115.390 + <echo>To run this application from the command line without Ant, try:</echo>
115.391 + <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
115.392 + <property location="${dist.jar}" name="dist.jar.resolved"/>
115.393 + <pathconvert property="run.classpath.with.dist.jar">
115.394 + <path path="${run.classpath}"/>
115.395 + <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
115.396 + </pathconvert>
115.397 + <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
115.398 + </target>
115.399 + <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
115.400 + <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
115.401 + <pathconvert property="run.classpath.without.build.classes.dir">
115.402 + <path path="${run.classpath}"/>
115.403 + <map from="${build.classes.dir.resolved}" to=""/>
115.404 + </pathconvert>
115.405 + <pathconvert pathsep=" " property="jar.classpath">
115.406 + <path path="${run.classpath.without.build.classes.dir}"/>
115.407 + <chainedmapper>
115.408 + <flattenmapper/>
115.409 + <globmapper from="*" to="lib/*"/>
115.410 + </chainedmapper>
115.411 + </pathconvert>
115.412 + <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
115.413 + <copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
115.414 + <fileset dir="${build.classes.dir}"/>
115.415 + <manifest>
115.416 + <attribute name="Main-Class" value="${main.class}"/>
115.417 + <attribute name="Class-Path" value="${jar.classpath}"/>
115.418 + </manifest>
115.419 + </copylibs>
115.420 + <echo>To run this application from the command line without Ant, try:</echo>
115.421 + <property location="${dist.jar}" name="dist.jar.resolved"/>
115.422 + <echo>java -jar "${dist.jar.resolved}"</echo>
115.423 + </target>
115.424 + <target name="-post-jar">
115.425 + <!-- Empty placeholder for easier customization. -->
115.426 + <!-- You can override this target in the ../build.xml file. -->
115.427 + </target>
115.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"/>
115.429 + <!--
115.430 + =================
115.431 + EXECUTION SECTION
115.432 + =================
115.433 + -->
115.434 + <target depends="init,compile" description="Run a main class." name="run">
115.435 + <j2seproject1:java>
115.436 + <customize>
115.437 + <arg line="${application.args}"/>
115.438 + </customize>
115.439 + </j2seproject1:java>
115.440 + </target>
115.441 + <target name="-do-not-recompile">
115.442 + <property name="javac.includes.binary" value=""/>
115.443 + </target>
115.444 + <target depends="init,-do-not-recompile,compile-single" name="run-single">
115.445 + <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
115.446 + <j2seproject1:java classname="${run.class}"/>
115.447 + </target>
115.448 + <!--
115.449 + =================
115.450 + DEBUGGING SECTION
115.451 + =================
115.452 + -->
115.453 + <target depends="init" if="netbeans.home" name="-debug-start-debugger">
115.454 + <j2seproject1:nbjpdastart name="${debug.class}"/>
115.455 + </target>
115.456 + <target depends="init,compile" name="-debug-start-debuggee">
115.457 + <j2seproject3:debug>
115.458 + <customize>
115.459 + <arg line="${application.args}"/>
115.460 + </customize>
115.461 + </j2seproject3:debug>
115.462 + </target>
115.463 + <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
115.464 + <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
115.465 + <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
115.466 + </target>
115.467 + <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
115.468 + <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
115.469 + <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
115.470 + <j2seproject3:debug classname="${debug.class}"/>
115.471 + </target>
115.472 + <target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
115.473 + <target depends="init" name="-pre-debug-fix">
115.474 + <fail unless="fix.includes">Must set fix.includes</fail>
115.475 + <property name="javac.includes" value="${fix.includes}.java"/>
115.476 + </target>
115.477 + <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
115.478 + <j2seproject1:nbjpdareload/>
115.479 + </target>
115.480 + <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
115.481 + <!--
115.482 + ===============
115.483 + JAVADOC SECTION
115.484 + ===============
115.485 + -->
115.486 + <target depends="init" name="-javadoc-build">
115.487 + <mkdir dir="${dist.javadoc.dir}"/>
115.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}">
115.489 + <classpath>
115.490 + <path path="${javac.classpath}"/>
115.491 + </classpath>
115.492 + <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
115.493 + <filename name="**/*.java"/>
115.494 + </fileset>
115.495 + </javadoc>
115.496 + </target>
115.497 + <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
115.498 + <nbbrowse file="${dist.javadoc.dir}/index.html"/>
115.499 + </target>
115.500 + <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
115.501 + <!--
115.502 + =========================
115.503 + JUNIT COMPILATION SECTION
115.504 + =========================
115.505 + -->
115.506 + <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
115.507 + <mkdir dir="${build.test.classes.dir}"/>
115.508 + </target>
115.509 + <target name="-pre-compile-test">
115.510 + <!-- Empty placeholder for easier customization. -->
115.511 + <!-- You can override this target in the ../build.xml file. -->
115.512 + </target>
115.513 + <target if="do.depend.true" name="-compile-test-depend">
115.514 + <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
115.515 + </target>
115.516 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
115.517 + <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
115.518 + <copy todir="${build.test.classes.dir}">
115.519 + <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
115.520 + </copy>
115.521 + </target>
115.522 + <target name="-post-compile-test">
115.523 + <!-- Empty placeholder for easier customization. -->
115.524 + <!-- You can override this target in the ../build.xml file. -->
115.525 + </target>
115.526 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
115.527 + <target name="-pre-compile-test-single">
115.528 + <!-- Empty placeholder for easier customization. -->
115.529 + <!-- You can override this target in the ../build.xml file. -->
115.530 + </target>
115.531 + <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
115.532 + <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
115.533 + <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
115.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}"/>
115.535 + <copy todir="${build.test.classes.dir}">
115.536 + <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
115.537 + </copy>
115.538 + </target>
115.539 + <target name="-post-compile-test-single">
115.540 + <!-- Empty placeholder for easier customization. -->
115.541 + <!-- You can override this target in the ../build.xml file. -->
115.542 + </target>
115.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"/>
115.544 + <!--
115.545 + =======================
115.546 + JUNIT EXECUTION SECTION
115.547 + =======================
115.548 + -->
115.549 + <target depends="init" if="have.tests" name="-pre-test-run">
115.550 + <mkdir dir="${build.test.results.dir}"/>
115.551 + </target>
115.552 + <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
115.553 + <j2seproject3:junit testincludes="**/*Test.java"/>
115.554 + </target>
115.555 + <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
115.556 + <fail if="tests.failed">Some tests failed; see details above.</fail>
115.557 + </target>
115.558 + <target depends="init" if="have.tests" name="test-report"/>
115.559 + <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
115.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"/>
115.561 + <target depends="init" if="have.tests" name="-pre-test-run-single">
115.562 + <mkdir dir="${build.test.results.dir}"/>
115.563 + </target>
115.564 + <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
115.565 + <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
115.566 + <j2seproject3:junit excludes="" includes="${test.includes}"/>
115.567 + </target>
115.568 + <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
115.569 + <fail if="tests.failed">Some tests failed; see details above.</fail>
115.570 + </target>
115.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"/>
115.572 + <!--
115.573 + =======================
115.574 + JUNIT DEBUGGING SECTION
115.575 + =======================
115.576 + -->
115.577 + <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
115.578 + <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
115.579 + <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
115.580 + <delete file="${test.report.file}"/>
115.581 + <mkdir dir="${build.test.results.dir}"/>
115.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}">
115.583 + <customize>
115.584 + <syspropertyset>
115.585 + <propertyref prefix="test-sys-prop."/>
115.586 + <mapper from="test-sys-prop.*" to="*" type="glob"/>
115.587 + </syspropertyset>
115.588 + <arg value="${test.class}"/>
115.589 + <arg value="showoutput=true"/>
115.590 + <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
115.591 + <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
115.592 + </customize>
115.593 + </j2seproject3:debug>
115.594 + </target>
115.595 + <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
115.596 + <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
115.597 + </target>
115.598 + <target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
115.599 + <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
115.600 + <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
115.601 + </target>
115.602 + <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
115.603 + <!--
115.604 + =========================
115.605 + APPLET EXECUTION SECTION
115.606 + =========================
115.607 + -->
115.608 + <target depends="init,compile-single" name="run-applet">
115.609 + <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
115.610 + <j2seproject1:java classname="sun.applet.AppletViewer">
115.611 + <customize>
115.612 + <arg value="${applet.url}"/>
115.613 + </customize>
115.614 + </j2seproject1:java>
115.615 + </target>
115.616 + <!--
115.617 + =========================
115.618 + APPLET DEBUGGING SECTION
115.619 + =========================
115.620 + -->
115.621 + <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
115.622 + <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
115.623 + <j2seproject3:debug classname="sun.applet.AppletViewer">
115.624 + <customize>
115.625 + <arg value="${applet.url}"/>
115.626 + </customize>
115.627 + </j2seproject3:debug>
115.628 + </target>
115.629 + <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
115.630 + <!--
115.631 + ===============
115.632 + CLEANUP SECTION
115.633 + ===============
115.634 + -->
115.635 + <target depends="init" name="deps-clean" unless="no.deps"/>
115.636 + <target depends="init" name="-do-clean">
115.637 + <delete dir="${build.dir}"/>
115.638 + <delete dir="${dist.dir}"/>
115.639 + </target>
115.640 + <target name="-post-clean">
115.641 + <!-- Empty placeholder for easier customization. -->
115.642 + <!-- You can override this target in the ../build.xml file. -->
115.643 + </target>
115.644 + <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
115.645 +</project>
116.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
116.2 +++ b/task4/solution14/nbproject/genfiles.properties Sat Oct 11 23:38:46 2008 +0200
116.3 @@ -0,0 +1,8 @@
116.4 +build.xml.data.CRC32=2ab820eb
116.5 +build.xml.script.CRC32=58a52595
116.6 +build.xml.stylesheet.CRC32=be360661
116.7 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
116.8 +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
116.9 +nbproject/build-impl.xml.data.CRC32=1d0fd5f2
116.10 +nbproject/build-impl.xml.script.CRC32=951643da
116.11 +nbproject/build-impl.xml.stylesheet.CRC32=e55b27f5
117.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
117.2 +++ b/task4/solution14/nbproject/project.properties Sat Oct 11 23:38:46 2008 +0200
117.3 @@ -0,0 +1,68 @@
117.4 +application.title=currency
117.5 +application.vendor=apidesign.org
117.6 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
117.7 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
117.8 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=default
117.9 +build.classes.dir=${build.dir}/classes
117.10 +build.classes.excludes=**/*.java,**/*.form
117.11 +# This directory is removed when the project is cleaned:
117.12 +build.dir=build
117.13 +build.generated.dir=${build.dir}/generated
117.14 +# Only compile against the classpath explicitly listed here:
117.15 +build.sysclasspath=ignore
117.16 +build.test.classes.dir=${build.dir}/test/classes
117.17 +build.test.results.dir=${build.dir}/test/results
117.18 +debug.classpath=\
117.19 + ${run.classpath}
117.20 +debug.test.classpath=\
117.21 + ${run.test.classpath}
117.22 +# This directory is removed when the project is cleaned:
117.23 +dist.dir=dist
117.24 +dist.jar=${dist.dir}/currency.jar
117.25 +dist.javadoc.dir=${dist.dir}/javadoc
117.26 +excludes=
117.27 +file.reference.junit-4.4.jar=../../libs/junit-4.4.jar
117.28 +file.reference.src-apifest08=..
117.29 +includes=**
117.30 +jar.compress=false
117.31 +javac.classpath=
117.32 +# Space-separated list of extra javac options
117.33 +javac.compilerargs=
117.34 +javac.deprecation=false
117.35 +javac.source=1.5
117.36 +javac.target=1.5
117.37 +javac.test.classpath=\
117.38 + ${javac.classpath}:\
117.39 + ${build.classes.dir}:\
117.40 + ${file.reference.junit-4.4.jar}
117.41 +javadoc.additionalparam=
117.42 +javadoc.author=false
117.43 +javadoc.encoding=
117.44 +javadoc.noindex=false
117.45 +javadoc.nonavbar=false
117.46 +javadoc.notree=false
117.47 +javadoc.private=false
117.48 +javadoc.splitindex=true
117.49 +javadoc.use=true
117.50 +javadoc.version=false
117.51 +javadoc.windowtitle=
117.52 +jnlp.codebase.type=local
117.53 +jnlp.codebase.url=file:/home/jarda/src/apifest08/currency/dist
117.54 +jnlp.descriptor=application
117.55 +jnlp.enabled=false
117.56 +jnlp.offline-allowed=false
117.57 +jnlp.signed=false
117.58 +meta.inf.dir=${src.dir}/META-INF
117.59 +platform.active=default_platform
117.60 +run.classpath=\
117.61 + ${javac.classpath}:\
117.62 + ${build.classes.dir}
117.63 +# Space-separated list of JVM arguments used when running the project
117.64 +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
117.65 +# or test-sys-prop.name=value to set system properties for unit tests):
117.66 +run.jvmargs=
117.67 +run.test.classpath=\
117.68 + ${javac.test.classpath}:\
117.69 + ${build.test.classes.dir}
117.70 +src.dir=src
117.71 +test.src.dir=test
118.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
118.2 +++ b/task4/solution14/nbproject/project.xml Sat Oct 11 23:38:46 2008 +0200
118.3 @@ -0,0 +1,16 @@
118.4 +<?xml version="1.0" encoding="UTF-8"?>
118.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
118.6 + <type>org.netbeans.modules.java.j2seproject</type>
118.7 + <configuration>
118.8 + <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
118.9 + <name>Currency Convertor Solution 14</name>
118.10 + <minimum-ant-version>1.6.5</minimum-ant-version>
118.11 + <source-roots>
118.12 + <root id="src.dir"/>
118.13 + </source-roots>
118.14 + <test-roots>
118.15 + <root id="test.src.dir"/>
118.16 + </test-roots>
118.17 + </data>
118.18 + </configuration>
118.19 +</project>
119.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
119.2 +++ b/task4/solution14/src/org/apidesign/apifest08/currency/Convertor.java Sat Oct 11 23:38:46 2008 +0200
119.3 @@ -0,0 +1,201 @@
119.4 +package org.apidesign.apifest08.currency;
119.5 +
119.6 +import java.util.ArrayList;
119.7 +import java.util.Collection;
119.8 +import java.util.Collections;
119.9 +import java.util.HashSet;
119.10 +import java.util.List;
119.11 +import java.util.Set;
119.12 +
119.13 +/** This is the skeleton class for your API. You need to make it public, so
119.14 + * it is accessible to your client code (currently in Task1Test.java) file.
119.15 + * <p>
119.16 + * Feel free to create additional classes or rename this one, just keep all
119.17 + * the API and its implementation in this package. Do not spread it outside
119.18 + * to other packages.
119.19 + */
119.20 +public final class Convertor {
119.21 + //version 1 fields
119.22 +
119.23 + private String currency1 = null;
119.24 + private String currency2 = null;
119.25 + private Rate rate = null;
119.26 +
119.27 + //version 2 field
119.28 + private List<CurrencyRate> currencyRates = null;
119.29 +
119.30 + //version - for compatible mode
119.31 + private int instanceVersion = 0; //compatible mode because of problem with empty currency and CZE -> CZE (1:2) rate
119.32 +
119.33 + Convertor(String currency1, String currency2, Rate rate) {
119.34 + instanceVersion = 1;
119.35 + if ((currency1 == null) || (currency2 == null) || (rate == null)) {
119.36 + throw new IllegalArgumentException("All arguments have to be non-null.");
119.37 + }
119.38 + this.currency1 = currency1;
119.39 + this.currency2 = currency2;
119.40 + this.rate = rate;
119.41 + }
119.42 +
119.43 + Convertor(final CurrencyRate ... currencyRate) {
119.44 + instanceVersion = 2;
119.45 +
119.46 + if (currencyRate == null) {
119.47 + throw new IllegalArgumentException("Parameter cannot be null.");
119.48 + }
119.49 + if (currencyRate.length == 0) {
119.50 + throw new IllegalArgumentException("CurrencyRates cannot be empty.");
119.51 + }
119.52 + Set<Pair<String,String>> currencies = new HashSet<Pair<String,String>>();
119.53 + List<CurrencyRate> curRates = new ArrayList<CurrencyRate>();
119.54 + for (int i = 0; i < currencyRate.length; i++) {
119.55 + CurrencyRate curRat = currencyRate[i];
119.56 + if (curRat == null) {
119.57 + throw new IllegalArgumentException("Parameter cannot be null.");
119.58 + }
119.59 + //check that currencyRate is not defined twice
119.60 + Pair<String, String> curPair= new Pair<String, String>(curRat.getCurrency1(), curRat.getCurrency2());
119.61 + if (currencies.contains(curPair)) {
119.62 + throw new IllegalArgumentException("Pair of currencies in a currency rate cannot be defined twice");
119.63 + }
119.64 + currencies.add(curPair);
119.65 +
119.66 + curRates.add(curRat);
119.67 + }
119.68 + this.currencyRates = Collections.unmodifiableList(curRates);
119.69 + }
119.70 +
119.71 + public double convert(String fromCurrency, String toCurrency, int amount) {
119.72 + if (instanceVersion == 1) {
119.73 + if ((fromCurrency == null) || (toCurrency == null)) {
119.74 + throw new IllegalArgumentException("All arguments have to be non-null.");
119.75 + }
119.76 +
119.77 + if (currency1.equals(fromCurrency) && currency2.equals(toCurrency)) {
119.78 + return rate.convertAtoB(amount);
119.79 + } else if (currency2.equals(fromCurrency) && currency1.equals(toCurrency)) {
119.80 + return rate.convertBtoA(amount);
119.81 + } else {
119.82 + throw new IllegalArgumentException("Convertor " + this.toString() +
119.83 + " cannot work with currencies " + fromCurrency + " and " + toCurrency + ".");
119.84 + }
119.85 + } else { //instanceVersion >= 2
119.86 + //find suitable convertor
119.87 + for (CurrencyRate curRate : currencyRates) {
119.88 + if ((curRate.getCurrency1().equals(fromCurrency))&&
119.89 + (curRate.getCurrency2().equals(toCurrency)))
119.90 + {
119.91 + return curRate.getRate().convertAtoB(amount);
119.92 + }
119.93 + }
119.94 + //suitable convertor not found, try to find inverse convertor
119.95 + for (CurrencyRate curRate : currencyRates) {
119.96 + if ((curRate.getCurrency2().equals(fromCurrency))&&
119.97 + (curRate.getCurrency1().equals(toCurrency)))
119.98 + {
119.99 + return curRate.getRate().convertBtoA(amount);
119.100 + }
119.101 + }
119.102 + //even inverse convertor not found
119.103 + throw new IllegalArgumentException("Cannot work with selected currencies.");
119.104 + }
119.105 + }
119.106 +
119.107 + public double convert(String fromCurrency, String toCurrency, double amount) {
119.108 + if (instanceVersion == 1) {
119.109 + if ((fromCurrency == null) || (toCurrency == null)) {
119.110 + throw new IllegalArgumentException("All arguments have to be non-null.");
119.111 + }
119.112 +
119.113 + if (currency1.equals(fromCurrency) && currency2.equals(toCurrency)) {
119.114 + return rate.convertAtoB(amount);
119.115 + } else if (currency2.equals(fromCurrency) && currency1.equals(toCurrency)) {
119.116 + return rate.convertBtoA(amount);
119.117 + } else {
119.118 + throw new IllegalArgumentException("Convertor " + this.toString() +
119.119 + " cannot work with currencies " + fromCurrency + " and " + toCurrency + ".");
119.120 + }
119.121 + } else { //instanceVersion >= 2
119.122 + //find suitable convertor
119.123 + for (CurrencyRate curRate : currencyRates) {
119.124 + if ((curRate.getCurrency1().equals(fromCurrency))&&
119.125 + (curRate.getCurrency2().equals(toCurrency)))
119.126 + {
119.127 + return curRate.getRate().convertAtoB(amount);
119.128 + }
119.129 + }
119.130 + //suitable convertor not found, try to find inverse convertor
119.131 + for (CurrencyRate curRate : currencyRates) {
119.132 + if ((curRate.getCurrency2().equals(fromCurrency))&&
119.133 + (curRate.getCurrency1().equals(toCurrency)))
119.134 + {
119.135 + return curRate.getRate().convertBtoA(amount);
119.136 + }
119.137 + }
119.138 + //even inverse convertor not found
119.139 + throw new IllegalArgumentException("Cannot work with selected currencies.");
119.140 + }
119.141 + }
119.142 +
119.143 + /**
119.144 + * Returns currency rates. If instantiated with constructor from vesion 1
119.145 + * it creates new collection with one CurrencyRate.
119.146 + * Note, it can cause exception because of empty currencies or same currencies.
119.147 + */
119.148 + public Collection<CurrencyRate> getCurrencyRates() {
119.149 + if (instanceVersion == 1) {
119.150 + List<CurrencyRate> ret = new ArrayList<CurrencyRate>();
119.151 + ret.add(new CurrencyRateImpl(currency1, currency2, rate)); //here it checks that currency rate is not nonsense
119.152 + return Collections.unmodifiableCollection(ret);
119.153 + } else { //instanceVersion >= 2
119.154 + return currencyRates;
119.155 + }
119.156 + }
119.157 +
119.158 + @Override
119.159 + public String toString() {
119.160 + if (instanceVersion == 1) {
119.161 + return currency1 + currency2;
119.162 + } else { //instanceVersion == 2
119.163 + return super.toString(); //better be compatible in future :-)
119.164 + }
119.165 + }
119.166 +
119.167 + @Override
119.168 + public boolean equals(Object obj) {
119.169 + if (instanceVersion == 1) {
119.170 + if (obj == null) {
119.171 + return false;
119.172 + }
119.173 + if (getClass() != obj.getClass()) {
119.174 + return false;
119.175 + }
119.176 + final Convertor other = (Convertor) obj;
119.177 + if (this.currency1 != other.currency1 && (this.currency1 == null || !this.currency1.equals(other.currency1))) {
119.178 + return false;
119.179 + }
119.180 + if (this.currency2 != other.currency2 && (this.currency2 == null || !this.currency2.equals(other.currency2))) {
119.181 + return false;
119.182 + }
119.183 + if (this.rate != other.rate && (this.rate == null || !this.rate.equals(other.rate))) {
119.184 + return false;
119.185 + }
119.186 + return true;
119.187 + } else { //instanceVersion == 2
119.188 + return super.equals(obj); //better be compatible in future :-)
119.189 + }
119.190 + }
119.191 +
119.192 + @Override
119.193 + public int hashCode() {
119.194 + if (instanceVersion == 1) {
119.195 + int hash = 5;
119.196 + hash = 67 * hash + (this.currency1 != null ? this.currency1.hashCode() : 0);
119.197 + hash = 67 * hash + (this.currency2 != null ? this.currency2.hashCode() : 0);
119.198 + hash = 67 * hash + (this.rate != null ? this.rate.hashCode() : 0);
119.199 + return hash;
119.200 + } else { //instanceVersion == 2
119.201 + return super.hashCode(); //better be compatible in future :-)
119.202 + }
119.203 + }
119.204 +}
120.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
120.2 +++ b/task4/solution14/src/org/apidesign/apifest08/currency/ConvertorFactory.java Sat Oct 11 23:38:46 2008 +0200
120.3 @@ -0,0 +1,66 @@
120.4 +
120.5 +package org.apidesign.apifest08.currency;
120.6 +
120.7 +import java.util.ArrayList;
120.8 +import java.util.List;
120.9 +
120.10 +public final class ConvertorFactory {
120.11 +
120.12 + //Singleton
120.13 + private static ConvertorFactory thisFactory = new ConvertorFactory();
120.14 + private ConvertorFactory() {};
120.15 + public static ConvertorFactory newInstance() { //ehm, mistake - it should be named getInstance
120.16 + return thisFactory;
120.17 + }
120.18 +
120.19 + public Convertor createConvertor(String currency1, String currency2, Rate rate) {
120.20 + return new Convertor(currency1, currency2, rate);
120.21 + }
120.22 +
120.23 + public Convertor createConvertor(String currency1, String currency2, int amount1, int amount2) {
120.24 + return new Convertor(currency1, currency2, new Rate(amount1, amount2));
120.25 + }
120.26 +
120.27 + public Convertor createConvertor(String currency1, String currency2, double amount1, double amount2) {
120.28 + return new Convertor(currency1, currency2, new Rate(amount1, amount2));
120.29 + }
120.30 +
120.31 + public Convertor createConvertor(String currency1, String currency2, double rate) {
120.32 + return new Convertor(currency1, currency2, new Rate(rate));
120.33 + }
120.34 +
120.35 + public Convertor createConvertor(CurrencyRate currencyRate) {
120.36 + return new Convertor(currencyRate);
120.37 + }
120.38 +
120.39 + public Convertor createConvertor(CurrencyRate ... currencyRates) {
120.40 + return new Convertor(currencyRates);
120.41 + }
120.42 +
120.43 + public Convertor mergeConvertors(Convertor ... convertors) {
120.44 + if (convertors == null) {
120.45 + throw new IllegalArgumentException("Parameter cannot be null.");
120.46 + }
120.47 + if (convertors.length == 0) {
120.48 + throw new IllegalArgumentException("Convertors cannot be empty.");
120.49 + }
120.50 + List<CurrencyRate> currRates = new ArrayList<CurrencyRate>();
120.51 + List<Pair<String,String>> currPairs = new ArrayList<Pair<String,String>>();
120.52 + for (Convertor convertor : convertors) {
120.53 + if (convertor == null) {
120.54 + throw new IllegalArgumentException("Parameter cannot be null.");
120.55 + }
120.56 + for (CurrencyRate currRate : convertor.getCurrencyRates()) {
120.57 + Pair<String,String> currPair = new Pair<String,String>(currRate.getCurrency1(), currRate.getCurrency2());
120.58 + if (currPairs.contains(currPair)) {
120.59 + throw new IllegalArgumentException("Cannot merge - convertors contain same currency rates.");
120.60 + }
120.61 + currPairs.add(currPair);
120.62 + currRates.add(currRate);
120.63 + }
120.64 + }
120.65 +
120.66 + return new Convertor(currRates.toArray(new CurrencyRate[0]));
120.67 + }
120.68 +
120.69 +}
121.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
121.2 +++ b/task4/solution14/src/org/apidesign/apifest08/currency/CurrencyRate.java Sat Oct 11 23:38:46 2008 +0200
121.3 @@ -0,0 +1,11 @@
121.4 +package org.apidesign.apifest08.currency;
121.5 +
121.6 +/**
121.7 + * This is interface for creating currency rates. The rate can be static or can change in time.
121.8 + * Implement this interface to inform the Convertor about the actual exchange rate between two currencies.
121.9 + */
121.10 +public interface CurrencyRate {
121.11 + public String getCurrency1();
121.12 + public String getCurrency2();
121.13 + public Rate getRate();
121.14 +}
122.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
122.2 +++ b/task4/solution14/src/org/apidesign/apifest08/currency/CurrencyRateFactory.java Sat Oct 11 23:38:46 2008 +0200
122.3 @@ -0,0 +1,25 @@
122.4 +package org.apidesign.apifest08.currency;
122.5 +
122.6 +
122.7 +public final class CurrencyRateFactory {
122.8 +
122.9 + //Singleton
122.10 + private static CurrencyRateFactory thisFactory = new CurrencyRateFactory();
122.11 + private CurrencyRateFactory() {};
122.12 + public static CurrencyRateFactory getInstance() {
122.13 + return thisFactory;
122.14 + }
122.15 +
122.16 + public CurrencyRate createCurrencyRate(final String currency1, final String currency2, final Rate rate) {
122.17 + return new CurrencyRateImpl(currency1, currency2, rate);
122.18 + }
122.19 +
122.20 + public CurrencyRate createCurrencyRate(final String currency1, final String currency2, int amount1, int amount2) {
122.21 + return new CurrencyRateImpl(currency1, currency2, new Rate(amount1, amount2));
122.22 + }
122.23 +
122.24 + public CurrencyRate createCurrencyRate(final String currency1, final String currency2, double amount1, double amount2) {
122.25 + return new CurrencyRateImpl(currency1, currency2, new Rate(amount1, amount2));
122.26 + }
122.27 +
122.28 +}
123.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
123.2 +++ b/task4/solution14/src/org/apidesign/apifest08/currency/CurrencyRateImpl.java Sat Oct 11 23:38:46 2008 +0200
123.3 @@ -0,0 +1,37 @@
123.4 +
123.5 +package org.apidesign.apifest08.currency;
123.6 +
123.7 +public final class CurrencyRateImpl implements CurrencyRate {
123.8 + private String currency1;
123.9 + private String currency2;
123.10 + private Rate rate;
123.11 +
123.12 + CurrencyRateImpl(final String currency1, final String currency2, final Rate rate) {
123.13 + if ((currency1 == null)||(currency2 == null) || (rate == null)) {
123.14 + throw new IllegalArgumentException("Argument cannot be null.");
123.15 + }
123.16 + if ("".equals(currency1) || "".equals(currency2)) {
123.17 + throw new IllegalArgumentException("Name of currency cannot be empty string");
123.18 + }
123.19 + if (currency1.equals(currency2)) {
123.20 + throw new IllegalArgumentException("Currencies in rate cannot be the same");
123.21 + }
123.22 +
123.23 + this.currency1 = currency1;
123.24 + this.currency2 = currency2;
123.25 + this.rate = rate;
123.26 + }
123.27 +
123.28 + public String getCurrency1() {
123.29 + return currency1;
123.30 + }
123.31 +
123.32 + public String getCurrency2() {
123.33 + return currency2;
123.34 + }
123.35 +
123.36 + public Rate getRate(){
123.37 + return rate;
123.38 + }
123.39 +
123.40 +}
124.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
124.2 +++ b/task4/solution14/src/org/apidesign/apifest08/currency/Pair.java Sat Oct 11 23:38:46 2008 +0200
124.3 @@ -0,0 +1,53 @@
124.4 +
124.5 +package org.apidesign.apifest08.currency;
124.6 +
124.7 +
124.8 +public final class Pair<A,B> {
124.9 +
124.10 + private final A first;
124.11 + private final B second;
124.12 +
124.13 + public Pair(A first, B second) {
124.14 + this.first = first;
124.15 + this.second = second;
124.16 + }
124.17 +
124.18 + public A getFirst() { return first; }
124.19 + public B getSecond() { return second; }
124.20 +
124.21 + @Override
124.22 + public String toString() {
124.23 + return "(" + first + ", " + second + ")";
124.24 + }
124.25 +
124.26 + private static boolean equals(Object x, Object y) {
124.27 + return (x == null && y == null) || (x != null && x.equals(y));
124.28 + }
124.29 +
124.30 + @Override
124.31 + public int hashCode() {
124.32 + int hash = 5;
124.33 + hash = 59 * hash + (this.first != null ? this.first.hashCode() : 0);
124.34 + hash = 59 * hash + (this.second != null ? this.second.hashCode() : 0);
124.35 + return hash;
124.36 + }
124.37 +
124.38 + @Override
124.39 + public boolean equals(Object obj) {
124.40 + if (obj == null) {
124.41 + return false;
124.42 + }
124.43 + if (getClass() != obj.getClass()) {
124.44 + return false;
124.45 + }
124.46 + final Pair<A, B> other = (Pair<A, B>) obj;
124.47 + if (this.first != other.first && (this.first == null || !this.first.equals(other.first))) {
124.48 + return false;
124.49 + }
124.50 + if (this.second != other.second && (this.second == null || !this.second.equals(other.second))) {
124.51 + return false;
124.52 + }
124.53 + return true;
124.54 + }
124.55 +
124.56 +}
125.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
125.2 +++ b/task4/solution14/src/org/apidesign/apifest08/currency/Rate.java Sat Oct 11 23:38:46 2008 +0200
125.3 @@ -0,0 +1,68 @@
125.4 +
125.5 +package org.apidesign.apifest08.currency;
125.6 +
125.7 +public final class Rate {
125.8 +
125.9 + private double rate;
125.10 +
125.11 + public Rate(int amountA, int amountB) {
125.12 + rate = amountA / (double)amountB;
125.13 + if (rate <= 0) {
125.14 + throw new IllegalArgumentException("Exchange rate must be positive.");
125.15 + }
125.16 + }
125.17 +
125.18 + public Rate(double amountA, double amountB) {
125.19 + rate = amountA / amountB;
125.20 + if (rate <= 0) {
125.21 + throw new IllegalArgumentException("Exchange rate must be positive.");
125.22 + }
125.23 + }
125.24 +
125.25 + public Rate(double rate) {
125.26 + this.rate = rate;
125.27 + if (this.rate <= 0) {
125.28 + throw new IllegalArgumentException("Exchange rate must be positive.");
125.29 + }
125.30 + }
125.31 +
125.32 + public double convertAtoB(int a) {
125.33 + return a / rate;
125.34 + }
125.35 +
125.36 + public double convertAtoB(double a) {
125.37 + return a / rate;
125.38 + }
125.39 +
125.40 + public double convertBtoA(int b) {
125.41 + return b * rate;
125.42 + }
125.43 +
125.44 + public double convertBtoA(double b) {
125.45 + return b * rate;
125.46 + }
125.47 +
125.48 +
125.49 + @Override
125.50 + public boolean equals(Object obj) {
125.51 + if (obj == null) {
125.52 + return false;
125.53 + }
125.54 + if (getClass() != obj.getClass()) {
125.55 + return false;
125.56 + }
125.57 + final Rate other = (Rate) obj;
125.58 + return true;
125.59 + }
125.60 +
125.61 + @Override
125.62 + public int hashCode() {
125.63 + int hash = 5;
125.64 + return hash;
125.65 + }
125.66 +
125.67 + @Override
125.68 + public String toString() {
125.69 + return ""+rate;
125.70 + }
125.71 +}
126.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
126.2 +++ b/task4/solution14/test/org/apidesign/apifest08/test/Task1Test.java Sat Oct 11 23:38:46 2008 +0200
126.3 @@ -0,0 +1,144 @@
126.4 +package org.apidesign.apifest08.test;
126.5 +
126.6 +import junit.framework.TestCase;
126.7 +import org.apidesign.apifest08.currency.Convertor;
126.8 +import org.apidesign.apifest08.currency.ConvertorFactory;
126.9 +
126.10 +/** Finish the Convertor API, and then write bodies of methods inside
126.11 + * of this class to match the given tasks. To fullfil your task, use the
126.12 + * API define in the <code>org.apidesign.apifest08.currency</code> package.
126.13 + * Do not you reflection, or other hacks as your code
126.14 + * shall run without any runtime permissions.
126.15 + */
126.16 +public class Task1Test extends TestCase {
126.17 + public Task1Test(String testName) {
126.18 + super(testName);
126.19 + }
126.20 +
126.21 + @Override
126.22 + protected void setUp() throws Exception {
126.23 + }
126.24 +
126.25 + @Override
126.26 + protected void tearDown() throws Exception {
126.27 + }
126.28 +
126.29 + //
126.30 + // Imagine that there are three parts of the whole system:
126.31 + // 1. there is someone who knows the current exchange rate
126.32 + // 2. there is someone who wants to do the conversion
126.33 + // 3. there is the API between 1. and 2. which allows them to communicate
126.34 + // Please design such API
126.35 + //
126.36 +
126.37 + /** Create convertor that understands two currencies, CZK and
126.38 + * USD. Make 1 USD == 17 CZK. This is a method provided for #1 group -
126.39 + * e.g. those that know the exchange rate. They somehow need to create
126.40 + * the objects from the API and tell them the exchange rate. The API itself
126.41 + * knows nothing about any rates, before the createCZKtoUSD method is called.
126.42 + *
126.43 + * Creation of the convertor shall not require subclassing of any class
126.44 + * or interface on the client side.
126.45 + *
126.46 + * @return prepared convertor ready for converting USD to CZK and CZK to USD
126.47 + */
126.48 + public static Convertor createCZKtoUSD() {
126.49 + return ConvertorFactory.newInstance().createConvertor("CZK", "USD", 17, 1);
126.50 + }
126.51 +
126.52 + /** Create convertor that understands two currencies, CZK and
126.53 + * SKK. Make 100 SKK == 80 CZK. Again this is method for the #1 group -
126.54 + * it knows the exchange rate, and needs to use the API to create objects
126.55 + * with the exchange rate. Anyone shall be ready to call this method without
126.56 + * any other method being called previously. The API itself shall know
126.57 + * nothing about any rates, before this method is called.
126.58 + *
126.59 + * Creation of the convertor shall not require subclassing of any class
126.60 + * or interface on the client side.
126.61 + *
126.62 + * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
126.63 + */
126.64 + public static Convertor createSKKtoCZK() {
126.65 + return ConvertorFactory.newInstance().createConvertor("SKK", "CZK", 100, 80);
126.66 + }
126.67 +
126.68 + //
126.69 + // now the methods for group #2 follow:
126.70 + // this group knows nothing about exchange rates, but knows how to use
126.71 + // the API to do conversions. It somehow (by calling one of the factory
126.72 + // methods) gets objects from the API and uses them to do the conversions.
126.73 + //
126.74 +
126.75 + /** Use the convertor from <code>createCZKtoUSD</code> method and do few conversions
126.76 + * with it.
126.77 + */
126.78 + public void testCurrencyCZKUSD() throws Exception {
126.79 + Convertor c = createCZKtoUSD();
126.80 + // convert $5 to CZK using c:
126.81 + assertEquals("Result is 85 CZK", 85.0, c.convert("USD", "CZK", 5));
126.82 +
126.83 + // convert $8 to CZK
126.84 + assertEquals("Result is 136 CZK", 136.0, c.convert("USD", "CZK", 8));
126.85 +
126.86 + // convert 1003CZK to USD
126.87 + assertEquals("Result is 59 CZK", 59.0, c.convert("CZK", "USD", 1003));
126.88 + }
126.89 +
126.90 + /** Use the convertor from <code>createSKKtoCZK</code> method and do few conversions
126.91 + * with it.
126.92 + */
126.93 + public void testCurrencySKKCZK() throws Exception {
126.94 + Convertor c = createSKKtoCZK();
126.95 + // convert 16CZK using c:
126.96 + // assertEquals("Result is 20 SKK");
126.97 + assertEquals("Result is 20 SKK", 20.0, c.convert("CZK", "SKK", 16));
126.98 +
126.99 + // convert 500SKK to CZK
126.100 + // assertEquals("Result is 400 CZK");
126.101 + assertEquals("Result is 400 SKK", 400.0, c.convert("SKK", "CZK", 500));
126.102 + }
126.103 +
126.104 + /** Verify that the CZK to USD convertor knows nothing about SKK.
126.105 + */
126.106 + public void testCannotConvertToSKKwithCZKUSDConvertor() throws Exception {
126.107 + Convertor c = createCZKtoUSD();
126.108 + // convert $5 to SKK, the API shall say this is not possible
126.109 + try {
126.110 + c.convert("USD", "SKK", 5);
126.111 + fail("Converting SKK with CZKUSD convertor is impossible");
126.112 + } catch (IllegalArgumentException e){
126.113 + //ok
126.114 + }
126.115 +
126.116 + // convert 500 SKK to CZK, the API shall say this is not possible
126.117 + try {
126.118 + c.convert("SKK", "CZK", 500);
126.119 + fail("Converting SKK with CZKUSD convertor is impossible");
126.120 + } catch (IllegalArgumentException e){
126.121 + //ok
126.122 + }
126.123 +
126.124 + }
126.125 +
126.126 + /** Verify that the CZK to SKK convertor knows nothing about USD.
126.127 + */
126.128 + public void testCannotConvertToUSDwithCZKSKKConvertor() throws Exception {
126.129 + Convertor c = createSKKtoCZK();
126.130 + // convert $5 to SKK, the API shall say this is not possible
126.131 + try {
126.132 + c.convert("USD", "SKK", 5);
126.133 + fail("Converting SKK with SKKCZK convertor is impossible");
126.134 + } catch (IllegalArgumentException e){
126.135 + //ok
126.136 + }
126.137 +
126.138 + // convert 500 CZK to USD, the API shall say this is not possible
126.139 + try {
126.140 + c.convert("CZK", "USD", 500);
126.141 + fail("Converting USD with SKKCZK convertor is impossible");
126.142 + } catch (IllegalArgumentException e){
126.143 + //ok
126.144 + }
126.145 +
126.146 + }
126.147 +}
127.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
127.2 +++ b/task4/solution14/test/org/apidesign/apifest08/test/Task2Test.java Sat Oct 11 23:38:46 2008 +0200
127.3 @@ -0,0 +1,169 @@
127.4 +package org.apidesign.apifest08.test;
127.5 +
127.6 +import junit.framework.TestCase;
127.7 +import org.apidesign.apifest08.currency.Convertor;
127.8 +import org.apidesign.apifest08.currency.ConvertorFactory;
127.9 +import org.apidesign.apifest08.currency.CurrencyRate;
127.10 +import org.apidesign.apifest08.currency.CurrencyRateFactory;
127.11 +
127.12 +/** There are many currencies around the world and many banks manipulate
127.13 + * with more than one or two at the same time. As banks are usually the
127.14 + * best paying clients, which is true even in case of your Convertor API,
127.15 + * it is reasonable to listen to their requests.
127.16 + * <p>
127.17 + * The quest for today is to enhance your existing convertor API to hold
127.18 + * information about many currencies and allow conversions between any of them.
127.19 + * Also, as conversion rates for diferent currencies usually arise from various
127.20 + * bank departments, there is another important need. There is a need to
127.21 + * compose two convertors into one by merging all the information about
127.22 + * currencies they know about.
127.23 + */
127.24 +public class Task2Test extends TestCase {
127.25 + public Task2Test(String testName) {
127.26 + super(testName);
127.27 + }
127.28 +
127.29 + @Override
127.30 + protected void setUp() throws Exception {
127.31 + }
127.32 +
127.33 + @Override
127.34 + protected void tearDown() throws Exception {
127.35 + }
127.36 +
127.37 + // As in Task1Test, keep in mind, that there are three parts
127.38 + // of the whole system:
127.39 + // 1. there is someone who knows the current exchange rate
127.40 + // 2. there is someone who wants to do the conversion
127.41 + // 3. there is the API between 1. and 2. which allows them to communicate
127.42 + //
127.43 + // Please backward compatibly enhance your existing API to support following
127.44 + // usecases:
127.45 + //
127.46 +
127.47 + /** Create convertor that understands two currencies, CZK and
127.48 + * SKK. Make 100 SKK == 75 CZK. This is method for the group of users that
127.49 + * knows the exchange rate, and needs to use the API to create objects
127.50 + * with the exchange rate. Anyone shall be ready to call this method without
127.51 + * any other method being called previously. The API itself shall know
127.52 + * nothing about any rates, before this method is called.
127.53 + */
127.54 + public static Convertor createTripleConvertor() {
127.55 + // Rates: 1USD = 15CZK
127.56 + // Rates: 1USD = 20SKK
127.57 + // Rates: 75CZK = 100SKK
127.58 + CurrencyRate usdCzk = CurrencyRateFactory.getInstance().createCurrencyRate("USD", "CZK", 1, 15);
127.59 + CurrencyRate usdSkk = CurrencyRateFactory.getInstance().createCurrencyRate("USD", "SKK", 1, 20);
127.60 + CurrencyRate czkSkk = CurrencyRateFactory.getInstance().createCurrencyRate("CZK", "SKK", 75, 100);
127.61 + return ConvertorFactory.newInstance().createConvertor(usdCzk, usdSkk, czkSkk);
127.62 + }
127.63 +
127.64 + /** Define convertor that understands three currencies. Use it.
127.65 + */
127.66 + public void testConvertorForUSDandCZKandSKK() throws Exception {
127.67 + Convertor c = createTripleConvertor();
127.68 +
127.69 + // convert $5 to CZK using c:
127.70 + // assertEquals("Result is 75 CZK");
127.71 + assertEquals("Result is 75 CZK", 75.0, c.convert("USD", "CZK", 5));
127.72 +
127.73 + // convert $5 to SKK using c:
127.74 + // assertEquals("Result is 100 SKK");
127.75 + assertEquals("Result is 100 SKK", 100.0, c.convert("USD", "SKK", 5));
127.76 +
127.77 + // convert 200SKK to CZK using c:
127.78 + // assertEquals("Result is 150 CZK");
127.79 + assertEquals("Result is 150 CZK", 150.0, c.convert("SKK", "CZK", 200));
127.80 +
127.81 + // convert 200SKK to USD using c:
127.82 + // assertEquals("Result is 10 USD");
127.83 + assertEquals("Result is 10 USD", 10.0, c.convert("SKK", "USD", 200));
127.84 + }
127.85 +
127.86 + /** Merge all currency rates of convertor 1 with convertor 2.
127.87 + * Implement this using your API, preferably this method just delegates
127.88 + * into some API method which does the actual work, without requiring
127.89 + * API clients to code anything complex.
127.90 + */
127.91 + public static Convertor merge(Convertor one, Convertor two) {
127.92 + return ConvertorFactory.newInstance().mergeConvertors(one,two);
127.93 + }
127.94 +
127.95 + /** Join the convertors from previous task, Task1Test and show that it
127.96 + * can be used to do reasonable conversions.
127.97 + */
127.98 + public void testConvertorComposition() throws Exception {
127.99 + Convertor c = merge(
127.100 + Task1Test.createCZKtoUSD(),
127.101 + Task1Test.createSKKtoCZK()
127.102 + );
127.103 +
127.104 + // convert $5 to CZK using c:
127.105 + // assertEquals("Result is 85 CZK");
127.106 + assertEquals("Result is 85 CZK", 85.0, c.convert("USD", "CZK", 5));
127.107 +
127.108 + // convert $8 to CZK using c:
127.109 + // assertEquals("Result is 136 CZK");
127.110 + assertEquals("Result is 136 CZK", 136.0, c.convert("USD", "CZK", 8));
127.111 +
127.112 + // convert 1003CZK to USD using c:
127.113 + // assertEquals("Result is 59 USD");
127.114 + assertEquals("Result is 59 USD", 59.0, c.convert("CZK", "USD", 1003));
127.115 +
127.116 + // convert 16CZK using c:
127.117 + // assertEquals("Result is 20 SKK");
127.118 + assertEquals("Result is 20 SKK", 20.0, c.convert("CZK", "SKK", 16));
127.119 +
127.120 + // convert 500SKK to CZK using c:
127.121 + // assertEquals("Result is 400 CZK");
127.122 + assertEquals("Result is 400 CZK", 400.0, c.convert("SKK", "CZK", 500));
127.123 +
127.124 + //test exceptions
127.125 + Convertor one = Task1Test.createCZKtoUSD();
127.126 + Convertor two = Task1Test.createSKKtoCZK();
127.127 + Convertor three = Task1Test.createSKKtoCZK();
127.128 + try {
127.129 + ConvertorFactory.newInstance().mergeConvertors(one,two,three);
127.130 + fail();
127.131 + } catch (IllegalArgumentException e) {
127.132 + //ok
127.133 + }
127.134 +
127.135 + //test exceptions
127.136 + try {
127.137 + ConvertorFactory.newInstance().mergeConvertors(c, two);
127.138 + fail();
127.139 + } catch (IllegalArgumentException e) {
127.140 + //ok
127.141 + }
127.142 +
127.143 + //try convertors from version 1
127.144 + Convertor v1one = ConvertorFactory.newInstance().createConvertor("CZE", "CZE", 1, 2);
127.145 + assertEquals("CZE->CZE 1:2 10 expects 20", 20.0, v1one.convert("CZE", "CZE", 10));
127.146 + try {
127.147 + ConvertorFactory.newInstance().mergeConvertors(v1one, two);
127.148 + fail();
127.149 + } catch (IllegalArgumentException e) {
127.150 + //ok
127.151 + }
127.152 +
127.153 + Convertor v1two = ConvertorFactory.newInstance().createConvertor("EUR", "", 1, 2);
127.154 + assertEquals("EUR->'' 1:2 10 expects 20", 20.0, v1two.convert("EUR", "", 10));
127.155 + try {
127.156 + ConvertorFactory.newInstance().mergeConvertors(v1two, two);
127.157 + fail();
127.158 + } catch (IllegalArgumentException e) {
127.159 + //ok
127.160 + }
127.161 +
127.162 + Convertor v1three = ConvertorFactory.newInstance().createConvertor("EUR", "", 1, 2);
127.163 + assertEquals("''->EUR 1:2 10 expects 5", 5.0, v1three.convert("", "EUR", 10));
127.164 + try {
127.165 + ConvertorFactory.newInstance().mergeConvertors(v1three, two);
127.166 + fail();
127.167 + } catch (IllegalArgumentException e) {
127.168 + //ok
127.169 + }
127.170 +
127.171 + }
127.172 +}
128.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
128.2 +++ b/task4/solution14/test/org/apidesign/apifest08/test/Task3Test.java Sat Oct 11 23:38:46 2008 +0200
128.3 @@ -0,0 +1,135 @@
128.4 +package org.apidesign.apifest08.test;
128.5 +
128.6 +import junit.framework.TestCase;
128.7 +import org.apidesign.apifest08.currency.Convertor;
128.8 +import org.apidesign.apifest08.currency.ConvertorFactory;
128.9 +import org.apidesign.apifest08.currency.CurrencyRate;
128.10 +import org.apidesign.apifest08.currency.Rate;
128.11 +
128.12 +/** The exchange rates are not always the same. They are changing. Day by day,
128.13 + * hour by hour, minute by minute. For every bank it is important to always
128.14 + * have the actual exchange rate available in the system. That is why let's
128.15 + * create a pluggable convertor that will always have up to date value of its
128.16 + * exchange rate.
128.17 + * <p>
128.18 + * The quest for today is to allow 3rd party developer to write a convertor
128.19 + * that adjusts its exchange rate everytime it is queried. This convertor is
128.20 + * written by independent vendor, the vendor knows only your Convertor API,
128.21 + * he does not know how the whole system looks and how the convertor is supposed
128.22 + * to be used.
128.23 + */
128.24 +public class Task3Test extends TestCase {
128.25 + public Task3Test(String testName) {
128.26 + super(testName);
128.27 + }
128.28 +
128.29 + @Override
128.30 + protected void setUp() throws Exception {
128.31 + }
128.32 +
128.33 + @Override
128.34 + protected void tearDown() throws Exception {
128.35 + }
128.36 +
128.37 + // Backward compatibly enhance your existing API to support following
128.38 + // usecases:
128.39 + //
128.40 +
128.41 +
128.42 + /** Without knowing anything about the surrounding system, write an
128.43 + * implementation of convertor that will return different rates everytime
128.44 + * it is queried. Convert USD to CZK and vice versa. Start with the rate of
128.45 + * 1USD = 16CZK and adjust it in favor of CZK by 0.01 CZK with every query.
128.46 + * As soon as you reach 1USD = 15CZK adjust it by 0.01 CZK in favor of USD
128.47 + * until you reach 1USD = 16CZK
128.48 + *
128.49 + * @return new instance of "online" USD and CZK convertor starting with rate 1USD = 16CZK
128.50 + */
128.51 + public static Convertor createOnlineCZKUSDConvertor() {
128.52 + // initial rate: 1USD = 16CZK
128.53 + // 2nd query 1USD = 15.99CZK
128.54 + // 3rd query 1USD = 15.98CZK
128.55 + // until 1USD = 15.00CZK
128.56 + // then 1USD = 15.01CZK
128.57 + // then 1USD = 15.02CZK
128.58 + // and so on and on up to 1USD = 16CZK
128.59 + // and then another round to 15, etc.
128.60 + CurrencyRate onlineCurrencyRate = new CurrencyRate() {
128.61 + private int usdAmount = 100;
128.62 + private int czkAmount = 1600;
128.63 + private boolean up = false;
128.64 + public String getCurrency1() {
128.65 + return "USD";
128.66 + }
128.67 +
128.68 + public String getCurrency2() {
128.69 + return "CZK";
128.70 + }
128.71 +
128.72 + public Rate getRate() { //return Rate according to online status
128.73 + Rate rate = new Rate(usdAmount, czkAmount);
128.74 + if (up) {
128.75 + if (czkAmount < 1600) {
128.76 + czkAmount++;
128.77 + } else {
128.78 + up = false;
128.79 + czkAmount--;
128.80 + }
128.81 + } else { //down
128.82 + if (czkAmount > 1500) {
128.83 + czkAmount--;
128.84 + } else {
128.85 + up = true;
128.86 + czkAmount++;
128.87 + }
128.88 + }
128.89 + return rate;
128.90 + }
128.91 + };
128.92 +
128.93 + return ConvertorFactory.newInstance().createConvertor(onlineCurrencyRate);
128.94 + }
128.95 +
128.96 + public void testFewQueriesForOnlineConvertor() {
128.97 + Convertor c = createOnlineCZKUSDConvertor();
128.98 + doFewQueriesForOnlineConvertor(c);
128.99 + }
128.100 +
128.101 + static void doFewQueriesForOnlineConvertor(Convertor c) {
128.102 + // convert $5 to CZK using c:
128.103 + //assertEquals("Result is 80 CZK");
128.104 + assertEquals("Result is 80 CZK", 80.0, c.convert("USD", "CZK", 5), 0.001);
128.105 +
128.106 + // convert $8 to CZK using c:
128.107 + //assertEquals("Result is 127.92 CZK");
128.108 + assertEquals("Result is 127.92 CZK", 127.92, c.convert("USD", "CZK", 8), 0.001);
128.109 +
128.110 + // convert $1 to CZK using c:
128.111 + //assertEquals("Result is 15.98 CZK");
128.112 + assertEquals("Result is 15.98 CZK", 15.98, c.convert("USD", "CZK", 1), 0.001);
128.113 +
128.114 + // convert 15.97CZK to USD using c:
128.115 + //assertEquals("Result is 1$");
128.116 + assertEquals("Result is 1$", 1.0, c.convert("CZK", "USD", 15.97), 0.001);
128.117 +
128.118 + }
128.119 +
128.120 + /** Join the convertors and show they behave sane.
128.121 + */
128.122 + public void testOnlineConvertorComposition() throws Exception {
128.123 + Convertor c = Task2Test.merge(
128.124 + createOnlineCZKUSDConvertor(),
128.125 + Task1Test.createSKKtoCZK()
128.126 + );
128.127 +
128.128 + // convert 16CZK to SKK using c:
128.129 + // assertEquals("Result is 20 SKK");
128.130 + assertEquals("Result is 20 SKK", 20.0, c.convert("CZK", "SKK", 16), 0.001);
128.131 +
128.132 + // convert 500SKK to CZK using c:
128.133 + // assertEquals("Result is 400 CZK");
128.134 + assertEquals("Result is 400 CZK", 400.0, c.convert("SKK", "CZK", 500), 0.001);
128.135 +
128.136 + doFewQueriesForOnlineConvertor(c);
128.137 + }
128.138 +}