diff --git a/assignments/nbproject/build-impl.xml b/assignments/nbproject/build-impl.xml index 3c98afaf0ea47432cdcd857b5feb02516d3f6f46..2e432ca6b7ea3928e1ee16efef1aa3911f8b3150 100644 --- a/assignments/nbproject/build-impl.xml +++ b/assignments/nbproject/build-impl.xml @@ -119,43 +119,7 @@ is divided into following sections: <property name="module.name" value=""/> </target> <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property,-init-modules-supported" name="-do-init"> - <j2seproject1:property name="platform.home" value="platforms.${platform.active}.home"/> - <j2seproject1:property name="platform.bootcp" value="platforms.${platform.active}.bootclasspath"/> - <j2seproject1:property name="platform.compiler" value="platforms.${platform.active}.compile"/> - <j2seproject1:property name="platform.javac.tmp" value="platforms.${platform.active}.javac"/> - <condition property="platform.javac" value="${platform.home}/bin/javac"> - <equals arg1="${platform.javac.tmp}" arg2="$${platforms.${platform.active}.javac}"/> - </condition> - <property name="platform.javac" value="${platform.javac.tmp}"/> - <j2seproject1:property name="platform.java.tmp" value="platforms.${platform.active}.java"/> - <condition property="platform.java" value="${platform.home}/bin/java"> - <equals arg1="${platform.java.tmp}" arg2="$${platforms.${platform.active}.java}"/> - </condition> - <property name="platform.java" value="${platform.java.tmp}"/> - <j2seproject1:property name="platform.javadoc.tmp" value="platforms.${platform.active}.javadoc"/> - <condition property="platform.javadoc" value="${platform.home}/bin/javadoc"> - <equals arg1="${platform.javadoc.tmp}" arg2="$${platforms.${platform.active}.javadoc}"/> - </condition> - <property name="platform.javadoc" value="${platform.javadoc.tmp}"/> - <condition property="platform.invalid" value="true"> - <or> - <contains string="${platform.javac}" substring="$${platforms."/> - <contains string="${platform.java}" substring="$${platforms."/> - <contains string="${platform.javadoc}" substring="$${platforms."/> - </or> - </condition> - <fail unless="platform.home">Must set platform.home</fail> - <fail unless="platform.bootcp">Must set platform.bootcp</fail> - <fail unless="platform.java">Must set platform.java</fail> - <fail unless="platform.javac">Must set platform.javac</fail> - <fail if="platform.invalid"> - The J2SE Platform is not correctly set up. - Your active platform is: ${platform.active}, but the corresponding property "platforms.${platform.active}.home" is not found in the project's properties files. - Either open the project in the IDE and setup the Platform with the same name or add it manually. - For example like this: - ant -Duser.properties.file=<path_to_property_file> jar (where you put the property "platforms.${platform.active}.home" in a .properties file) - or ant -Dplatforms.${platform.active}.home=<path_to_JDK_home> jar (where no properties file is used) - </fail> + <property name="platform.java" value="${java.home}/bin/java"/> <available file="${manifest.file}" property="manifest.available"/> <condition property="splashscreen.available"> <and> @@ -278,6 +242,20 @@ is divided into following sections: <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> + <condition else="false" property="javac.fork"> + <or> + <istrue value="${jdkBug6558476}"/> + <istrue value="${javac.external.vm}"/> + </or> + </condition> <property name="jar.index" value="false"/> <property name="jar.index.metainf" value="${jar.index}"/> <property name="copylibs.rebase" value="true"/> @@ -365,7 +343,7 @@ is divided into following sections: </path> </resourcecount> </condition> - <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" executable="${platform.javac}" fork="yes" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}"> + <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="*"/> @@ -416,7 +394,7 @@ is divided into following sections: <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}" executable="${platform.javac}" fork="yes" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}"> + <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="*"/> @@ -458,7 +436,7 @@ is divided into following sections: <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}" executable="${platform.javac}" fork="yes" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}"> + <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="*"/> @@ -537,7 +515,7 @@ is divided into following sections: <element name="customizePrototype" optional="true"/> <sequential> <property name="junit.forkmode" value="perTest"/> - <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" jvm="${platform.java}" showoutput="true" tempdir="${build.dir}"> + <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}"> <syspropertyset> <propertyref prefix="test-sys-prop."/> <mapper from="test-sys-prop.*" to="*" type="glob"/> @@ -565,7 +543,7 @@ is divided into following sections: <element name="customizePrototype" optional="true"/> <sequential> <property name="junit.forkmode" value="perTest"/> - <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" jvm="${platform.java}" showoutput="true" tempdir="${build.dir}"> + <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}"> <syspropertyset> <propertyref prefix="test-sys-prop."/> <mapper from="test-sys-prop.*" to="*" type="glob"/> @@ -641,7 +619,7 @@ is divided into following sections: </fileset> </union> <taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/> - <testng classfilesetref="test.set" failureProperty="tests.failed" jvm="${platform.java}" listeners="org.testng.reporters.VerboseReporter" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="Networked_Graphics_MV3500_assignments" testname="TestNG tests" workingDir="${work.dir}"> + <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="Networked_Graphics_MV3500_assignments" testname="TestNG tests" workingDir="${work.dir}"> <xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/> <propertyset> <propertyref prefix="test-sys-prop."/> @@ -872,9 +850,6 @@ is divided into following sections: <classpath> <path path="@{classpath}"/> </classpath> - <bootclasspath> - <path path="${platform.bootcp}"/> - </bootclasspath> </nbjpdastart> </sequential> </macrodef> @@ -924,7 +899,7 @@ is divided into following sections: <attribute default="jvm" name="jvm"/> <element name="customize" optional="true"/> <sequential> - <java classname="@{classname}" dir="${work.dir}" failonerror="${java.failonerror}" fork="true" jvm="${platform.java}" module="@{modulename}"> + <java classname="@{classname}" dir="${work.dir}" failonerror="${java.failonerror}" fork="true" module="@{modulename}"> <classpath> <path path="@{classpath}"/> </classpath> @@ -958,7 +933,7 @@ is divided into following sections: <attribute default="jvm" name="jvm"/> <element name="customize" optional="true"/> <sequential> - <java classname="@{classname}" dir="${work.dir}" failonerror="${java.failonerror}" fork="true" jvm="${platform.java}"> + <java classname="@{classname}" dir="${work.dir}" failonerror="${java.failonerror}" fork="true"> <classpath> <path path="@{classpath}"/> </classpath> @@ -990,7 +965,7 @@ is divided into following sections: <attribute default="jvm" name="jvm"/> <element name="customize" optional="true"/> <sequential> - <java classname="@{classname}" dir="${work.dir}" failonerror="${java.failonerror}" fork="true" jvm="${platform.java}"> + <java classname="@{classname}" dir="${work.dir}" failonerror="${java.failonerror}" 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}"/> @@ -1224,7 +1199,7 @@ is divided into following sections: <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">${platform.java} -jar "${dist.jar.resolved}"</echo> + <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,-check-do-mkdist" if="do.archive" name="-do-jar-jar" unless="do.mkdist"> <j2seproject1:jar manifest="${tmp.manifest.file}"/> @@ -1326,8 +1301,8 @@ is divided into following sections: <isset property="main.class.available"/> </and> </condition> - <property name="platform.jlink" value="${platform.home}/bin/jlink"/> - <property name="jlink.systemmodules.internal" value="${platform.home}/jmods"/> + <property name="platform.jlink" value="${jdk.home}/bin/jlink"/> + <property name="jlink.systemmodules.internal" value="${jdk.home}/jmods"/> <exec executable="${platform.jlink}"> <arg value="--module-path"/> <arg path="${jlink.systemmodules.internal}:${run.modulepath}:${dist.jar}"/> @@ -1520,19 +1495,16 @@ is divided into following sections: </not> </and> </condition> - <exec executable="${platform.java}" failonerror="false" outputproperty="platform.version.output"> - <arg value="-version"/> - </exec> <condition else="" property="bug5101868workaround" value="*.java"> - <matches multiline="true" pattern="1\.[56](\..*)?" string="${platform.version.output}"/> + <matches pattern="1\.[56](\..*)?" string="${java.version}"/> </condition> <condition else="" property="javadoc.html5.cmd.line.arg" value="-html5"> <and> <isset property="javadoc.html5"/> - <available file="${platform.home}${file.separator}lib${file.separator}jrt-fs.jar"/> + <available file="${jdk.home}${file.separator}lib${file.separator}jrt-fs.jar"/> </and> </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}" executable="${platform.javadoc}" 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}"> + <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> diff --git a/assignments/nbproject/genfiles.properties b/assignments/nbproject/genfiles.properties index 12bdff2716eac05cf19dd6cff1860cae176c38f5..37ef1b25a6e621d253a6cbee2d69d24e9263d2ae 100644 --- a/assignments/nbproject/genfiles.properties +++ b/assignments/nbproject/genfiles.properties @@ -1,5 +1,5 @@ # 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=45f9e03b -nbproject/build-impl.xml.script.CRC32=e94792c1 +nbproject/build-impl.xml.data.CRC32=5eaf4250 +nbproject/build-impl.xml.script.CRC32=bd12e823 nbproject/build-impl.xml.stylesheet.CRC32=f89f7d21@1.95.0.48 diff --git a/assignments/nbproject/project.properties b/assignments/nbproject/project.properties index 3c1afa9b2e632b28bc845f30724722589b52d0fd..f9870e967a12c0c550b9d1b8cfab8bc4d8b7df5a 100644 --- a/assignments/nbproject/project.properties +++ b/assignments/nbproject/project.properties @@ -40,14 +40,14 @@ file.reference.dis-enums-1.3.jar=../lib/dis-enums-1.3.jar file.reference.guava-28.0-jre.jar=../lib/guava-28.0-jre.jar file.reference.open-dis7-entities-all.jar=../lib/open-dis7-entities-all.jar file.reference.open-dis7-java.jar=../lib/open-dis7-java.jar -file.reference.open-dis7-javadoc.jar=../lib/open-dis7-javadoc.jar file.reference.open-dis_4.16.jar=../lib/open-dis_4.16.jar includes=** +jar.archive.disabled=${jnlp.enabled} jar.compress=false +jar.index=${jnlp.enabled} javac.classpath=\ - ${file.reference.open-dis7-java.jar}:\ ${file.reference.open-dis7-entities-all.jar}:\ - ${file.reference.open-dis7-javadoc.jar}:\ + ${file.reference.open-dis7-java.jar}:\ ${file.reference.commons-io-2.6.jar}:\ ${file.reference.guava-28.0-jre.jar}:\ ${file.reference.open-dis_4.16.jar}:\ @@ -77,16 +77,34 @@ javadoc.noindex=false javadoc.nonavbar=false javadoc.notree=false javadoc.private=false +javadoc.reference.open-dis7-java.jar=../lib/open-dis7-javadoc.jar javadoc.splitindex=true javadoc.use=true javadoc.version=false javadoc.windowtitle= jlink.launcher=false jlink.launcher.name=Networked_Graphics_MV3500_assignments -main.class=MV3500Cohort2019JulySeptember.homework2.Yurkovich.Yurkovich_Server +jnlp.codebase.type=no.codebase +jnlp.descriptor=application +jnlp.enabled=false +jnlp.mixed.code=default +jnlp.offline-allowed=false +jnlp.signed=false +jnlp.signing= +jnlp.signing.alias= +jnlp.signing.keystore= +main.class=MV3500Cohort2020JulySeptember.homework1.WeissenbergerTcpExample1Telnet +# Optional override of default Application-Library-Allowable-Codebase attribute identifying the locations where your signed RIA is expected to be found. +manifest.custom.application.library.allowable.codebase= +# Optional override of default Caller-Allowable-Codebase attribute identifying the domains from which JavaScript code can make calls to your RIA without security prompts. +manifest.custom.caller.allowable.codebase= +# Optional override of default Codebase manifest attribute, use to prevent RIAs from being repurposed +manifest.custom.codebase= +# Optional override of default Permissions manifest attribute (supported values: sandbox, all-permissions) +manifest.custom.permissions= meta.inf.dir=${src.dir}/META-INF -mkdist.disabled=true -platform.active=JDK_1.8 +mkdist.disabled=false +platform.active=default_platform project.licensePath=../license.txt run.classpath=\ ${javac.classpath}:\ @@ -103,5 +121,6 @@ run.test.classpath=\ run.test.modulepath=\ ${javac.test.modulepath} source.encoding=UTF-8 +source.reference.open-dis7-java.jar=../lib/open-dis7-source.jar src.dir=src test.src.dir=test diff --git a/assignments/nbproject/project.xml b/assignments/nbproject/project.xml index 445e0de38b4090b3e636e336405b59737631250d..50cb4b5e05ed23e35a86d22bbf893f7a217b875b 100644 --- a/assignments/nbproject/project.xml +++ b/assignments/nbproject/project.xml @@ -4,7 +4,6 @@ <configuration> <data xmlns="http://www.netbeans.org/ns/j2se-project/3"> <name>Networked Graphics MV3500 assignments</name> - <explicit-platform explicit-source-supported="true"/> <source-roots> <root id="src.dir"/> </source-roots> diff --git a/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/Doku.pdf b/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/Doku.pdf new file mode 100644 index 0000000000000000000000000000000000000000..191a0c453cae997e6a39f7cc48997ada7d31ede1 Binary files /dev/null and b/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/Doku.pdf differ diff --git a/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/HW2.jpg b/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/HW2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2babdaed93845fd29dbe1e82b7c6f27d9cfe4ee3 Binary files /dev/null and b/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/HW2.jpg differ diff --git a/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/LokiChatClient.java b/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/LokiChatClient.java new file mode 100644 index 0000000000000000000000000000000000000000..4c133b53fb47cbaf0686254824b86f5534f2192e --- /dev/null +++ b/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/LokiChatClient.java @@ -0,0 +1,107 @@ +package MV3500Cohort2020JulySeptember.homework2.Weissenberger; + +import java.io.*; +import java.net.*; + +/** + * This client program establishes a socket connection to the chat server, hand + * over the connection to a thread. + * + * @author Bernd "Loki" Weissenberger + */ +public class LokiChatClient implements Runnable { + + private Socket socket = null; + private Thread thread = null; + private DataInputStream console = null; + private DataOutputStream streamOut = null; + private LokiClientThread client = null; + + /** + * constructor. + * @param serverName as named (localhost per default) + * @param serverPort as named (should be 2317) + */ + public LokiChatClient(String serverName, int serverPort) { + System.out.println("***********************************************"); + System.out.println("* Establishing connection. Please wait ... :) *"); + System.out.println("***********************************************"); + + try { + socket = new Socket(serverName, serverPort); + System.out.println("I'm connected: " + socket); + start(); + } catch (UnknownHostException uhe) { + System.out.println("Host unknown: " + uhe.getMessage()); + } catch (IOException ioe) { + System.out.println("Unexpected exception (server isn't up??): " + ioe.getMessage()); + } + } + + public void run() { + while (thread != null) { + try { + streamOut.writeUTF(console.readLine()); + streamOut.flush(); + } catch (IOException ioe) { + System.out.println("Sending error: " + ioe.getMessage()); + stop(); + } + } + } + + public void handle(String msg) { + if (msg.equals(".bye")) { + System.out.println("Good bye. Press RETURN to exit ..."); + stop(); + } else { + System.out.println(msg); + } + } + + /** + * setup the streams and (if possible) the Thread + * @throws IOException + */ + public void start() throws IOException { + console = new DataInputStream(System.in); + streamOut = new DataOutputStream(socket.getOutputStream()); + if (thread == null) { + client = new LokiClientThread(this, socket); + thread = new Thread(this); + thread.start(); + } + } + + /** + * stops the Thread + */ + public void stop() { + if (thread != null) { //thread.stop(); + thread = null; + } + try { + if (console != null) { + console.close(); + } + if (streamOut != null) { + streamOut.close(); + } + if (socket != null) { + socket.close(); + } + } catch (IOException ioe) { + System.out.println("Error closing ..."); + } + client.close(); + } + + /** + * main method with fix IP and Port + * @param args + */ + public static void main(String args[]) { + LokiChatClient client = null; + client = new LokiChatClient("127.0.0.1", 2317); + } +} diff --git a/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/LokiChatServer.java b/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/LokiChatServer.java new file mode 100644 index 0000000000000000000000000000000000000000..393d40bd9285d5cea5d6873d43e3d339bbf50ec5 --- /dev/null +++ b/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/LokiChatServer.java @@ -0,0 +1,149 @@ +package MV3500Cohort2020JulySeptember.homework2.Weissenberger; + +import java.io.*; +import java.net.*; + +/** + * A server example that creates a new thread to handle multiple + * connections one after another, running in parallel. + * + * @author Bernd Weissenberger + */ +public class LokiChatServer implements Runnable { + + private LokiServerThread clients[] = new LokiServerThread[50]; + private ServerSocket server = null; + private Thread thread = null; + private int clientCount = 0; + + /** + * constructor + * @param port + */ + public LokiChatServer(int port) { + try { + System.out.println("Binding to port " + port + ", please wait ..."); + server = new ServerSocket(port); + System.out.println("Server started: " + server); + start(); + } catch (IOException ioe) { + System.out.println("Can not bind to port " + port + ": " + ioe.getMessage()); + } + } + + /** + * start a new thread + */ + @Override + public void run() { + while (thread != null) { + try { + System.out.println("Waiting for a client ..."); + addThread(server.accept()); + } catch (IOException ioe) { + System.out.println("Server accept error: " + ioe); + stop(); + } + } + } + public void start() { + if (thread == null) { + thread = new Thread(this); + thread.start(); + } + } + + /** + * kill the thread + */ + public void stop() { + if (thread != null) { + //thread.stop(); + thread = null; + } + } + + /** + * get the client by ID + * @param ID + * @return + */ + private int findClient(int ID) { + for (int i = 0; i < clientCount; i++) { + if (clients[i].getID() == ID) { + return i; + } + } + return -1; + } + + /** + * sending message to all clients + * @param ID + * @param input + */ + public synchronized void handle(int ID, String input) { + if (input.equals(".bye")) { + clients[findClient(ID)].send(".bye"); + remove(ID); + } else { + for (int i = 0; i < clientCount; i++) { + clients[i].send(ID + " says: " + input); + } + } + } + + /** + * remove a quit client from list + * @param ID + */ + public synchronized void remove(int ID) { + int pos = findClient(ID); + if (pos >= 0) { + LokiServerThread toTerminate = clients[pos]; + System.out.println("Removing client thread " + ID + " at " + pos); + if (pos < clientCount - 1) { + for (int i = pos + 1; i < clientCount; i++) { + clients[i - 1] = clients[i]; + } + } + clientCount--; + try { + toTerminate.close(); + } catch (IOException ioe) { + System.out.println("Error closing thread: " + ioe); + } + //toTerminate.stop(); + } + } + + /** + * add a thread to list + * @param socket + */ + private void addThread(Socket socket) { + if (clientCount < clients.length) { + System.out.println("Client accepted: " + socket); + clients[clientCount] = new LokiServerThread(this, socket); + try { + clients[clientCount].open(); + clients[clientCount].start(); + clientCount++; + } catch (IOException ioe) { + System.out.println("Error opening thread: " + ioe); + } + } else { + System.out.println("Client refused: maximum " + clients.length + " reached."); + } + } + + /** + * the main for this class. Just starts a new server listening at port 2317 + * @param args + */ + public static void main(String args[]) { + LokiChatServer server = null; + server = new LokiChatServer(2317); + } + +} diff --git a/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/LokiClientThread.java b/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/LokiClientThread.java new file mode 100644 index 0000000000000000000000000000000000000000..7c17ba9e045f2f5f06eb07092fbd24f4584ac414 --- /dev/null +++ b/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/LokiClientThread.java @@ -0,0 +1,67 @@ +package MV3500Cohort2020JulySeptember.homework2.Weissenberger; + +import java.io.*; +import java.net.*; + +/** + * A program that handles all logic associated with one socket connection by + * running in a thread of its own. This is the client portion. + * + * @author Bernd Weisenberger + */ +public class LokiClientThread extends Thread { + + private Socket socket = null; + private LokiChatClient client = null; + private DataInputStream streamIn = null; + + /** + * constructor + * @param client + * @param socket + */ + public LokiClientThread(LokiChatClient client, Socket socket) { + this.client = client; + this.socket = socket; + this.open(); + this.start(); + } + + /** + * initialize the stream + */ + public void open() { + try { + streamIn = new DataInputStream(socket.getInputStream()); + } catch (IOException ioe) { + System.out.println("Error getting input stream: " + ioe); + } + } + + /** + * closes the stream + */ + public void close() { + try { + if (streamIn != null) { + streamIn.close(); + } + } catch (IOException ioe) { + System.out.println("Error closing input stream: " + ioe); + } + } + + /** + * uses the handle() from Client to react (send or quit) + */ + public void run() { + while (true) { + try { + client.handle(streamIn.readUTF()); + } catch (IOException ioe) { + System.out.println("Listening error: " + ioe.getMessage()); + client.stop(); + } + } + } +} diff --git a/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/LokiServerThread.java b/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/LokiServerThread.java new file mode 100644 index 0000000000000000000000000000000000000000..a8dfc011f097413cb779d4dd88927c7801f55da0 --- /dev/null +++ b/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/LokiServerThread.java @@ -0,0 +1,97 @@ +package MV3500Cohort2020JulySeptember.homework2.Weissenberger; + +import java.io.*; +import java.net.*; + +/** + * A program that handles all logic associated with one socket connection + * by running in a thread of its own. This is the server + * portion + * + * @author Bernd Weissenberger + */ +public class LokiServerThread extends Thread { + + // as named + private LokiChatServer server = null; + private Socket socket = null; + private int ID = -1; + private DataInputStream streamIn = null; + private DataOutputStream streamOut = null; + + /** + * constructor + * @param server instance of the server + * @param socket ...and the socket + */ + public LokiServerThread(LokiChatServer server, Socket socket) { + super(); + this.server = server; + this.socket = socket; + this.ID = socket.getPort(); + } + + /** + * send the messages + * @param msg + */ + public void send(String msg) { + try { + streamOut.writeUTF(msg); + streamOut.flush(); + } catch (IOException ioe) { + System.out.println(ID + " ERROR sending: " + ioe.getMessage()); + server.remove(ID); + } + } + + /** + * simple getter + * @return + */ + public int getID() { + return ID; + } + + /** + * read he input using the handler method + */ + @Override + public void run() { + System.out.println("Server Thread " + ID + " running."); + while (true) { + try { + server.handle(ID, streamIn.readUTF()); + } catch (IOException ioe) { + System.out.println(ID + " ERROR reading: " + ioe.getMessage()); + server.remove(ID); + //stop(); + } + } + } + + /** + * open all needed streams + * @throws IOException + */ + public void open() throws IOException { + streamIn = new DataInputStream(new BufferedInputStream(socket.getInputStream())); + streamOut = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())); + } + + /** + * close socket and streams + * @throws IOException + */ + public void close() throws IOException { + if (socket != null) { + socket.close(); + } + if (streamIn != null) { + streamIn.close(); + } + if (streamOut != null) { + streamOut.close(); + } + } +} diff --git a/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/README.md b/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/README.md index 0144d62d033fbe094ceac7a6d1bedc12d3c158b0..301da8445dabd4c8e16e79368993984173252dd2 100644 --- a/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/README.md +++ b/assignments/src/MV3500Cohort2020JulySeptember/homework2/Weissenberger/README.md @@ -10,3 +10,17 @@ References include * [assignments source subdirectories](../../../../../assignments/src) show examples from previous cohorts. Questions and innovation are always welcome, good luck! + + +Coded three classes: +LokiChatServer +LokiServerThread +LokiChatClient +LokiClientThread + +1. Run the LokiChatServer once +2. Run the LokiChatClient twice or more +3. type some messages in a client console +4. you will see the message on each of the client consoles + +Please see HW2.jpg (chart) and doku.pdf \ No newline at end of file