aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCamil Staps2015-04-18 00:26:48 +0200
committerCamil Staps2015-04-18 00:26:48 +0200
commit6dd7405206b2babfe491b59250f4d1d7f78e654b (patch)
treea5e53ec980a4cbdce038dd0beb3c8fe71fa0e80c
parentAdded tarball w8 (diff)
Week9
-rw-r--r--.gitignore4
-rw-r--r--Week9/.gitignore9
-rw-r--r--Week9/Assignment (in Dutch).pdfbin0 -> 84105 bytes
-rw-r--r--Week9/Assignment appendix (in Dutch).pdfbin0 -> 43076 bytes
-rw-r--r--Week9/Makefile7
-rw-r--r--Week9/build.xml73
-rw-r--r--Week9/manifest.mf3
-rw-r--r--Week9/nbproject/build-impl.xml1396
-rw-r--r--Week9/nbproject/genfiles.properties8
-rw-r--r--Week9/nbproject/project.properties73
-rw-r--r--Week9/nbproject/project.xml13
-rw-r--r--Week9/solution.tex35
-rw-r--r--Week9/src/com/camilstaps/shop/Article.java89
-rw-r--r--Week9/src/com/camilstaps/shop/CLIInteraction.java94
-rw-r--r--Week9/src/com/camilstaps/shop/Cart.java74
-rw-r--r--Week9/src/com/camilstaps/shop/Category.java28
-rw-r--r--Week9/src/com/camilstaps/shop/Command.java25
-rw-r--r--Week9/src/com/camilstaps/shop/Database.java390
-rw-r--r--Week9/src/com/camilstaps/shop/DatabaseItem.java15
-rw-r--r--Week9/src/com/camilstaps/shop/DuplicateEntryException.java18
-rw-r--r--Week9/src/com/camilstaps/shop/InputRequiredException.java13
-rw-r--r--Week9/src/com/camilstaps/shop/ItemNotFoundException.java14
-rw-r--r--Week9/src/com/camilstaps/shop/Order.java67
-rw-r--r--Week9/src/com/camilstaps/shop/Shell.java476
-rw-r--r--Week9/src/com/camilstaps/shop/Shop.java23
-rw-r--r--Week9/src/com/camilstaps/shop/User.java143
-rw-r--r--Week9/src/com/camilstaps/shop/UserInteraction.java198
-rw-r--r--Week9/uml-project.vppbin0 -> 508928 bytes
28 files changed, 3287 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index 1ee7b42..5a0c41f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,4 +7,6 @@
/Week5/build/
/Week4/dist/
/Week8/nbproject/private/
-/Week8/build/ \ No newline at end of file
+/Week8/build/
+/Week9/nbproject/private/
+/Week9/build/ \ No newline at end of file
diff --git a/Week9/.gitignore b/Week9/.gitignore
new file mode 100644
index 0000000..52083c3
--- /dev/null
+++ b/Week9/.gitignore
@@ -0,0 +1,9 @@
+solution.aux
+solution.idx
+solution.log
+solution.out
+solution.pdf
+db
+
+*.vpp.working
+*.vpp~*
diff --git a/Week9/Assignment (in Dutch).pdf b/Week9/Assignment (in Dutch).pdf
new file mode 100644
index 0000000..087342f
--- /dev/null
+++ b/Week9/Assignment (in Dutch).pdf
Binary files differ
diff --git a/Week9/Assignment appendix (in Dutch).pdf b/Week9/Assignment appendix (in Dutch).pdf
new file mode 100644
index 0000000..9d24ec8
--- /dev/null
+++ b/Week9/Assignment appendix (in Dutch).pdf
Binary files differ
diff --git a/Week9/Makefile b/Week9/Makefile
new file mode 100644
index 0000000..bd1f10f
--- /dev/null
+++ b/Week9/Makefile
@@ -0,0 +1,7 @@
+all: tex view
+
+tex:
+ pdflatex solution.tex
+
+view:
+ gnome-open solution.pdf \ No newline at end of file
diff --git a/Week9/build.xml b/Week9/build.xml
new file mode 100644
index 0000000..d3fe323
--- /dev/null
+++ b/Week9/build.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<!-- By default, only the Clean and Build commands use this build script. -->
+<!-- Commands such as Run, Debug, and Test only use this build script if -->
+<!-- the Compile on Save feature is turned off for the project. -->
+<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
+<!-- in the project's Project Properties dialog box.-->
+<project name="Week9" default="default" basedir=".">
+ <description>Builds, tests, and runs the project Week9.</description>
+ <import file="nbproject/build-impl.xml"/>
+ <!--
+
+ There exist several targets which are by default empty and which can be
+ used for execution of your tasks. These targets are usually executed
+ before and after some main targets. They are:
+
+ -pre-init: called before initialization of project properties
+ -post-init: called after initialization of project properties
+ -pre-compile: called before javac compilation
+ -post-compile: called after javac compilation
+ -pre-compile-single: called before javac compilation of single file
+ -post-compile-single: called after javac compilation of single file
+ -pre-compile-test: called before javac compilation of JUnit tests
+ -post-compile-test: called after javac compilation of JUnit tests
+ -pre-compile-test-single: called before javac compilation of single JUnit test
+ -post-compile-test-single: called after javac compilation of single JUunit test
+ -pre-jar: called before JAR building
+ -post-jar: called after JAR building
+ -post-clean: called after cleaning build products
+
+ (Targets beginning with '-' are not intended to be called on their own.)
+
+ Example of inserting an obfuscator after compilation could look like this:
+
+ <target name="-post-compile">
+ <obfuscate>
+ <fileset dir="${build.classes.dir}"/>
+ </obfuscate>
+ </target>
+
+ For list of available properties check the imported
+ nbproject/build-impl.xml file.
+
+
+ Another way to customize the build is by overriding existing main targets.
+ The targets of interest are:
+
+ -init-macrodef-javac: defines macro for javac compilation
+ -init-macrodef-junit: defines macro for junit execution
+ -init-macrodef-debug: defines macro for class debugging
+ -init-macrodef-java: defines macro for class execution
+ -do-jar: JAR building
+ run: execution of project
+ -javadoc-build: Javadoc generation
+ test-report: JUnit report generation
+
+ An example of overriding the target for project execution could look like this:
+
+ <target name="run" depends="Week9-impl.jar">
+ <exec dir="bin" executable="launcher.exe">
+ <arg file="${dist.jar}"/>
+ </exec>
+ </target>
+
+ Notice that the overridden target depends on the jar target and not only on
+ the compile target as the regular run target does. Again, for a list of available
+ properties which you can use, check the target you are overriding in the
+ nbproject/build-impl.xml file.
+
+ -->
+</project>
diff --git a/Week9/manifest.mf b/Week9/manifest.mf
new file mode 100644
index 0000000..328e8e5
--- /dev/null
+++ b/Week9/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/Week9/nbproject/build-impl.xml b/Week9/nbproject/build-impl.xml
new file mode 100644
index 0000000..6df8cc2
--- /dev/null
+++ b/Week9/nbproject/build-impl.xml
@@ -0,0 +1,1396 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM project.xml - DO NOT EDIT ***
+*** EDIT ../build.xml INSTEAD ***
+
+For the purpose of easier reading the script
+is divided into following sections:
+
+ - initialization
+ - compilation
+ - jar
+ - execution
+ - debugging
+ - javadoc
+ - test compilation
+ - test execution
+ - test debugging
+ - applet
+ - cleanup
+
+ -->
+<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="Week9-impl">
+ <fail message="Please build using Ant 1.8.0 or higher.">
+ <condition>
+ <not>
+ <antversion atleast="1.8.0"/>
+ </not>
+ </condition>
+ </fail>
+ <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
+ <!--
+ ======================
+ INITIALIZATION SECTION
+ ======================
+ -->
+ <target name="-pre-init">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="-pre-init" name="-init-private">
+ <property file="nbproject/private/config.properties"/>
+ <property file="nbproject/private/configs/${config}.properties"/>
+ <property file="nbproject/private/private.properties"/>
+ </target>
+ <target depends="-pre-init,-init-private" name="-init-user">
+ <property file="${user.properties.file}"/>
+ <!-- The two properties below are usually overridden -->
+ <!-- by the active platform. Just a fallback. -->
+ <property name="default.javac.source" value="1.4"/>
+ <property name="default.javac.target" value="1.4"/>
+ </target>
+ <target depends="-pre-init,-init-private,-init-user" name="-init-project">
+ <property file="nbproject/configs/${config}.properties"/>
+ <property file="nbproject/project.properties"/>
+ </target>
+ <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
+ <property name="platform.java" value="${java.home}/bin/java"/>
+ <available file="${manifest.file}" property="manifest.available"/>
+ <condition property="splashscreen.available">
+ <and>
+ <not>
+ <equals arg1="${application.splash}" arg2="" trim="true"/>
+ </not>
+ <available file="${application.splash}"/>
+ </and>
+ </condition>
+ <condition property="main.class.available">
+ <and>
+ <isset property="main.class"/>
+ <not>
+ <equals arg1="${main.class}" arg2="" trim="true"/>
+ </not>
+ </and>
+ </condition>
+ <condition property="profile.available">
+ <and>
+ <isset property="javac.profile"/>
+ <length length="0" string="${javac.profile}" when="greater"/>
+ <matches pattern="1\.[89](\..*)?" string="${javac.source}"/>
+ </and>
+ </condition>
+ <condition property="do.archive">
+ <or>
+ <not>
+ <istrue value="${jar.archive.disabled}"/>
+ </not>
+ <istrue value="${not.archive.disabled}"/>
+ </or>
+ </condition>
+ <condition property="do.mkdist">
+ <and>
+ <isset property="do.archive"/>
+ <isset property="libs.CopyLibs.classpath"/>
+ <not>
+ <istrue value="${mkdist.disabled}"/>
+ </not>
+ </and>
+ </condition>
+ <condition property="do.archive+manifest.available">
+ <and>
+ <isset property="manifest.available"/>
+ <istrue value="${do.archive}"/>
+ </and>
+ </condition>
+ <condition property="do.archive+main.class.available">
+ <and>
+ <isset property="main.class.available"/>
+ <istrue value="${do.archive}"/>
+ </and>
+ </condition>
+ <condition property="do.archive+splashscreen.available">
+ <and>
+ <isset property="splashscreen.available"/>
+ <istrue value="${do.archive}"/>
+ </and>
+ </condition>
+ <condition property="do.archive+profile.available">
+ <and>
+ <isset property="profile.available"/>
+ <istrue value="${do.archive}"/>
+ </and>
+ </condition>
+ <condition property="have.tests">
+ <or/>
+ </condition>
+ <condition property="have.sources">
+ <or>
+ <available file="${src.dir}"/>
+ </or>
+ </condition>
+ <condition property="netbeans.home+have.tests">
+ <and>
+ <isset property="netbeans.home"/>
+ <isset property="have.tests"/>
+ </and>
+ </condition>
+ <condition property="no.javadoc.preview">
+ <and>
+ <isset property="javadoc.preview"/>
+ <isfalse value="${javadoc.preview}"/>
+ </and>
+ </condition>
+ <property name="run.jvmargs" value=""/>
+ <property name="run.jvmargs.ide" value=""/>
+ <property name="javac.compilerargs" value=""/>
+ <property name="work.dir" value="${basedir}"/>
+ <condition property="no.deps">
+ <and>
+ <istrue value="${no.dependencies}"/>
+ </and>
+ </condition>
+ <property name="javac.debug" value="true"/>
+ <property name="javadoc.preview" value="true"/>
+ <property name="application.args" value=""/>
+ <property name="source.encoding" value="${file.encoding}"/>
+ <property name="runtime.encoding" value="${source.encoding}"/>
+ <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
+ <and>
+ <isset property="javadoc.encoding"/>
+ <not>
+ <equals arg1="${javadoc.encoding}" arg2=""/>
+ </not>
+ </and>
+ </condition>
+ <property name="javadoc.encoding.used" value="${source.encoding}"/>
+ <property name="includes" value="**"/>
+ <property name="excludes" value=""/>
+ <property name="do.depend" value="false"/>
+ <condition property="do.depend.true">
+ <istrue value="${do.depend}"/>
+ </condition>
+ <path id="endorsed.classpath.path" path="${endorsed.classpath}"/>
+ <condition else="" property="endorsed.classpath.cmd.line.arg" value="-Xbootclasspath/p:'${toString:endorsed.classpath.path}'">
+ <and>
+ <isset property="endorsed.classpath"/>
+ <not>
+ <equals arg1="${endorsed.classpath}" arg2="" trim="true"/>
+ </not>
+ </and>
+ </condition>
+ <condition else="" property="javac.profile.cmd.line.arg" value="-profile ${javac.profile}">
+ <isset property="profile.available"/>
+ </condition>
+ <condition else="false" property="jdkBug6558476">
+ <and>
+ <matches pattern="1\.[56]" string="${java.specification.version}"/>
+ <not>
+ <os family="unix"/>
+ </not>
+ </and>
+ </condition>
+ <property name="javac.fork" value="${jdkBug6558476}"/>
+ <property name="jar.index" value="false"/>
+ <property name="jar.index.metainf" value="${jar.index}"/>
+ <property name="copylibs.rebase" value="true"/>
+ <available file="${meta.inf.dir}/persistence.xml" property="has.persistence.xml"/>
+ <condition property="junit.available">
+ <or>
+ <available classname="org.junit.Test" classpath="${run.test.classpath}"/>
+ <available classname="junit.framework.Test" classpath="${run.test.classpath}"/>
+ </or>
+ </condition>
+ <condition property="testng.available">
+ <available classname="org.testng.annotations.Test" classpath="${run.test.classpath}"/>
+ </condition>
+ <condition property="junit+testng.available">
+ <and>
+ <istrue value="${junit.available}"/>
+ <istrue value="${testng.available}"/>
+ </and>
+ </condition>
+ <condition else="testng" property="testng.mode" value="mixed">
+ <istrue value="${junit+testng.available}"/>
+ </condition>
+ <condition else="" property="testng.debug.mode" value="-mixed">
+ <istrue value="${junit+testng.available}"/>
+ </condition>
+ </target>
+ <target name="-post-init">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
+ <fail unless="src.dir">Must set src.dir</fail>
+ <fail unless="build.dir">Must set build.dir</fail>
+ <fail unless="dist.dir">Must set dist.dir</fail>
+ <fail unless="build.classes.dir">Must set build.classes.dir</fail>
+ <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
+ <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
+ <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
+ <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
+ <fail unless="dist.jar">Must set dist.jar</fail>
+ </target>
+ <target name="-init-macrodef-property">
+ <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
+ <attribute name="name"/>
+ <attribute name="value"/>
+ <sequential>
+ <property name="@{name}" value="${@{value}}"/>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
+ <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${src.dir}" name="srcdir"/>
+ <attribute default="${build.classes.dir}" name="destdir"/>
+ <attribute default="${javac.classpath}" name="classpath"/>
+ <attribute default="${javac.processorpath}" name="processorpath"/>
+ <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="${javac.debug}" name="debug"/>
+ <attribute default="${empty.dir}" name="sourcepath"/>
+ <attribute default="${empty.dir}" name="gensrcdir"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property location="${build.dir}/empty" name="empty.dir"/>
+ <mkdir dir="${empty.dir}"/>
+ <mkdir dir="@{apgeneratedsrcdir}"/>
+ <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+ <src>
+ <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+ <include name="*"/>
+ </dirset>
+ </src>
+ <classpath>
+ <path path="@{classpath}"/>
+ </classpath>
+ <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <compilerarg line="${javac.profile.cmd.line.arg}"/>
+ <compilerarg line="${javac.compilerargs}"/>
+ <compilerarg value="-processorpath"/>
+ <compilerarg path="@{processorpath}:${empty.dir}"/>
+ <compilerarg line="${ap.processors.internal}"/>
+ <compilerarg line="${annotation.processing.processor.options}"/>
+ <compilerarg value="-s"/>
+ <compilerarg path="@{apgeneratedsrcdir}"/>
+ <compilerarg line="${ap.proc.none.internal}"/>
+ <customize/>
+ </javac>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
+ <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${src.dir}" name="srcdir"/>
+ <attribute default="${build.classes.dir}" name="destdir"/>
+ <attribute default="${javac.classpath}" name="classpath"/>
+ <attribute default="${javac.processorpath}" name="processorpath"/>
+ <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="${javac.debug}" name="debug"/>
+ <attribute default="${empty.dir}" name="sourcepath"/>
+ <attribute default="${empty.dir}" name="gensrcdir"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property location="${build.dir}/empty" name="empty.dir"/>
+ <mkdir dir="${empty.dir}"/>
+ <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+ <src>
+ <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+ <include name="*"/>
+ </dirset>
+ </src>
+ <classpath>
+ <path path="@{classpath}"/>
+ </classpath>
+ <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <compilerarg line="${javac.profile.cmd.line.arg}"/>
+ <compilerarg line="${javac.compilerargs}"/>
+ <customize/>
+ </javac>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
+ <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${src.dir}" name="srcdir"/>
+ <attribute default="${build.classes.dir}" name="destdir"/>
+ <attribute default="${javac.classpath}" name="classpath"/>
+ <sequential>
+ <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
+ <classpath>
+ <path path="@{classpath}"/>
+ </classpath>
+ </depend>
+ </sequential>
+ </macrodef>
+ <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${build.classes.dir}" name="destdir"/>
+ <sequential>
+ <fail unless="javac.includes">Must set javac.includes</fail>
+ <pathconvert pathsep="${line.separator}" property="javac.includes.binary">
+ <path>
+ <filelist dir="@{destdir}" files="${javac.includes}"/>
+ </path>
+ <globmapper from="*.java" to="*.class"/>
+ </pathconvert>
+ <tempfile deleteonexit="true" property="javac.includesfile.binary"/>
+ <echo file="${javac.includesfile.binary}" message="${javac.includes.binary}"/>
+ <delete>
+ <files includesfile="${javac.includesfile.binary}"/>
+ </delete>
+ <delete>
+ <fileset file="${javac.includesfile.binary}"/>
+ </delete>
+ </sequential>
+ </macrodef>
+ </target>
+ <target if="${junit.available}" name="-init-macrodef-junit-init">
+ <condition else="false" property="nb.junit.batch" value="true">
+ <and>
+ <istrue value="${junit.available}"/>
+ <not>
+ <isset property="test.method"/>
+ </not>
+ </and>
+ </condition>
+ <condition else="false" property="nb.junit.single" value="true">
+ <and>
+ <istrue value="${junit.available}"/>
+ <isset property="test.method"/>
+ </and>
+ </condition>
+ </target>
+ <target name="-init-test-properties">
+ <property name="test.binaryincludes" value="&lt;nothing&gt;"/>
+ <property name="test.binarytestincludes" value=""/>
+ <property name="test.binaryexcludes" value=""/>
+ </target>
+ <target if="${nb.junit.single}" name="-init-macrodef-junit-single" unless="${nb.junit.batch}">
+ <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property name="junit.forkmode" value="perTest"/>
+ <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+ <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
+ <syspropertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <formatter type="brief" usefile="false"/>
+ <formatter type="xml"/>
+ <jvmarg value="-ea"/>
+ <customize/>
+ </junit>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-batch" unless="${nb.junit.single}">
+ <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property name="junit.forkmode" value="perTest"/>
+ <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+ <batchtest todir="${build.test.results.dir}">
+ <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
+ <filename name="${test.binarytestincludes}"/>
+ </fileset>
+ </batchtest>
+ <syspropertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <formatter type="brief" usefile="false"/>
+ <formatter type="xml"/>
+ <jvmarg value="-ea"/>
+ <customize/>
+ </junit>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-junit-init,-init-macrodef-junit-single, -init-macrodef-junit-batch" if="${junit.available}" name="-init-macrodef-junit"/>
+ <target if="${testng.available}" name="-init-macrodef-testng">
+ <macrodef name="testng" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <condition else="" property="testng.methods.arg" value="@{testincludes}.@{testmethods}">
+ <isset property="test.method"/>
+ </condition>
+ <union id="test.set"/>
+ <taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/>
+ <testng classfilesetref="test.set" failureProperty="tests.failed" listeners="org.testng.reporters.VerboseReporter" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="Week9" testname="TestNG tests" workingDir="${work.dir}">
+ <xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/>
+ <propertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </propertyset>
+ <customize/>
+ </testng>
+ </sequential>
+ </macrodef>
+ </target>
+ <target name="-init-macrodef-test-impl">
+ <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element implicit="true" name="customize" optional="true"/>
+ <sequential>
+ <echo>No tests executed.</echo>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-junit" if="${junit.available}" name="-init-macrodef-junit-impl">
+ <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element implicit="true" name="customize" optional="true"/>
+ <sequential>
+ <j2seproject3:junit excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+ <customize/>
+ </j2seproject3:junit>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-testng" if="${testng.available}" name="-init-macrodef-testng-impl">
+ <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element implicit="true" name="customize" optional="true"/>
+ <sequential>
+ <j2seproject3:testng excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+ <customize/>
+ </j2seproject3:testng>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-test-impl,-init-macrodef-junit-impl,-init-macrodef-testng-impl" name="-init-macrodef-test">
+ <macrodef name="test" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <sequential>
+ <j2seproject3:test-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+ <customize>
+ <classpath>
+ <path path="${run.test.classpath}"/>
+ </classpath>
+ <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <jvmarg line="${run.jvmargs}"/>
+ <jvmarg line="${run.jvmargs.ide}"/>
+ </customize>
+ </j2seproject3:test-impl>
+ </sequential>
+ </macrodef>
+ </target>
+ <target if="${junit.available}" name="-init-macrodef-junit-debug" unless="${nb.junit.batch}">
+ <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property name="junit.forkmode" value="perTest"/>
+ <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+ <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
+ <syspropertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <formatter type="brief" usefile="false"/>
+ <formatter type="xml"/>
+ <jvmarg value="-ea"/>
+ <jvmarg line="${debug-args-line}"/>
+ <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+ <customize/>
+ </junit>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-debug-batch">
+ <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property name="junit.forkmode" value="perTest"/>
+ <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+ <batchtest todir="${build.test.results.dir}">
+ <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
+ <filename name="${test.binarytestincludes}"/>
+ </fileset>
+ </batchtest>
+ <syspropertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <formatter type="brief" usefile="false"/>
+ <formatter type="xml"/>
+ <jvmarg value="-ea"/>
+ <jvmarg line="${debug-args-line}"/>
+ <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+ <customize/>
+ </junit>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-junit-debug,-init-macrodef-junit-debug-batch" if="${junit.available}" name="-init-macrodef-junit-debug-impl">
+ <macrodef name="test-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element implicit="true" name="customize" optional="true"/>
+ <sequential>
+ <j2seproject3:junit-debug excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+ <customize/>
+ </j2seproject3:junit-debug>
+ </sequential>
+ </macrodef>
+ </target>
+ <target if="${testng.available}" name="-init-macrodef-testng-debug">
+ <macrodef name="testng-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${main.class}" name="testClass"/>
+ <attribute default="" name="testMethod"/>
+ <element name="customize2" optional="true"/>
+ <sequential>
+ <condition else="-testclass @{testClass}" property="test.class.or.method" value="-methods @{testClass}.@{testMethod}">
+ <isset property="test.method"/>
+ </condition>
+ <condition else="-suitename Week9 -testname @{testClass} ${test.class.or.method}" property="testng.cmd.args" value="@{testClass}">
+ <matches pattern=".*\.xml" string="@{testClass}"/>
+ </condition>
+ <delete dir="${build.test.results.dir}" quiet="true"/>
+ <mkdir dir="${build.test.results.dir}"/>
+ <j2seproject3:debug classname="org.testng.TestNG" classpath="${debug.test.classpath}">
+ <customize>
+ <customize2/>
+ <jvmarg value="-ea"/>
+ <arg line="${testng.debug.mode}"/>
+ <arg line="-d ${build.test.results.dir}"/>
+ <arg line="-listener org.testng.reporters.VerboseReporter"/>
+ <arg line="${testng.cmd.args}"/>
+ </customize>
+ </j2seproject3:debug>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-testng-debug" if="${testng.available}" name="-init-macrodef-testng-debug-impl">
+ <macrodef name="testng-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${main.class}" name="testClass"/>
+ <attribute default="" name="testMethod"/>
+ <element implicit="true" name="customize2" optional="true"/>
+ <sequential>
+ <j2seproject3:testng-debug testClass="@{testClass}" testMethod="@{testMethod}">
+ <customize2/>
+ </j2seproject3:testng-debug>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-junit-debug-impl" if="${junit.available}" name="-init-macrodef-test-debug-junit">
+ <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <attribute default="${main.class}" name="testClass"/>
+ <attribute default="" name="testMethod"/>
+ <sequential>
+ <j2seproject3:test-debug-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+ <customize>
+ <classpath>
+ <path path="${run.test.classpath}"/>
+ </classpath>
+ <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <jvmarg line="${run.jvmargs}"/>
+ <jvmarg line="${run.jvmargs.ide}"/>
+ </customize>
+ </j2seproject3:test-debug-impl>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-testng-debug-impl" if="${testng.available}" name="-init-macrodef-test-debug-testng">
+ <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <attribute default="${main.class}" name="testClass"/>
+ <attribute default="" name="testMethod"/>
+ <sequential>
+ <j2seproject3:testng-debug-impl testClass="@{testClass}" testMethod="@{testMethod}">
+ <customize2>
+ <syspropertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ </customize2>
+ </j2seproject3:testng-debug-impl>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-test-debug-junit,-init-macrodef-test-debug-testng" name="-init-macrodef-test-debug"/>
+ <!--
+ pre NB7.2 profiling section; consider it deprecated
+ -->
+ <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile, -profile-init-check" if="profiler.info.jvmargs.agent" name="profile-init"/>
+ <target if="profiler.info.jvmargs.agent" name="-profile-pre-init">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target if="profiler.info.jvmargs.agent" name="-profile-post-init">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target if="profiler.info.jvmargs.agent" name="-profile-init-macrodef-profile">
+ <macrodef name="resolve">
+ <attribute name="name"/>
+ <attribute name="value"/>
+ <sequential>
+ <property name="@{name}" value="${env.@{value}}"/>
+ </sequential>
+ </macrodef>
+ <macrodef name="profile">
+ <attribute default="${main.class}" name="classname"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property environment="env"/>
+ <resolve name="profiler.current.path" value="${profiler.info.pathvar}"/>
+ <java classname="@{classname}" dir="${profiler.info.dir}" fork="true" jvm="${profiler.info.jvm}">
+ <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <jvmarg value="${profiler.info.jvmargs.agent}"/>
+ <jvmarg line="${profiler.info.jvmargs}"/>
+ <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+ <arg line="${application.args}"/>
+ <classpath>
+ <path path="${run.classpath}"/>
+ </classpath>
+ <syspropertyset>
+ <propertyref prefix="run-sys-prop."/>
+ <mapper from="run-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <customize/>
+ </java>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile" if="profiler.info.jvmargs.agent" name="-profile-init-check">
+ <fail unless="profiler.info.jvm">Must set JVM to use for profiling in profiler.info.jvm</fail>
+ <fail unless="profiler.info.jvmargs.agent">Must set profiler agent JVM arguments in profiler.info.jvmargs.agent</fail>
+ </target>
+ <!--
+ end of pre NB7.2 profiling section
+ -->
+ <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
+ <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
+ <attribute default="${main.class}" name="name"/>
+ <attribute default="${debug.classpath}" name="classpath"/>
+ <attribute default="" name="stopclassname"/>
+ <sequential>
+ <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
+ <classpath>
+ <path path="@{classpath}"/>
+ </classpath>
+ </nbjpdastart>
+ </sequential>
+ </macrodef>
+ <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
+ <attribute default="${build.classes.dir}" name="dir"/>
+ <sequential>
+ <nbjpdareload>
+ <fileset dir="@{dir}" includes="${fix.classes}">
+ <include name="${fix.includes}*.class"/>
+ </fileset>
+ </nbjpdareload>
+ </sequential>
+ </macrodef>
+ </target>
+ <target name="-init-debug-args">
+ <property name="version-output" value="java version &quot;${ant.java.version}"/>
+ <condition property="have-jdk-older-than-1.4">
+ <or>
+ <contains string="${version-output}" substring="java version &quot;1.0"/>
+ <contains string="${version-output}" substring="java version &quot;1.1"/>
+ <contains string="${version-output}" substring="java version &quot;1.2"/>
+ <contains string="${version-output}" substring="java version &quot;1.3"/>
+ </or>
+ </condition>
+ <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
+ <istrue value="${have-jdk-older-than-1.4}"/>
+ </condition>
+ <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
+ <os family="windows"/>
+ </condition>
+ <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
+ <isset property="debug.transport"/>
+ </condition>
+ </target>
+ <target depends="-init-debug-args" name="-init-macrodef-debug">
+ <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${main.class}" name="classname"/>
+ <attribute default="${debug.classpath}" name="classpath"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <java classname="@{classname}" dir="${work.dir}" fork="true">
+ <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <jvmarg line="${debug-args-line}"/>
+ <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+ <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+ <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+ <jvmarg line="${run.jvmargs}"/>
+ <jvmarg line="${run.jvmargs.ide}"/>
+ <classpath>
+ <path path="@{classpath}"/>
+ </classpath>
+ <syspropertyset>
+ <propertyref prefix="run-sys-prop."/>
+ <mapper from="run-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <customize/>
+ </java>
+ </sequential>
+ </macrodef>
+ </target>
+ <target name="-init-macrodef-java">
+ <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
+ <attribute default="${main.class}" name="classname"/>
+ <attribute default="${run.classpath}" name="classpath"/>
+ <attribute default="jvm" name="jvm"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <java classname="@{classname}" dir="${work.dir}" fork="true">
+ <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+ <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+ <jvmarg line="${run.jvmargs}"/>
+ <jvmarg line="${run.jvmargs.ide}"/>
+ <classpath>
+ <path path="@{classpath}"/>
+ </classpath>
+ <syspropertyset>
+ <propertyref prefix="run-sys-prop."/>
+ <mapper from="run-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <customize/>
+ </java>
+ </sequential>
+ </macrodef>
+ </target>
+ <target name="-init-macrodef-copylibs">
+ <macrodef name="copylibs" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${manifest.file}" name="manifest"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+ <pathconvert property="run.classpath.without.build.classes.dir">
+ <path path="${run.classpath}"/>
+ <map from="${build.classes.dir.resolved}" to=""/>
+ </pathconvert>
+ <pathconvert pathsep=" " property="jar.classpath">
+ <path path="${run.classpath.without.build.classes.dir}"/>
+ <chainedmapper>
+ <flattenmapper/>
+ <filtermapper>
+ <replacestring from=" " to="%20"/>
+ </filtermapper>
+ <globmapper from="*" to="lib/*"/>
+ </chainedmapper>
+ </pathconvert>
+ <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
+ <copylibs compress="${jar.compress}" excludeFromCopy="${copylibs.excludes}" index="${jar.index}" indexMetaInf="${jar.index.metainf}" jarfile="${dist.jar}" manifest="@{manifest}" rebase="${copylibs.rebase}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
+ <fileset dir="${build.classes.dir}" excludes="${dist.archive.excludes}"/>
+ <manifest>
+ <attribute name="Class-Path" value="${jar.classpath}"/>
+ <customize/>
+ </manifest>
+ </copylibs>
+ </sequential>
+ </macrodef>
+ </target>
+ <target name="-init-presetdef-jar">
+ <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
+ <jar compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}">
+ <j2seproject1:fileset dir="${build.classes.dir}" excludes="${dist.archive.excludes}"/>
+ </jar>
+ </presetdef>
+ </target>
+ <target name="-init-ap-cmdline-properties">
+ <property name="annotation.processing.enabled" value="true"/>
+ <property name="annotation.processing.processors.list" value=""/>
+ <property name="annotation.processing.processor.options" value=""/>
+ <property name="annotation.processing.run.all.processors" value="true"/>
+ <property name="javac.processorpath" value="${javac.classpath}"/>
+ <property name="javac.test.processorpath" value="${javac.test.classpath}"/>
+ <condition property="ap.supported.internal" value="true">
+ <not>
+ <matches pattern="1\.[0-5](\..*)?" string="${javac.source}"/>
+ </not>
+ </condition>
+ </target>
+ <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-ap-cmdline-supported">
+ <condition else="" property="ap.processors.internal" value="-processor ${annotation.processing.processors.list}">
+ <isfalse value="${annotation.processing.run.all.processors}"/>
+ </condition>
+ <condition else="" property="ap.proc.none.internal" value="-proc:none">
+ <isfalse value="${annotation.processing.enabled}"/>
+ </condition>
+ </target>
+ <target depends="-init-ap-cmdline-properties,-init-ap-cmdline-supported" name="-init-ap-cmdline">
+ <property name="ap.cmd.line.internal" value=""/>
+ </target>
+ <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-test,-init-macrodef-test-debug,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar,-init-ap-cmdline" name="init"/>
+ <!--
+ ===================
+ COMPILATION SECTION
+ ===================
+ -->
+ <target name="-deps-jar-init" unless="built-jar.properties">
+ <property location="${build.dir}/built-jar.properties" name="built-jar.properties"/>
+ <delete file="${built-jar.properties}" quiet="true"/>
+ </target>
+ <target if="already.built.jar.${basedir}" name="-warn-already-built-jar">
+ <echo level="warn" message="Cycle detected: Week9 was already built"/>
+ </target>
+ <target depends="init,-deps-jar-init" name="deps-jar" unless="no.deps">
+ <mkdir dir="${build.dir}"/>
+ <touch file="${built-jar.properties}" verbose="false"/>
+ <property file="${built-jar.properties}" prefix="already.built.jar."/>
+ <antcall target="-warn-already-built-jar"/>
+ <propertyfile file="${built-jar.properties}">
+ <entry key="${basedir}" value=""/>
+ </propertyfile>
+ </target>
+ <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
+ <target depends="init" name="-check-automatic-build">
+ <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
+ </target>
+ <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
+ <antcall target="clean"/>
+ </target>
+ <target depends="init,deps-jar" name="-pre-pre-compile">
+ <mkdir dir="${build.classes.dir}"/>
+ </target>
+ <target name="-pre-compile">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target if="do.depend.true" name="-compile-depend">
+ <pathconvert property="build.generated.subdirs">
+ <dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+ <include name="*"/>
+ </dirset>
+ </pathconvert>
+ <j2seproject3:depend srcdir="${src.dir}:${build.generated.subdirs}"/>
+ </target>
+ <target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
+ <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
+ <copy todir="${build.classes.dir}">
+ <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+ </copy>
+ </target>
+ <target if="has.persistence.xml" name="-copy-persistence-xml">
+ <mkdir dir="${build.classes.dir}/META-INF"/>
+ <copy todir="${build.classes.dir}/META-INF">
+ <fileset dir="${meta.inf.dir}" includes="persistence.xml orm.xml"/>
+ </copy>
+ </target>
+ <target name="-post-compile">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
+ <target name="-pre-compile-single">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
+ <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+ <j2seproject3:force-recompile/>
+ <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.dir}"/>
+ </target>
+ <target name="-post-compile-single">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
+ <!--
+ ====================
+ JAR BUILDING SECTION
+ ====================
+ -->
+ <target depends="init" name="-pre-pre-jar">
+ <dirname file="${dist.jar}" property="dist.jar.dir"/>
+ <mkdir dir="${dist.jar.dir}"/>
+ </target>
+ <target name="-pre-jar">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init" if="do.archive" name="-do-jar-create-manifest" unless="manifest.available">
+ <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+ <touch file="${tmp.manifest.file}" verbose="false"/>
+ </target>
+ <target depends="init" if="do.archive+manifest.available" name="-do-jar-copy-manifest">
+ <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+ <copy file="${manifest.file}" tofile="${tmp.manifest.file}"/>
+ </target>
+ <target depends="init,-do-jar-create-manifest,-do-jar-copy-manifest" if="do.archive+main.class.available" name="-do-jar-set-mainclass">
+ <manifest file="${tmp.manifest.file}" mode="update">
+ <attribute name="Main-Class" value="${main.class}"/>
+ </manifest>
+ </target>
+ <target depends="init,-do-jar-create-manifest,-do-jar-copy-manifest" if="do.archive+profile.available" name="-do-jar-set-profile">
+ <manifest file="${tmp.manifest.file}" mode="update">
+ <attribute name="Profile" value="${javac.profile}"/>
+ </manifest>
+ </target>
+ <target depends="init,-do-jar-create-manifest,-do-jar-copy-manifest" if="do.archive+splashscreen.available" name="-do-jar-set-splashscreen">
+ <basename file="${application.splash}" property="splashscreen.basename"/>
+ <mkdir dir="${build.classes.dir}/META-INF"/>
+ <copy failonerror="false" file="${application.splash}" todir="${build.classes.dir}/META-INF"/>
+ <manifest file="${tmp.manifest.file}" mode="update">
+ <attribute name="SplashScreen-Image" value="META-INF/${splashscreen.basename}"/>
+ </manifest>
+ </target>
+ <target depends="init,-init-macrodef-copylibs,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen" if="do.mkdist" name="-do-jar-copylibs">
+ <j2seproject3:copylibs manifest="${tmp.manifest.file}"/>
+ <echo level="info">To run this application from the command line without Ant, try:</echo>
+ <property location="${dist.jar}" name="dist.jar.resolved"/>
+ <echo level="info">java -jar "${dist.jar.resolved}"</echo>
+ </target>
+ <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen" if="do.archive" name="-do-jar-jar" unless="do.mkdist">
+ <j2seproject1:jar manifest="${tmp.manifest.file}"/>
+ <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+ <property location="${dist.jar}" name="dist.jar.resolved"/>
+ <pathconvert property="run.classpath.with.dist.jar">
+ <path path="${run.classpath}"/>
+ <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
+ </pathconvert>
+ <condition else="" property="jar.usage.message" value="To run this application from the command line without Ant, try:${line.separator}${platform.java} -cp ${run.classpath.with.dist.jar} ${main.class}">
+ <isset property="main.class.available"/>
+ </condition>
+ <condition else="debug" property="jar.usage.level" value="info">
+ <isset property="main.class.available"/>
+ </condition>
+ <echo level="${jar.usage.level}" message="${jar.usage.message}"/>
+ </target>
+ <target depends="-do-jar-copylibs" if="do.archive" name="-do-jar-delete-manifest">
+ <delete>
+ <fileset file="${tmp.manifest.file}"/>
+ </delete>
+ </target>
+ <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen,-do-jar-jar,-do-jar-delete-manifest" name="-do-jar-without-libraries"/>
+ <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen,-do-jar-copylibs,-do-jar-delete-manifest" name="-do-jar-with-libraries"/>
+ <target name="-post-jar">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,compile,-pre-jar,-do-jar-without-libraries,-do-jar-with-libraries,-post-jar" name="-do-jar"/>
+ <target depends="init,compile,-pre-jar,-do-jar,-post-jar" description="Build JAR." name="jar"/>
+ <!--
+ =================
+ EXECUTION SECTION
+ =================
+ -->
+ <target depends="init,compile" description="Run a main class." name="run">
+ <j2seproject1:java>
+ <customize>
+ <arg line="${application.args}"/>
+ </customize>
+ </j2seproject1:java>
+ </target>
+ <target name="-do-not-recompile">
+ <property name="javac.includes.binary" value=""/>
+ </target>
+ <target depends="init,compile-single" name="run-single">
+ <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+ <j2seproject1:java classname="${run.class}"/>
+ </target>
+ <target depends="init,compile-test-single" name="run-test-with-main">
+ <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+ <j2seproject1:java classname="${run.class}" classpath="${run.test.classpath}"/>
+ </target>
+ <!--
+ =================
+ DEBUGGING SECTION
+ =================
+ -->
+ <target depends="init" if="netbeans.home" name="-debug-start-debugger">
+ <j2seproject1:nbjpdastart name="${debug.class}"/>
+ </target>
+ <target depends="init" if="netbeans.home" name="-debug-start-debugger-main-test">
+ <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${debug.class}"/>
+ </target>
+ <target depends="init,compile" name="-debug-start-debuggee">
+ <j2seproject3:debug>
+ <customize>
+ <arg line="${application.args}"/>
+ </customize>
+ </j2seproject3:debug>
+ </target>
+ <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
+ <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
+ <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
+ </target>
+ <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
+ <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
+ <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+ <j2seproject3:debug classname="${debug.class}"/>
+ </target>
+ <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
+ <target depends="init,compile-test-single" if="netbeans.home" name="-debug-start-debuggee-main-test">
+ <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+ <j2seproject3:debug classname="${debug.class}" classpath="${debug.test.classpath}"/>
+ </target>
+ <target depends="init,compile-test-single,-debug-start-debugger-main-test,-debug-start-debuggee-main-test" if="netbeans.home" name="debug-test-with-main"/>
+ <target depends="init" name="-pre-debug-fix">
+ <fail unless="fix.includes">Must set fix.includes</fail>
+ <property name="javac.includes" value="${fix.includes}.java"/>
+ </target>
+ <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
+ <j2seproject1:nbjpdareload/>
+ </target>
+ <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
+ <!--
+ =================
+ PROFILING SECTION
+ =================
+ -->
+ <!--
+ pre NB7.2 profiler integration
+ -->
+ <target depends="profile-init,compile" description="Profile a project in the IDE." if="profiler.info.jvmargs.agent" name="-profile-pre72">
+ <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+ <nbprofiledirect>
+ <classpath>
+ <path path="${run.classpath}"/>
+ </classpath>
+ </nbprofiledirect>
+ <profile/>
+ </target>
+ <target depends="profile-init,compile-single" description="Profile a selected class in the IDE." if="profiler.info.jvmargs.agent" name="-profile-single-pre72">
+ <fail unless="profile.class">Must select one file in the IDE or set profile.class</fail>
+ <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+ <nbprofiledirect>
+ <classpath>
+ <path path="${run.classpath}"/>
+ </classpath>
+ </nbprofiledirect>
+ <profile classname="${profile.class}"/>
+ </target>
+ <target depends="profile-init,compile-single" if="profiler.info.jvmargs.agent" name="-profile-applet-pre72">
+ <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+ <nbprofiledirect>
+ <classpath>
+ <path path="${run.classpath}"/>
+ </classpath>
+ </nbprofiledirect>
+ <profile classname="sun.applet.AppletViewer">
+ <customize>
+ <arg value="${applet.url}"/>
+ </customize>
+ </profile>
+ </target>
+ <target depends="profile-init,compile-test-single" if="profiler.info.jvmargs.agent" name="-profile-test-single-pre72">
+ <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+ <nbprofiledirect>
+ <classpath>
+ <path path="${run.test.classpath}"/>
+ </classpath>
+ </nbprofiledirect>
+ <junit dir="${profiler.info.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" jvm="${profiler.info.jvm}" showoutput="true">
+ <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+ <jvmarg value="${profiler.info.jvmargs.agent}"/>
+ <jvmarg line="${profiler.info.jvmargs}"/>
+ <test name="${profile.class}"/>
+ <classpath>
+ <path path="${run.test.classpath}"/>
+ </classpath>
+ <syspropertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <formatter type="brief" usefile="false"/>
+ <formatter type="xml"/>
+ </junit>
+ </target>
+ <!--
+ end of pre NB72 profiling section
+ -->
+ <target if="netbeans.home" name="-profile-check">
+ <condition property="profiler.configured">
+ <or>
+ <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-agentpath:"/>
+ <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-javaagent:"/>
+ </or>
+ </condition>
+ </target>
+ <target depends="-profile-check,-profile-pre72" description="Profile a project in the IDE." if="profiler.configured" name="profile" unless="profiler.info.jvmargs.agent">
+ <startprofiler/>
+ <antcall target="run"/>
+ </target>
+ <target depends="-profile-check,-profile-single-pre72" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-single" unless="profiler.info.jvmargs.agent">
+ <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+ <startprofiler/>
+ <antcall target="run-single"/>
+ </target>
+ <target depends="-profile-test-single-pre72" description="Profile a selected test in the IDE." name="profile-test-single"/>
+ <target depends="-profile-check" description="Profile a selected test in the IDE." if="profiler.configured" name="profile-test" unless="profiler.info.jvmargs">
+ <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+ <startprofiler/>
+ <antcall target="test-single"/>
+ </target>
+ <target depends="-profile-check" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-test-with-main">
+ <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+ <startprofiler/>
+ <antcal target="run-test-with-main"/>
+ </target>
+ <target depends="-profile-check,-profile-applet-pre72" if="profiler.configured" name="profile-applet" unless="profiler.info.jvmargs.agent">
+ <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+ <startprofiler/>
+ <antcall target="run-applet"/>
+ </target>
+ <!--
+ ===============
+ JAVADOC SECTION
+ ===============
+ -->
+ <target depends="init" if="have.sources" name="-javadoc-build">
+ <mkdir dir="${dist.javadoc.dir}"/>
+ <condition else="" property="javadoc.endorsed.classpath.cmd.line.arg" value="-J${endorsed.classpath.cmd.line.arg}">
+ <and>
+ <isset property="endorsed.classpath.cmd.line.arg"/>
+ <not>
+ <equals arg1="${endorsed.classpath.cmd.line.arg}" arg2=""/>
+ </not>
+ </and>
+ </condition>
+ <condition else="" property="bug5101868workaround" value="*.java">
+ <matches pattern="1\.[56](\..*)?" string="${java.version}"/>
+ </condition>
+ <javadoc additionalparam="-J-Dfile.encoding=${file.encoding} ${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}">
+ <classpath>
+ <path path="${javac.classpath}"/>
+ </classpath>
+ <fileset dir="${src.dir}" excludes="${bug5101868workaround},${excludes}" includes="${includes}">
+ <filename name="**/*.java"/>
+ </fileset>
+ <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+ <include name="**/*.java"/>
+ <exclude name="*.java"/>
+ </fileset>
+ <arg line="${javadoc.endorsed.classpath.cmd.line.arg}"/>
+ </javadoc>
+ <copy todir="${dist.javadoc.dir}">
+ <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
+ <filename name="**/doc-files/**"/>
+ </fileset>
+ <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+ <include name="**/doc-files/**"/>
+ </fileset>
+ </copy>
+ </target>
+ <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
+ <nbbrowse file="${dist.javadoc.dir}/index.html"/>
+ </target>
+ <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
+ <!--
+ =========================
+ TEST COMPILATION SECTION
+ =========================
+ -->
+ <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
+ <mkdir dir="${build.test.classes.dir}"/>
+ </target>
+ <target name="-pre-compile-test">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target if="do.depend.true" name="-compile-test-depend">
+ <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir=""/>
+ </target>
+ <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
+ <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" processorpath="${javac.test.processorpath}" srcdir=""/>
+ <copy todir="${build.test.classes.dir}"/>
+ </target>
+ <target name="-post-compile-test">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
+ <target name="-pre-compile-test-single">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
+ <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+ <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
+ <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" processorpath="${javac.test.processorpath}" sourcepath="" srcdir=""/>
+ <copy todir="${build.test.classes.dir}"/>
+ </target>
+ <target name="-post-compile-test-single">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
+ <!--
+ =======================
+ TEST EXECUTION SECTION
+ =======================
+ -->
+ <target depends="init" if="have.tests" name="-pre-test-run">
+ <mkdir dir="${build.test.results.dir}"/>
+ </target>
+ <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
+ <j2seproject3:test includes="${includes}" testincludes="**/*Test.java"/>
+ </target>
+ <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
+ <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+ </target>
+ <target depends="init" if="have.tests" name="test-report"/>
+ <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
+ <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
+ <target depends="init" if="have.tests" name="-pre-test-run-single">
+ <mkdir dir="${build.test.results.dir}"/>
+ </target>
+ <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
+ <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+ <j2seproject3:test excludes="" includes="${test.includes}" testincludes="${test.includes}"/>
+ </target>
+ <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
+ <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+ </target>
+ <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
+ <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single-method">
+ <fail unless="test.class">Must select some files in the IDE or set test.class</fail>
+ <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
+ <j2seproject3:test excludes="" includes="${javac.includes}" testincludes="${test.class}" testmethods="${test.method}"/>
+ </target>
+ <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method" if="have.tests" name="-post-test-run-single-method">
+ <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+ </target>
+ <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method,-post-test-run-single-method" description="Run single unit test." name="test-single-method"/>
+ <!--
+ =======================
+ TEST DEBUGGING SECTION
+ =======================
+ -->
+ <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test">
+ <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+ <j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testincludes="${javac.includes}"/>
+ </target>
+ <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test-method">
+ <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+ <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
+ <j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testMethod="${test.method}" testincludes="${test.class}" testmethods="${test.method}"/>
+ </target>
+ <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
+ <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
+ </target>
+ <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
+ <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test-method" name="debug-test-method"/>
+ <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
+ <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
+ </target>
+ <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
+ <!--
+ =========================
+ APPLET EXECUTION SECTION
+ =========================
+ -->
+ <target depends="init,compile-single" name="run-applet">
+ <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+ <j2seproject1:java classname="sun.applet.AppletViewer">
+ <customize>
+ <arg value="${applet.url}"/>
+ </customize>
+ </j2seproject1:java>
+ </target>
+ <!--
+ =========================
+ APPLET DEBUGGING SECTION
+ =========================
+ -->
+ <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
+ <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+ <j2seproject3:debug classname="sun.applet.AppletViewer">
+ <customize>
+ <arg value="${applet.url}"/>
+ </customize>
+ </j2seproject3:debug>
+ </target>
+ <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
+ <!--
+ ===============
+ CLEANUP SECTION
+ ===============
+ -->
+ <target name="-deps-clean-init" unless="built-clean.properties">
+ <property location="${build.dir}/built-clean.properties" name="built-clean.properties"/>
+ <delete file="${built-clean.properties}" quiet="true"/>
+ </target>
+ <target if="already.built.clean.${basedir}" name="-warn-already-built-clean">
+ <echo level="warn" message="Cycle detected: Week9 was already built"/>
+ </target>
+ <target depends="init,-deps-clean-init" name="deps-clean" unless="no.deps">
+ <mkdir dir="${build.dir}"/>
+ <touch file="${built-clean.properties}" verbose="false"/>
+ <property file="${built-clean.properties}" prefix="already.built.clean."/>
+ <antcall target="-warn-already-built-clean"/>
+ <propertyfile file="${built-clean.properties}">
+ <entry key="${basedir}" value=""/>
+ </propertyfile>
+ </target>
+ <target depends="init" name="-do-clean">
+ <delete dir="${build.dir}"/>
+ <delete dir="${dist.dir}" followsymlinks="false" includeemptydirs="true"/>
+ </target>
+ <target name="-post-clean">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
+ <target name="-check-call-dep">
+ <property file="${call.built.properties}" prefix="already.built."/>
+ <condition property="should.call.dep">
+ <and>
+ <not>
+ <isset property="already.built.${call.subproject}"/>
+ </not>
+ <available file="${call.script}"/>
+ </and>
+ </condition>
+ </target>
+ <target depends="-check-call-dep" if="should.call.dep" name="-maybe-call-dep">
+ <ant antfile="${call.script}" inheritall="false" target="${call.target}">
+ <propertyset>
+ <propertyref prefix="transfer."/>
+ <mapper from="transfer.*" to="*" type="glob"/>
+ </propertyset>
+ </ant>
+ </target>
+</project>
diff --git a/Week9/nbproject/genfiles.properties b/Week9/nbproject/genfiles.properties
new file mode 100644
index 0000000..12dfb41
--- /dev/null
+++ b/Week9/nbproject/genfiles.properties
@@ -0,0 +1,8 @@
+build.xml.data.CRC32=e81d22ef
+build.xml.script.CRC32=078500a2
+build.xml.stylesheet.CRC32=8064a381@1.75.2.48
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=e81d22ef
+nbproject/build-impl.xml.script.CRC32=8b93a16f
+nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48
diff --git a/Week9/nbproject/project.properties b/Week9/nbproject/project.properties
new file mode 100644
index 0000000..b361673
--- /dev/null
+++ b/Week9/nbproject/project.properties
@@ -0,0 +1,73 @@
+annotation.processing.enabled=true
+annotation.processing.enabled.in.editor=false
+annotation.processing.processor.options=
+annotation.processing.processors.list=
+annotation.processing.run.all.processors=true
+annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+ ${run.classpath}
+debug.test.classpath=\
+ ${run.test.classpath}
+# Files in build.classes.dir which should be excluded from distribution jar
+dist.archive.excludes=
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/Week9.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+excludes=
+file.reference.Week9-src=src
+includes=**
+jar.compress=false
+javac.classpath=
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.processorpath=\
+ ${javac.classpath}
+javac.source=1.7
+javac.target=1.7
+javac.test.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+javac.test.processorpath=\
+ ${javac.test.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+main.class=com.camilstaps.shop.Shop
+manifest.file=manifest.mf
+meta.inf.dir=${src.dir}/META-INF
+mkdist.disabled=false
+platform.active=default_platform
+run.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project.
+# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
+# To set system properties for unit tests define test-sys-prop.name=value:
+run.jvmargs=
+run.test.classpath=\
+ ${javac.test.classpath}:\
+ ${build.test.classes.dir}
+source.encoding=UTF-8
+src.dir=${file.reference.Week9-src}
diff --git a/Week9/nbproject/project.xml b/Week9/nbproject/project.xml
new file mode 100644
index 0000000..16c13ca
--- /dev/null
+++ b/Week9/nbproject/project.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+ <type>org.netbeans.modules.java.j2seproject</type>
+ <configuration>
+ <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
+ <name>Week9</name>
+ <source-roots>
+ <root id="src.dir"/>
+ </source-roots>
+ <test-roots/>
+ </data>
+ </configuration>
+</project>
diff --git a/Week9/solution.tex b/Week9/solution.tex
new file mode 100644
index 0000000..eff9370
--- /dev/null
+++ b/Week9/solution.tex
@@ -0,0 +1,35 @@
+\documentclass[a4paper,11pt]{article}
+
+\usepackage[margin=2cm]{geometry}
+\usepackage[hidelinks]{hyperref}
+\usepackage[dutch]{babel}
+\usepackage[utf8]{inputenc}
+\usepackage{fourier}
+
+\author{Camil Staps}
+\title{De RU-webwinkel}
+
+\begin{document}
+
+\maketitle
+
+\section*{Vereenvoudigingen}
+
+\subsection*{Geen webinterface}
+In plaats van een webinterface schrijven we een Java-applicatie waarbij alle interactie op de command line plaatsvindt.
+We gebruiken geen database backend maar een aantal bestanden die lokaal opgeslagen worden.
+
+\subsection*{Per onderdeel}
+
+\begin{description}
+\item[Registreren] Een gebruiker registreert zich vanaf de command line. Het wachtwoord wat gegenereerd wordt, wordt niet naar het emailadres van de gebruiker verstuurd, maar naar \texttt{stdout} geschreven. Het wachtwoord zal niet beveiligd worden opgeslagen.
+\item[Aanbieden van een product] Het zal niet mogelijk zijn voor een gebruiker om multimedia te \emph{uploaden}. Het zal wel mogelijk zijn om multimedia toe te voegen aan een product: hierbij geeft de gebruiker het pad naar het multimediabestand op. Producten zullen niet automatisch na 30 dagen verdwijnen.
+\item[Zoeken van een product] Een gevolg van het werken op de command line is dat we geen multimedia grafisch kunnen weergeven. In plaats daarvan zullen we, als er multimedia aan een product is gekoppeld, het pad naar het bestand weergeven. Het zal slechts mogelijk zijn te zoeken op naam en beschrijving. Het zal niet mogelijk zijn deze zoekopdracht verder te verfijnen.
+\item[Kopen van een product] We voeren geen vereenvoudigingen door op dit onderdeel.
+\item[Afhandeling van de koop] Betalingen worden niet in het systeem verwerkt. In plaats daarvan gaat de gebruiker akkoord met het betalen, waarna hij verwacht wordt langs te komen om te betalen. Hierna zal de beheerder in het systeem kunnen aangeven dat een order is betaald. Er zullen geen extra kosten (als bezorgings-- of administratiekosten) in rekening worden gebracht. De klant geeft verder geen afleveradres op. Hij wordt geacht langs te komen om het artikel op te halen.
+\item[Controle op naleving van de regels] We zullen geen reglement gebruiken. De gebruiker hoeft bij registratie nergens mee in te stemmen, en er wordt dus ook niets vastgelegd. De beheerder zal nog wel gebruikers kunnen blokkeren. Hij wordt hierbij niet gebonden door een reglement, en mag dus iedereen naar believen blokkeren.
+\item[Loggen] Er zullen geen transacties worden gelogd. Op het moment dat een gebruiker uitcheckt, en dus akkoord gaat met de betaling van de artikelen in de winkelwagen, wordt er wel een bestelling aan de database toegevoegd.
+\item[Beheer] Het zal niet mogelijk zijn bestaande artikelen aan te passen. In plaats daarvan zal de beheerder ófwel de lokale bestanden die als database fungeren handmatig moeten aanpassen, of het artikel moeten verwijderen en een nieuw artikel in de plaats zetten. Het zal niet mogelijk zijn personen voor bepaalde tijd te blokkeren, waarbij ze automatisch worden gedeblokkeerd. Het zal wel mogelijk zijn personen handmatig te (de)blokkeren. De beheerder zal geen gebruikers kunnen toevoegen. Gebruikers worden geacht zich zelf te registreren.
+\end{description}
+
+\end{document} \ No newline at end of file
diff --git a/Week9/src/com/camilstaps/shop/Article.java b/Week9/src/com/camilstaps/shop/Article.java
new file mode 100644
index 0000000..92b496f
--- /dev/null
+++ b/Week9/src/com/camilstaps/shop/Article.java
@@ -0,0 +1,89 @@
+/**
+ * Copyright (c) 2015 Camil Staps <info@camilstaps.nl>
+ * See the LICENSE file for copying permission.
+ */
+
+package com.camilstaps.shop;
+
+import java.io.File;
+
+/**
+ * An Article in the webshop
+ * @author Camil Staps, s4498062
+ */
+public class Article extends DatabaseItem {
+
+ /**
+ * Basic data about the article
+ */
+ private final String name;
+ private String description;
+ private final Category category;
+ private File multimedia;
+ private final float price;
+
+ /**
+ * The user who added the article
+ */
+ private final User user;
+
+ /**
+ * Straightforwardly creating a new article
+ * @param user
+ * @param name
+ * @param category
+ * @param price
+ */
+ public Article(User user, String name, Category category, float price) {
+ this.user = user;
+ this.name = name;
+ this.category = category;
+ this.price = price;
+ }
+
+ public User getUser() {
+ return user;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public Category getCategory() {
+ return category;
+ }
+
+ public File getMultimedia() {
+ return multimedia;
+ }
+
+ public float getPrice() {
+ return price;
+ }
+
+ /**
+ * Set a new description
+ * @param description
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Set multimedia
+ * @param multimedia
+ */
+ public void setMultimedia(File multimedia) {
+ this.multimedia = multimedia;
+ }
+
+ @Override
+ public String toString() {
+ return name + " (" + category.getName() + "): " + Float.toString(price);
+ }
+
+} \ No newline at end of file
diff --git a/Week9/src/com/camilstaps/shop/CLIInteraction.java b/Week9/src/com/camilstaps/shop/CLIInteraction.java
new file mode 100644
index 0000000..cbf59ab
--- /dev/null
+++ b/Week9/src/com/camilstaps/shop/CLIInteraction.java
@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2015 Camil Staps <info@camilstaps.nl>
+ * See the LICENSE file for copying permission.
+ */
+
+package com.camilstaps.shop;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.InputMismatchException;
+import java.util.Scanner;
+
+/**
+ * Command Line Interface Interaction
+ * @author Camil Staps, s4498062
+ */
+public class CLIInteraction extends UserInteraction {
+
+ private final Scanner in;
+ private final PrintStream out;
+
+ /**
+ * Default is stdin and stdout
+ */
+ public CLIInteraction() {
+ this(System.in, System.out);
+ }
+
+ /**
+ * CLI interaction with custom input and outputstream
+ * @param is
+ * @param ps
+ */
+ public CLIInteraction(InputStream is, PrintStream ps) {
+ in = new Scanner(is);
+ out = ps;
+ }
+
+ @Override
+ String getString() {
+ return in.nextLine();
+ }
+
+ @Override
+ public int getChoice(String question, String[] options) {
+ out.println(question);
+ int i = 1;
+ for (String option : options) {
+ out.println(" " + (i++) + " : " + option);
+ }
+ int selection = 0;
+ boolean read = false;
+ do {
+ if (read) {
+ out.println("Invalid option. Try again:");
+ }
+ try {
+ selection = in.nextInt();
+ } catch (InputMismatchException ex) {
+ }
+ in.nextLine();
+ read = true;
+ } while (selection < 1 || selection > options.length);
+ return selection - 1;
+ }
+
+ @Override
+ void putString(String string) {
+ out.print(string);
+ }
+
+ @Override
+ Command getCommand() {
+ putString("â–º ");
+ return new Command(getString());
+ }
+
+ @Override
+ float getFloat() {
+ float result = in.nextFloat();
+ in.nextLine();
+ return result;
+ }
+
+ @Override
+ boolean getBoolean() {
+ putString(" (yes/no) ");
+ String result;
+ do {
+ result = in.nextLine();
+ } while (!result.equalsIgnoreCase("yes") && !result.equalsIgnoreCase("no"));
+ return result.equalsIgnoreCase("yes");
+ }
+} \ No newline at end of file
diff --git a/Week9/src/com/camilstaps/shop/Cart.java b/Week9/src/com/camilstaps/shop/Cart.java
new file mode 100644
index 0000000..6c2b836
--- /dev/null
+++ b/Week9/src/com/camilstaps/shop/Cart.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2015 Camil Staps <info@camilstaps.nl>
+ * See the LICENSE file for copying permission.
+ */
+
+package com.camilstaps.shop;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A Cart holds the articles a User is planning to buy.
+ * @author Camil Staps, s4498062
+ */
+public class Cart implements Serializable {
+
+ private final Set<Article> articles = new HashSet<>();
+
+ public Set<Article> getArticles() {
+ return articles;
+ }
+
+ /**
+ * Get the total price of all articles
+ * @return
+ */
+ public float getTotalAmount() {
+ float result = 0;
+ for (Article a : articles) {
+ result += a.getPrice();
+ }
+ return result;
+ }
+
+ /**
+ * Add a new article
+ * @param article
+ */
+ public void add(Article article) {
+ Database.getInstance().removeItem(article);
+ articles.add(article);
+ }
+
+ /**
+ * Remove an article (and put it back in the database)
+ * @param article
+ */
+ public void remove(Article article) {
+ articles.remove(article);
+ try {
+ Database.getInstance().addItem(article);
+ } catch (DuplicateEntryException ex) {
+ }
+ }
+
+ /**
+ * Remove all articles in the manner of remove()
+ * @see self#remove
+ */
+ public void reset() {
+ for (Article a : articles) {
+ remove(a);
+ }
+ }
+
+ /**
+ * Remove all articles, but don't put them back in the database
+ */
+ public void clear() {
+ articles.clear();
+ }
+
+} \ No newline at end of file
diff --git a/Week9/src/com/camilstaps/shop/Category.java b/Week9/src/com/camilstaps/shop/Category.java
new file mode 100644
index 0000000..05c247c
--- /dev/null
+++ b/Week9/src/com/camilstaps/shop/Category.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2015 Camil Staps <info@camilstaps.nl>
+ * See the LICENSE file for copying permission.
+ */
+
+package com.camilstaps.shop;
+
+/**
+ * A Category for Articles
+ * @author Camil Staps, s4498062
+ */
+public class Category extends DatabaseItem {
+
+ private final String name;
+
+ /**
+ * Create a new Category
+ * @param name
+ */
+ public Category(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+} \ No newline at end of file
diff --git a/Week9/src/com/camilstaps/shop/Command.java b/Week9/src/com/camilstaps/shop/Command.java
new file mode 100644
index 0000000..b4694c0
--- /dev/null
+++ b/Week9/src/com/camilstaps/shop/Command.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2015 Camil Staps <info@camilstaps.nl>
+ * See the LICENSE file for copying permission.
+ */
+
+package com.camilstaps.shop;
+
+/**
+ * A Command is something that can be executed by a normal visitor, a User or an Administrator.
+ * The current version only holds one string as command, but later versions could include arguments.
+ * @author Camil Staps, s4498062
+ */
+public class Command {
+
+ private final String command;
+
+ public Command(String command) {
+ this.command = command;
+ }
+
+ public String getCommand() {
+ return command;
+ }
+
+}
diff --git a/Week9/src/com/camilstaps/shop/Database.java b/Week9/src/com/camilstaps/shop/Database.java
new file mode 100644
index 0000000..b04eaf5
--- /dev/null
+++ b/Week9/src/com/camilstaps/shop/Database.java
@@ -0,0 +1,390 @@
+/**
+ * Copyright (c) 2015 Camil Staps <info@camilstaps.nl>
+ * See the LICENSE file for copying permission.
+ */
+
+package com.camilstaps.shop;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * The Shop database
+ * @author Camil Staps, s4498062
+ */
+public class Database {
+
+ /**
+ * This is a singleton
+ */
+ private static Database instance;
+
+ /**
+ * Keep the database in working memory during runtime
+ */
+ private Set<User> users;
+ private Set<Article> articles;
+ private Set<Category> categories;
+ private Set<Order> orders;
+
+ /**
+ * Files to store the database
+ */
+ private final File FILE_DB = new File("./db");
+ private final File FILE_USERS = new File("./db/users.db");
+ private final File FILE_ARTICLES = new File("./db/articles.db");
+ private final File FILE_CATEGORIES = new File("./db/categories.db");
+ private final File FILE_ORDERS = new File("./db/orders.db");
+
+ /**
+ * Don't use this constructor. This is a singleton: use getInstance() instead.
+ * @see self#getInstance()
+ */
+ public Database() {
+ if (!FILE_DB.exists())
+ FILE_DB.mkdir();
+
+ readUsers();
+ readArticles();
+ readCategories();
+ readOrders();
+ }
+
+ /**
+ * Get an instance of the database. This is a singleton.
+ * @return the database
+ */
+ public static Database getInstance() {
+ if (instance == null) {
+ instance = new Database();
+ }
+ return instance;
+ }
+
+ /**
+ * Add an item to the database
+ * @param item the item
+ * @throws com.camilstaps.shop.DuplicateEntryException
+ * @throws ClassCastException if the item to remove is not a DatabaseItem
+ */
+ public void addItem(DatabaseItem item) throws DuplicateEntryException {
+ if (item instanceof User) {
+ if (isUserExists(((User) item).getNr())) {
+ throw new DuplicateEntryException();
+ }
+ users.add((User) item);
+ } else if (item instanceof Article) {
+ if (isArticleExists(((Article) item).getName())) {
+ throw new DuplicateEntryException();
+ }
+ articles.add((Article) item);
+ } else if (item instanceof Category) {
+ if (isCategoryExists(((Category) item).getName())) {
+ throw new DuplicateEntryException();
+ }
+ categories.add((Category) item);
+ } else if (item instanceof Order) {
+ orders.add((Order) item);
+ } else {
+ throw new ClassCastException();
+ }
+ }
+
+ /**
+ * Remove an item from the database
+ * @param item the item to remove
+ * @throws ClassCastException if the item to remove is not a DatabaseItem
+ */
+ public void removeItem(DatabaseItem item) {
+ if (item instanceof User) {
+ users.remove((User) item);
+ } else if (item instanceof Article) {
+ articles.remove((Article) item);
+ } else if (item instanceof Category) {
+ categories.remove((Category) item);
+ } else if (item instanceof Order) {
+ orders.remove((Order) item);
+ } else {
+ throw new ClassCastException();
+ }
+ }
+
+ /**
+ * Save the database to the filesystem.
+ * @return true on success, false on failure
+ */
+ public boolean write() {
+ return writeUsers() && writeArticles() && writeCategories() && writeOrders();
+ }
+
+ /**
+ * Check if there exists a user with a certain U/S-number
+ * @param nr
+ * @return
+ */
+ public boolean isUserExists(String nr) {
+ for (User user : users) {
+ if (user.getNr().equals(nr)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if an article with a name exists
+ * @param name
+ * @return
+ */
+ public boolean isArticleExists(String name) {
+ for (Article article : articles) {
+ if (article.getName().equals(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if a category with a name exists
+ * @param name
+ * @return
+ */
+ public boolean isCategoryExists(String name) {
+ for (Category category : categories) {
+ if (category.getName().equals(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get the set of users
+ * @return
+ */
+ public Set<User> getUsers() {
+ return users;
+ }
+
+ /**
+ * Get the set of articles
+ * @return
+ */
+ public Set<Article> getArticles() {
+ return articles;
+ }
+
+ /**
+ * Get the set of categories
+ * @return
+ */
+ public Set<Category> getCategories() {
+ return categories;
+ }
+
+ /**
+ * Get an array of the names of the categories
+ * @return
+ */
+ public String[] getCategoryNames() {
+ String[] categoryNames = new String[categories.size()];
+ int i = 0;
+ for (Category c : categories) {
+ categoryNames[i++] = c.getName();
+ }
+ return categoryNames;
+ }
+
+ /**
+ * Get the set of orders
+ * @return
+ */
+ public Set<Order> getOrders() {
+ return orders;
+ }
+
+ /**
+ * Get the set of articles of which the name or description matches a regular expression
+ * @param p the regular expression
+ * @return
+ */
+ public Set<Article> searchArticle(Pattern p) {
+ Set<Article> result = new HashSet<>();
+ for (Article a : articles) {
+ if (p.matcher(a.getName()).find() || p.matcher(a.getDescription()).find()) {
+ result.add(a);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Get a user by his number
+ * @param number
+ * @return
+ * @throws com.camilstaps.shop.ItemNotFoundException
+ */
+ public User getUser(String number) throws ItemNotFoundException {
+ for (User u : users) {
+ if (u.getNr().equals(number)) {
+ return u;
+ }
+ }
+ throw new ItemNotFoundException();
+ }
+
+ /**
+ * Get an article by its name
+ * @param name
+ * @return
+ * @throws ItemNotFoundException
+ */
+ public Article getArticle(String name) throws ItemNotFoundException {
+ for (Article a : articles) {
+ if (a.getName().equals(name)) {
+ return a;
+ }
+ }
+ throw new ItemNotFoundException();
+ }
+
+ /**
+ * Get a category by a name
+ * @param name
+ * @return
+ */
+ public Category getCategory(String name) throws ItemNotFoundException {
+ for (Category c : categories) {
+ if (c.getName().equals(name)) {
+ return c;
+ }
+ }
+ throw new ItemNotFoundException();
+ }
+
+ /**
+ * Read the users from the database into RAM
+ */
+ private void readUsers() {
+ users = new HashSet<>();
+ try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(FILE_USERS))) {
+ users = (Set) in.readObject();
+ in.close();
+ } catch (FileNotFoundException ex) {
+ } catch (IOException | ClassNotFoundException ex) {
+ }
+ }
+
+ /**
+ * Read the articles from the database into RAM
+ */
+ private void readArticles() {
+ articles = new HashSet<>();
+ try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(FILE_ARTICLES))) {
+ articles = (Set) in.readObject();
+ in.close();
+ } catch (FileNotFoundException ex) {
+ } catch (IOException | ClassNotFoundException ex) {
+ }
+ }
+
+ /**
+ * Read the categories from the database into RAM
+ */
+ private void readCategories() {
+ categories = new HashSet<>();
+ try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(FILE_CATEGORIES))) {
+ categories = (Set) in.readObject();
+ in.close();
+ } catch (FileNotFoundException ex) {
+ } catch (IOException | ClassNotFoundException ex) {
+ }
+ }
+
+ /**
+ * Read the orders from the database into RAM
+ */
+ private void readOrders() {
+ orders = new HashSet<>();
+ try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(FILE_ORDERS))) {
+ orders = (Set) in.readObject();
+ in.close();
+ } catch (FileNotFoundException ex) {
+ } catch (IOException | ClassNotFoundException ex) {
+ }
+ }
+
+ /**
+ * Write the users from RAM to the database
+ */
+ private boolean writeUsers() {
+ System.err.println("Saving users...");
+
+ try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(FILE_USERS))) {
+ out.writeObject(users);
+ out.close();
+ return true;
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ return false;
+ }
+
+ /**
+ * Write the articles from RAM to the database
+ */
+ private boolean writeArticles() {
+ System.err.println("Saving articles...");
+
+ try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(FILE_ARTICLES))) {
+ out.writeObject(articles);
+ out.close();
+ return true;
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ return false;
+ }
+
+ /**
+ * Write the categories from RAM to the database
+ */
+ private boolean writeCategories() {
+ System.err.println("Saving categories...");
+
+ try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(FILE_CATEGORIES))) {
+ out.writeObject(categories);
+ out.close();
+ return true;
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ return false;
+ }
+
+ /**
+ * Write the orders from RAM to the database
+ */
+ private boolean writeOrders() {
+ System.err.println("Saving orders...");
+
+ try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(FILE_ORDERS))) {
+ out.writeObject(orders);
+ out.close();
+ return true;
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ return false;
+ }
+
+} \ No newline at end of file
diff --git a/Week9/src/com/camilstaps/shop/DatabaseItem.java b/Week9/src/com/camilstaps/shop/DatabaseItem.java
new file mode 100644
index 0000000..0cbe661
--- /dev/null
+++ b/Week9/src/com/camilstaps/shop/DatabaseItem.java
@@ -0,0 +1,15 @@
+/**
+ * Copyright (c) 2015 Camil Staps <info@camilstaps.nl>
+ * See the LICENSE file for copying permission.
+ */
+
+package com.camilstaps.shop;
+
+import java.io.Serializable;
+
+/**
+ * DatabaseItem is a general class for anything that is stored in the Database
+ * @author Camil Staps, s4498062
+ */
+public class DatabaseItem implements Serializable {
+} \ No newline at end of file
diff --git a/Week9/src/com/camilstaps/shop/DuplicateEntryException.java b/Week9/src/com/camilstaps/shop/DuplicateEntryException.java
new file mode 100644
index 0000000..a91d7c7
--- /dev/null
+++ b/Week9/src/com/camilstaps/shop/DuplicateEntryException.java
@@ -0,0 +1,18 @@
+/**
+ * Copyright (c) 2015 Camil Staps <info@camilstaps.nl>
+ * See the LICENSE file for copying permission.
+ */
+
+package com.camilstaps.shop;
+
+/**
+ * This Exception is thrown when an attempt is made to add a DatabaseItem to the
+ * Database which gives a uniqueness conflict, such as:
+ * * An article with the same name exists
+ * * A category with the same name exists
+ * * A user with the same number exists
+ *
+ * @author Camil Staps, s4498062
+ */
+public class DuplicateEntryException extends Exception {
+}
diff --git a/Week9/src/com/camilstaps/shop/InputRequiredException.java b/Week9/src/com/camilstaps/shop/InputRequiredException.java
new file mode 100644
index 0000000..ca0110d
--- /dev/null
+++ b/Week9/src/com/camilstaps/shop/InputRequiredException.java
@@ -0,0 +1,13 @@
+/**
+ * Copyright (c) 2015 Camil Staps <info@camilstaps.nl>
+ * See the LICENSE file for copying permission.
+ */
+
+package com.camilstaps.shop;
+
+/**
+ * This Exception is thrown when required input was omitted by the user.
+ * @author Camil Staps, s4498062
+ */
+public class InputRequiredException extends Exception {
+}
diff --git a/Week9/src/com/camilstaps/shop/ItemNotFoundException.java b/Week9/src/com/camilstaps/shop/ItemNotFoundException.java
new file mode 100644
index 0000000..5122d79
--- /dev/null
+++ b/Week9/src/com/camilstaps/shop/ItemNotFoundException.java
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 2015 Camil Staps <info@camilstaps.nl>
+ * See the LICENSE file for copying permission.
+ */
+
+package com.camilstaps.shop;
+
+/**
+ * This error is thrown when an attempt is made to instantiate an object with a
+ * non-existing name, number, etc.
+ * @author Camil Staps, s4498062
+ */
+public class ItemNotFoundException extends Exception {
+}
diff --git a/Week9/src/com/camilstaps/shop/Order.java b/Week9/src/com/camilstaps/shop/Order.java
new file mode 100644
index 0000000..92d04d7
--- /dev/null
+++ b/Week9/src/com/camilstaps/shop/Order.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2015 Camil Staps <info@camilstaps.nl>
+ * See the LICENSE file for copying permission.
+ */
+
+package com.camilstaps.shop;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * An order is a set of articles, purchased by a user
+ * @author Camil Staps, s4498062
+ */
+public class Order extends DatabaseItem {
+
+ private final Set<Article> articles;
+ private final User user;
+ private boolean paid = false;
+
+ /**
+ * This constructor takes the articles from the Cart of the User, and clears
+ * that Cart afterwards.
+ * @param user
+ */
+ public Order(User user) {
+ this.user = user;
+ articles = new HashSet<>();
+ for (Article a : user.getCart().getArticles()) {
+ articles.add(a);
+ }
+ user.getCart().clear();
+ }
+
+ public User getUser() {
+ return user;
+ }
+
+ public Set<Article> getArticles() {
+ return articles;
+ }
+
+ public void setPaid(boolean set) {
+ paid = set;
+ }
+
+ /**
+ * See whether payment has been received for this article already
+ * @return
+ */
+ public boolean isPaid() {
+ return paid;
+ }
+
+ /**
+ * Get the total price of all articles
+ * @return
+ */
+ public float getTotalAmount() {
+ float result = 0;
+ for (Article a : articles) {
+ result += a.getPrice();
+ }
+ return result;
+ }
+
+}
diff --git a/Week9/src/com/camilstaps/shop/Shell.java b/Week9/src/com/camilstaps/shop/Shell.java
new file mode 100644
index 0000000..69d5207
--- /dev/null
+++ b/Week9/src/com/camilstaps/shop/Shell.java
@@ -0,0 +1,476 @@
+/**
+ * Copyright (c) 2015 Camil Staps <info@camilstaps.nl>
+ * See the LICENSE file for copying permission.
+ */
+
+package com.camilstaps.shop;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * Executing commands and providing output, using a UserInteraction and acting
+ * on a Database.
+ * @author Camil Staps, s4498062
+ */
+public class Shell {
+
+ /**
+ * The Database to work with
+ */
+ private final Database database;
+ /**
+ * The UserInteraction to use
+ */
+ private final UserInteraction ui;
+
+ /**
+ * The current User, if logged in
+ */
+ private User user;
+
+ public Shell(UserInteraction userInteraction) {
+ this.database = Database.getInstance();
+ this.ui = userInteraction;
+ }
+
+ /**
+ * Request commands, execute them, and show the results
+ */
+ public void run() {
+ while (true) {
+ Command command = ui.getCommand();
+ try {
+ Method method = getClass().getMethod("exec" + command.getCommand().substring(0,1).toUpperCase() + command.getCommand().substring(1));
+ method.invoke(this);
+
+ if (command.getCommand().equalsIgnoreCase("exit")) {
+ return;
+ }
+ } catch (NoSuchMethodException ex) {
+ ui.putStringLn("Failure: no such command");
+ } catch (InvocationTargetException ex) {
+ ui.putStringLn("Failure: " + ex.getCause().toString());
+ } catch (SecurityException | IllegalAccessException | IllegalArgumentException ex) {
+ ui.putStringLn("Failure: unknown error");
+ }
+ }
+ }
+
+ /**
+ * Require that the visitor logs in
+ * @throws com.camilstaps.shop.Shell.LoginRequiredException if the visitor fails to login
+ * @throws ItemNotFoundException if the visitor tries to login with a non-existing User number
+ */
+ public void requireLogin() throws LoginRequiredException, ItemNotFoundException {
+ if (user == null) {
+ ui.putStringLn("You must login first.");
+
+ try {
+ execLogin();
+ } catch (InputRequiredException ex) {
+ }
+
+ if (user == null) {
+ throw new LoginRequiredException();
+ }
+ }
+ }
+
+ /**
+ * Require that an administrator is logged in
+ * @throws com.camilstaps.shop.Shell.AdminRequiredException if the visitor fails to login, or is not an administrator
+ * @throws ItemNotFoundException if the visitor tries to login with a non-existing User number
+ */
+ public void requireAdmin() throws AdminRequiredException, ItemNotFoundException {
+ if (user == null || !user.isAdmin()) {
+ ui.putStringLn("You must login as an administrator first.");
+
+ try {
+ execLogin();
+ } catch (InputRequiredException ex) {
+ }
+
+ if (user == null || !user.isAdmin()) {
+ throw new AdminRequiredException();
+ }
+ }
+ }
+
+ /**
+ * Command: add an article
+ * @throws DuplicateEntryException
+ * @throws InputRequiredException
+ * @throws com.camilstaps.shop.Shell.LoginRequiredException
+ * @throws ItemNotFoundException
+ */
+ public void execAddArticle() throws DuplicateEntryException, InputRequiredException, LoginRequiredException, ItemNotFoundException {
+ requireLogin();
+
+ String name = ui.getRequiredString("Name: ");
+ Category category = ui.getCategory();
+ float price = ui.getFloat("Price: ");
+
+ Article a = new Article(user, name, category, price);
+ database.addItem(a);
+ }
+
+ /**
+ * Command: set the article description
+ * @throws com.camilstaps.shop.Shell.LoginRequiredException
+ * @throws ItemNotFoundException
+ * @throws InputRequiredException
+ */
+ public void execSetArticleDescription() throws LoginRequiredException, ItemNotFoundException, InputRequiredException {
+ requireLogin();
+
+ Article a;
+ if (user.isAdmin()) {
+ a = ui.getArticle();
+ } else {
+ a = ui.getArticle(user);
+ }
+
+ a.setDescription(ui.getRequiredString("Description: "));
+ }
+
+ /**
+ * Command: set the multimedia linked to an article
+ * @throws com.camilstaps.shop.Shell.LoginRequiredException
+ * @throws ItemNotFoundException
+ * @throws InputRequiredException
+ */
+ public void execSetArticleMultimedia() throws LoginRequiredException, ItemNotFoundException, InputRequiredException {
+ requireLogin();
+
+ Article a;
+ if (user.isAdmin()) {
+ a = ui.getArticle();
+ } else {
+ a = ui.getArticle(user);
+ }
+
+ a.setMultimedia(new File(ui.getRequiredString("Multimedia: ")));
+ }
+
+ /**
+ * Command: remove an article
+ * @throws com.camilstaps.shop.Shell.LoginRequiredException
+ * @throws ItemNotFoundException
+ * @throws InputRequiredException
+ */
+ public void execRemoveArticle() throws LoginRequiredException, ItemNotFoundException, InputRequiredException {
+ requireLogin();
+
+ Article a;
+ if (user.isAdmin()) {
+ a = ui.getArticle();
+ } else {
+ a = ui.getArticle(user);
+ }
+
+ database.removeItem(a);
+ }
+
+ /**
+ * Command: show a list of articles
+ */
+ public void execListArticles() {
+ for (Article a : database.getArticles()) {
+ ui.putStringLn(a.toString());
+ }
+ }
+
+ /**
+ * Command: search for an article
+ */
+ public void execSearchArticle() {
+ String regex = ui.getString("Keywords: ");
+ for (Article a : database.searchArticle(Pattern.compile(regex))) {
+ ui.putStringLn(a.toString());
+ }
+ }
+
+ /**
+ * Command: show detailed data about an article
+ * @throws InputRequiredException
+ * @throws ItemNotFoundException
+ */
+ public void execShowArticle() throws InputRequiredException, ItemNotFoundException {
+ Article a = ui.getArticle();
+ ui.putStringLn(a.toString());
+ if (a.getDescription() != null) {
+ ui.putStringLn(a.getDescription());
+ }
+ File multimedia = a.getMultimedia();
+ if (multimedia != null) {
+ ui.putStringLn("Multimedia: " + multimedia.getPath());
+ }
+ if (user != null && user.isAdmin()) {
+ ui.putStringLn("User: " + a.getUser().toString(true));
+ }
+ }
+
+ /**
+ * Command: add a category
+ * @throws DuplicateEntryException
+ * @throws InputRequiredException
+ * @throws com.camilstaps.shop.Shell.AdminRequiredException
+ * @throws ItemNotFoundException
+ */
+ public void execAddCategory() throws DuplicateEntryException, InputRequiredException, AdminRequiredException, ItemNotFoundException {
+ requireAdmin();
+
+ String name = ui.getRequiredString("Name: ");
+ database.addItem(new Category(name));
+ }
+
+ /**
+ * Command: list categories
+ */
+ public void execListCategories() {
+ for (String c : database.getCategoryNames()) {
+ ui.putStringLn(c);
+ }
+ }
+
+ /**
+ * Command: list users
+ * Administrators see a more detailed list
+ */
+ public void execListUsers() {
+ for (User u : database.getUsers()) {
+ ui.putStringLn(u.toString(user != null && user.isAdmin()));
+ }
+ }
+
+ /**
+ * Command: register a new user
+ * @throws DuplicateEntryException
+ * @throws InputRequiredException
+ */
+ public void execRegister() throws DuplicateEntryException, InputRequiredException {
+ boolean addAsAdmin = false;
+
+ if (database.getUsers().isEmpty()) {
+ addAsAdmin = true;
+ ui.putStringLn("This is the first user and will therefore be added as administrator.");
+ } else if (user != null && user.isAdmin()) {
+ addAsAdmin = ui.getBoolean("Add user as administrator");
+ }
+
+ String nr = ui.getRequiredString("Number: ");
+ String email = ui.getRequiredString("Email: ");
+
+ User u = new User(nr, email, addAsAdmin);
+
+ String password = u.setRandomPassword();
+ ui.putStringLn("Password: " + password);
+
+ database.addItem(u);
+ }
+
+ /**
+ * Command: login
+ * @throws InputRequiredException
+ * @throws ItemNotFoundException
+ */
+ public void execLogin() throws InputRequiredException, ItemNotFoundException {
+ if (user != null) {
+ ui.putStringLn("You are already logged in.");
+ return;
+ }
+
+ User u = ui.getUser();
+ String pw = ui.getRequiredString("Password: ");
+
+ if (!u.verify(pw)) {
+ ui.putStringLn("Failed to login.");
+ return;
+ }
+
+ if (u.isBlocked()) {
+ ui.putStringLn("You are blocked.");
+ return;
+ }
+
+ user = u;
+ }
+
+ /**
+ * Command: logout
+ */
+ public void execLogout() {
+ user = null;
+ }
+
+ /**
+ * Command: add an article to the cart
+ * @throws com.camilstaps.shop.Shell.LoginRequiredException
+ * @throws ItemNotFoundException
+ * @throws InputRequiredException
+ */
+ public void execAddToCart() throws LoginRequiredException, ItemNotFoundException, InputRequiredException {
+ requireLogin();
+
+ user.getCart().add(ui.getArticle());
+ }
+
+ /**
+ * Command: remove an article from the cart
+ * @throws com.camilstaps.shop.Shell.LoginRequiredException
+ * @throws ItemNotFoundException
+ */
+ public void execRemoveFromCart() throws LoginRequiredException, ItemNotFoundException {
+ requireLogin();
+
+ user.getCart().remove(ui.getArticle(user.getCart().getArticles()));
+ }
+
+ /**
+ * Command: list articles in the cart
+ * @throws com.camilstaps.shop.Shell.LoginRequiredException
+ * @throws ItemNotFoundException
+ */
+ public void execListCart() throws LoginRequiredException, ItemNotFoundException {
+ requireLogin();
+
+ for (Article a : user.getCart().getArticles()) {
+ ui.putStringLn(a.toString());
+ }
+
+ ui.putStringLn("Total value: " + user.getCart().getTotalAmount());
+ }
+
+ /**
+ * Command: remove all articles from the cart
+ * @throws com.camilstaps.shop.Shell.LoginRequiredException
+ * @throws ItemNotFoundException
+ */
+ public void execClearCart() throws LoginRequiredException, ItemNotFoundException {
+ requireLogin();
+
+ if (ui.getBoolean("Are you sure?")) user.getCart().reset();
+ }
+
+ /**
+ * Command: checkout (create an Order using the current Cart)
+ * @throws ItemNotFoundException
+ * @throws com.camilstaps.shop.Shell.LoginRequiredException
+ * @throws DuplicateEntryException
+ */
+ public void execCheckout() throws ItemNotFoundException, LoginRequiredException, DuplicateEntryException {
+ requireLogin();
+
+ if (user.getCart().getArticles().isEmpty()) {
+ throw new ItemNotFoundException();
+ }
+
+ ui.putStringLn("By checking out, you agree to pay the total amount.");
+ if (!ui.getBoolean("Do you agree?"))
+ return;
+
+ Order order = new Order(user);
+ database.addItem(order);
+
+ ui.putStringLn("Your order has been added as " + order.toString());
+ }
+
+ /**
+ * Command: list orders
+ * @throws ItemNotFoundException
+ * @throws com.camilstaps.shop.Shell.LoginRequiredException
+ */
+ public void execListOrders() throws ItemNotFoundException, LoginRequiredException {
+ requireLogin();
+
+ Set<Order> orders;
+ if (user.isAdmin()) {
+ orders = database.getOrders();
+ } else {
+ orders = user.getOrders();
+ }
+ for (Order o : orders) {
+ ui.putStringLn(o.toString());
+ }
+ }
+
+ /**
+ * Command: show detailed information about an order
+ * @throws com.camilstaps.shop.Shell.LoginRequiredException
+ * @throws ItemNotFoundException
+ * @throws InputRequiredException
+ */
+ public void execShowOrder() throws LoginRequiredException, ItemNotFoundException, InputRequiredException {
+ requireLogin();
+
+ Order o;
+ if (user.isAdmin()) {
+ o = ui.getOrder();
+ } else {
+ o = ui.getOrder(user);
+ }
+ ui.putStringLn(o.toString());
+ for (Article a : o.getArticles()) {
+ ui.putStringLn(" " + a.toString());
+ }
+ ui.putStringLn("Total amount: " + o.getTotalAmount());
+ ui.putStringLn("Paid: " + (o.isPaid() ? "yes" : "no"));
+ }
+
+ /**
+ * Command: set the paid status of an Order to true
+ * @throws com.camilstaps.shop.Shell.AdminRequiredException
+ * @throws ItemNotFoundException
+ * @throws InputRequiredException
+ */
+ public void execSetOrderPaid() throws AdminRequiredException, ItemNotFoundException, InputRequiredException {
+ requireAdmin();
+ ui.getOrder().setPaid(true);
+ }
+
+ /**
+ * Command: block a user
+ * @throws InputRequiredException
+ * @throws ItemNotFoundException
+ * @throws com.camilstaps.shop.Shell.AdminRequiredException
+ */
+ public void execBlockUser() throws InputRequiredException, ItemNotFoundException, AdminRequiredException {
+ requireAdmin();
+ ui.getUser().setBlocked(true);
+ }
+
+ /**
+ * Command: unblock a user
+ * @throws InputRequiredException
+ * @throws ItemNotFoundException
+ * @throws com.camilstaps.shop.Shell.AdminRequiredException
+ */
+ public void execUnblockUser() throws InputRequiredException, ItemNotFoundException, AdminRequiredException {
+ requireAdmin();
+ ui.getUser().setBlocked(false);
+ }
+
+ /**
+ * Command: save the database
+ */
+ public void execExit() {
+ database.write();
+ }
+
+ /**
+ * This Exception is thrown when the visitor is required to login, but fails
+ */
+ private class LoginRequiredException extends Exception {
+ }
+
+ /**
+ * This Exception is thrown when the visitor is required to login as an administrator, but fails
+ */
+ private class AdminRequiredException extends Exception {
+ }
+
+}
diff --git a/Week9/src/com/camilstaps/shop/Shop.java b/Week9/src/com/camilstaps/shop/Shop.java
new file mode 100644
index 0000000..cab828a
--- /dev/null
+++ b/Week9/src/com/camilstaps/shop/Shop.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2015 Camil Staps <info@camilstaps.nl>
+ * See the LICENSE file for copying permission.
+ */
+
+package com.camilstaps.shop;
+
+/**
+ * The webshop
+ * @author Camil Staps, s4498062
+ */
+public class Shop {
+
+ /**
+ * Create a shell and run
+ * @param args
+ */
+ public static void main(String[] args) {
+ Shell sh = new Shell(new CLIInteraction());
+ sh.run();
+ }
+
+}
diff --git a/Week9/src/com/camilstaps/shop/User.java b/Week9/src/com/camilstaps/shop/User.java
new file mode 100644
index 0000000..5696a60
--- /dev/null
+++ b/Week9/src/com/camilstaps/shop/User.java
@@ -0,0 +1,143 @@
+/**
+ * Copyright (c) 2015 Camil Staps <info@camilstaps.nl>
+ * See the LICENSE file for copying permission.
+ */
+
+package com.camilstaps.shop;
+
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
+
+/**
+ * A User is a person with a U/S-number, email and password.
+ * He may be blocked / be an admin, and has a Cart.
+ * @author Camil Staps, s4498062
+ */
+public class User extends DatabaseItem {
+
+ private final String nr;
+ private final String email;
+ private String hash;
+ private final boolean isAdmin;
+ private final Cart cart = new Cart();
+ private boolean isBlocked = false;
+
+ public User (String nr, String email) {
+ this.nr = nr;
+ this.email = email;
+ this.isAdmin = false;
+ }
+
+ public User (String nr, String email, boolean isAdmin) {
+ this.nr = nr;
+ this.email = email;
+ this.isAdmin = isAdmin;
+ }
+
+ public String getNr() {
+ return nr;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public boolean isAdmin() {
+ return isAdmin;
+ }
+
+ public Cart getCart() {
+ return cart;
+ }
+
+ public Set<Article> getArticles() {
+ Set<Article> articles = Database.getInstance().getArticles();
+ Set<Article> result = new HashSet<>();
+ for (Article a : articles) {
+ if (a.getUser().getNr().equals(nr)) {
+ result.add(a);
+ }
+ }
+ return result;
+ }
+
+ public Set<Order> getOrders() {
+ Set<Order> orders = Database.getInstance().getOrders();
+ Set<Order> result = new HashSet<>();
+ for (Order o : orders) {
+ if (o.getUser().getNr().equals(nr)) {
+ result.add(o);
+ }
+ }
+ return result;
+ }
+
+ public void setBlocked(boolean set) {
+ isBlocked = set;
+ }
+
+ public boolean isBlocked() {
+ return isBlocked;
+ }
+
+ /**
+ * Set a random new password for the user
+ * @return the new password
+ */
+ public String setRandomPassword() {
+ String pw = generatePassword();
+ hash = hash(pw);
+ return pw;
+ }
+
+ /**
+ * Hash a password. Currently, this is just the identity function.
+ * @param password
+ * @return
+ */
+ public static String hash(String password) {
+ return password;
+ }
+
+ /**
+ * Generate a random password
+ * @return
+ */
+ private static String generatePassword() {
+ // Only characters that cannot easily be confused
+ final String drawFrom = "123456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
+ final Random r = new Random();
+
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 12; i++) {
+ sb.append(drawFrom.charAt(r.nextInt(drawFrom.length())));
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Verify if a password matches the user's password
+ * @param password the password to check
+ * @return
+ */
+ public boolean verify(String password) {
+ return hash(password).equals(hash);
+ }
+
+ @Override
+ public String toString() {
+ return (isAdmin ? "++ " : "") + nr + " (" + email + ")" + (isBlocked ? " -!-" : "");
+ }
+
+ /**
+ * This User as a String, with a detailed and a quick view
+ * @param showSensitive whether to show sensitive data (email, isAdmin, isBlocked) or not
+ * @return
+ */
+ public String toString(boolean showSensitive) {
+ return showSensitive ? toString() : nr;
+ }
+
+} \ No newline at end of file
diff --git a/Week9/src/com/camilstaps/shop/UserInteraction.java b/Week9/src/com/camilstaps/shop/UserInteraction.java
new file mode 100644
index 0000000..a857f85
--- /dev/null
+++ b/Week9/src/com/camilstaps/shop/UserInteraction.java
@@ -0,0 +1,198 @@
+/**
+ * Copyright (c) 2015 Camil Staps <info@camilstaps.nl>
+ * See the LICENSE file for copying permission.
+ */
+
+package com.camilstaps.shop;
+
+import java.util.Set;
+
+/**
+ * Interact with the user: provide and request information.
+ * @author Camil Staps, s4498062
+ */
+public abstract class UserInteraction {
+
+ /**
+ * Show a String
+ * @param string
+ */
+ abstract void putString(String string);
+
+ /**
+ * Show a String with a linefeed
+ * @param string
+ */
+ void putStringLn(String string) {
+ putString(string + System.lineSeparator());
+ }
+
+ /**
+ * Get a String as input
+ * @return
+ */
+ abstract String getString();
+
+ /**
+ * Get a String as input, after outputting a question
+ * @param question
+ * @return
+ */
+ String getString(String question) {
+ putString(question);
+ return getString();
+ }
+
+ /**
+ * Get a String as input, and throw an Exception when it's empty
+ * @return
+ * @throws InputRequiredException
+ */
+ String getRequiredString() throws InputRequiredException {
+ String result = getString();
+ if (result.isEmpty()) throw new InputRequiredException();
+ return result;
+ }
+
+ /**
+ * Get a String as input, after outputting a question, and throw an
+ * Exception when the input is empty
+ * @param question
+ * @return
+ * @throws InputRequiredException
+ */
+ String getRequiredString(String question) throws InputRequiredException {
+ putString(question);
+ return getRequiredString();
+ }
+
+ /**
+ * Get a float as input
+ * @return
+ */
+ abstract float getFloat();
+
+ /**
+ * Get a float as input, after outputting a question
+ * @param question
+ * @return
+ */
+ float getFloat(String question) {
+ putString(question);
+ return getFloat();
+ }
+
+ /**
+ * Get a boolean as input
+ * @return
+ */
+ abstract boolean getBoolean();
+
+ /**
+ * Get a boolean as input, after outputting a question
+ * @param question
+ * @return
+ */
+ boolean getBoolean(String question) {
+ putString(question);
+ return getBoolean();
+ }
+
+ /**
+ * Get a Command as input
+ * @return
+ */
+ abstract Command getCommand();
+
+ /**
+ * Let the user choose from an array of options, after outputting a question
+ * @param question
+ * @param options
+ * @return the index of the choice in the options array
+ */
+ abstract int getChoice(String question, String[] options);
+
+ /**
+ * Let the user choose from a Set of Articles
+ * @param set
+ * @return
+ */
+ Article getArticle(Set<Article> set) {
+ String[] articleNames = new String[set.size()];
+ Article[] articles = new Article[set.size()];
+ int i = 0;
+ for (Article a : set) {
+ articleNames[i] = a.toString();
+ articles[i++] = a;
+ }
+ return articles[getChoice("Article: ", articleNames)];
+ }
+
+ /**
+ * Let the user choose an Article
+ * @return
+ * @throws InputRequiredException
+ * @throws ItemNotFoundException
+ */
+ Article getArticle() throws InputRequiredException, ItemNotFoundException {
+ String name = getRequiredString("Name article: ");
+ return Database.getInstance().getArticle(name);
+ }
+
+ /**
+ * Let the user choose an Article from the Articles of a specific User
+ * @param user
+ * @return
+ */
+ Article getArticle(User user) {
+ return getArticle(user.getArticles());
+ }
+
+ /**
+ * Let the user choose a category
+ * @return
+ * @throws ItemNotFoundException
+ */
+ Category getCategory() throws ItemNotFoundException {
+ String[] categories = Database.getInstance().getCategoryNames();
+ return Database.getInstance().getCategory(categories[getChoice("Category: ", categories)]);
+ }
+
+ /**
+ * Let the user choose a User
+ * @return
+ * @throws InputRequiredException
+ * @throws ItemNotFoundException
+ */
+ User getUser() throws InputRequiredException, ItemNotFoundException {
+ return Database.getInstance().getUser(getRequiredString("Number user: "));
+ }
+
+ /**
+ * Let the user choose an order
+ * @return
+ * @throws InputRequiredException
+ * @throws ItemNotFoundException
+ */
+ Order getOrder() throws InputRequiredException, ItemNotFoundException {
+ return getOrder(getUser());
+ }
+
+ /**
+ * Let the user choose an order, from the orders of a specific User
+ * @param user
+ * @return
+ */
+ Order getOrder(User user) {
+ Set<Order> orders = user.getOrders();
+ String[] orderStrings = new String[orders.size()];
+ Order[] orderObjects = new Order[orders.size()];
+ int i = 0;
+ for (Order o : orders) {
+ orderStrings[i] = o.toString();
+ orderObjects[i++] = o;
+ }
+ return orderObjects[getChoice("Order: ", orderStrings)];
+ }
+
+} \ No newline at end of file
diff --git a/Week9/uml-project.vpp b/Week9/uml-project.vpp
new file mode 100644
index 0000000..fdd56f8
--- /dev/null
+++ b/Week9/uml-project.vpp
Binary files differ