From 3230b722fb2b58d2e7b13500716ed53f8f30363a Mon Sep 17 00:00:00 2001 From: Sandro Leuchter Date: Tue, 18 Mar 2025 07:08:10 +0100 Subject: [PATCH] initial --- 02-udp/justfile | 4 + 02-udp/pom.xml | 14 + 02-udp/udp.code-workspace | 43 +++ 02-udp/udp.echo/justfile | 6 + 02-udp/udp.echo/pom.xml | 13 + .../udp.echo/src/main/java/vs/EchoClient.java | 33 ++ .../udp.echo/src/main/java/vs/EchoServer.java | 31 ++ 02-udp/udp.echo_solution/justfile | 6 + 02-udp/udp.echo_solution/pom.xml | 13 + .../src/main/java/vs/EchoClient.java | 58 ++++ .../src/main/java/vs/EchoServer.java | 50 +++ 02-udp/udp.game_solution/justfile | 6 + 02-udp/udp.game_solution/pom.xml | 13 + .../src/main/java/vs/ReactionGameClient.java | 42 +++ .../src/main/java/vs/ReactionGameServer.java | 63 ++++ 02-udp/udp.messwerte/justfile | 6 + 02-udp/udp.messwerte/pom.xml | 13 + .../src/main/java/vs/MesswertClient.java | 22 ++ .../src/main/java/vs/MesswertServer.java | 8 + 02-udp/udp.messwerte_solution/justfile | 6 + 02-udp/udp.messwerte_solution/pom.xml | 13 + .../src/main/java/vs/MesswertClient.java | 56 ++++ .../src/main/java/vs/MesswertServer.java | 47 +++ 02-udp/udp.time/justfile | 6 + 02-udp/udp.time/pom.xml | 13 + .../udp.time/src/main/java/vs/TimeClient.java | 8 + .../udp.time/src/main/java/vs/TimeServer.java | 8 + 02-udp/udp.time_solution/justfile | 6 + 02-udp/udp.time_solution/pom.xml | 13 + .../src/main/java/vs/TimeClient.java | 57 ++++ .../src/main/java/vs/TimeServer.java | 53 +++ 03-tcp/justfile | 4 + 03-tcp/pom.xml | 14 + 03-tcp/tcp.code-workspace | 39 +++ 03-tcp/tcp.echo/justfile | 11 + 03-tcp/tcp.echo/pom.xml | 13 + .../tcp.echo/src/main/java/vs/EchoClient.java | 37 +++ .../src/main/java/vs/EchoServerIterativ.java | 60 ++++ .../src/main/java/vs/EchoServerThreaded.java | 41 +++ 03-tcp/tcp.echo_solution/justfile | 13 + 03-tcp/tcp.echo_solution/pom.xml | 13 + .../src/main/java/vs/EchoClient.java | 53 +++ .../src/main/java/vs/EchoServerIterativ.java | 98 ++++++ .../main/java/vs/EchoServerThreadPool.java | 115 +++++++ .../src/main/java/vs/EchoServerThreaded.java | 106 ++++++ 03-tcp/tcp.filer/justfile | 10 + 03-tcp/tcp.filer/pom.xml | 13 + .../src/main/java/vs/FileClient.java | 22 ++ .../src/main/java/vs/FileServerIterativ.java | 61 ++++ .../src/main/java/vs/FileServerThreaded.java | 49 +++ .../tcp.filer/src/main/resources/message.txt | 25 ++ 03-tcp/tcp.filer_solution/justfile | 12 + 03-tcp/tcp.filer_solution/pom.xml | 13 + .../src/main/java/vs/FileClient.java | 39 +++ .../src/main/java/vs/FileServerIterativ.java | 109 ++++++ .../main/java/vs/FileServerThreadPool.java | 128 ++++++++ .../src/main/java/vs/FileServerThreaded.java | 118 +++++++ .../src/main/resources/message.txt | 25 ++ 03-tcp/tcp.time/justfile | 10 + 03-tcp/tcp.time/pom.xml | 13 + .../tcp.time/src/main/java/vs/TimeClient.java | 23 ++ .../src/main/java/vs/TimeLongServer.java | 38 +++ .../src/main/java/vs/TimeTextServer.java | 38 +++ 03-tcp/tcp.time_solution/justfile | 10 + 03-tcp/tcp.time_solution/pom.xml | 13 + .../src/main/java/vs/TimeClient.java | 63 ++++ .../src/main/java/vs/TimeLongServer.java | 65 ++++ .../src/main/java/vs/TimeTextServer.java | 65 ++++ 05-jms/jms.chat/justfile | 8 + 05-jms/jms.chat/pom.xml | 14 + .../jms.chat/src/main/java/vs/ChatClient.java | 69 ++++ .../src/main/resources/jndi.properties | 5 + 05-jms/jms.chat_solution/justfile | 15 + 05-jms/jms.chat_solution/pom.xml | 14 + .../src/main/java/vs/ChatClient.java | 111 +++++++ .../main/java/vs/ChatClientUserProperty.java | 113 +++++++ .../src/main/java/vs/Conf.java | 5 + .../src/main/resources/jndi.properties | 5 + 05-jms/jms.client/justfile | 4 + 05-jms/jms.client/pom.xml | 14 + .../src/main/java/vs/JMSClient.java | 84 +++++ .../src/main/resources/jndi.properties | 6 + 05-jms/jms.client_solution/justfile | 4 + 05-jms/jms.client_solution/pom.xml | 14 + .../src/main/java/vs/JMSClient.java | 110 +++++++ .../src/main/resources/jndi.properties | 6 + 05-jms/jms.code-workspace | 55 ++++ 05-jms/jms.echo/justfile | 6 + 05-jms/jms.echo/pom.xml | 14 + 05-jms/jms.echo/src/main/java/vs/Conf.java | 5 + .../src/main/java/vs/EchoReplierNode.java | 74 +++++ .../src/main/java/vs/EchoRequesterNode.java | 85 +++++ .../src/main/resources/jndi.properties | 6 + .../jms.echo/target/classes/jndi.properties | 6 + 05-jms/jms.echo/target/classes/vs/Conf.class | Bin 0 -> 317 bytes .../target/classes/vs/EchoReplierNode.class | Bin 0 -> 3738 bytes .../target/classes/vs/EchoRequesterNode.class | Bin 0 -> 4150 bytes 05-jms/jms.echo_solution/justfile | 6 + 05-jms/jms.echo_solution/pom.xml | 14 + .../src/main/java/vs/Conf.java | 16 + .../src/main/java/vs/EchoReplierNode.java | 100 ++++++ .../src/main/java/vs/EchoRequesterNode.java | 117 +++++++ .../src/main/resources/jndi.properties | 6 + 05-jms/jms.logger/justfile | 12 + 05-jms/jms.logger/pom.xml | 14 + 05-jms/jms.logger/src/main/java/vs/Conf.java | 5 + .../main/java/vs/ConsumerCallbackNode.java | 68 ++++ .../main/java/vs/ConsumerFilteredNode.java | 68 ++++ .../src/main/java/vs/ConsumerPullNode.java | 62 ++++ .../src/main/java/vs/ProducerNode.java | 60 ++++ .../src/main/resources/jndi.properties | 4 + 05-jms/jms.logger_solution/justfile | 12 + 05-jms/jms.logger_solution/pom.xml | 14 + .../src/main/java/vs/Conf.java | 16 + .../main/java/vs/ConsumerCallbackNode.java | 94 ++++++ .../main/java/vs/ConsumerFilteredNode.java | 97 ++++++ .../src/main/java/vs/ConsumerPullNode.java | 92 ++++++ .../src/main/java/vs/ProducerNode.java | 88 +++++ .../src/main/resources/jndi.properties | 4 + 05-jms/jms.revers_solution/justfile | 8 + 05-jms/jms.revers_solution/pom.xml | 14 + .../src/main/java/vs/Anfrager.java | 124 +++++++ .../src/main/java/vs/Conf.java | 16 + .../src/main/java/vs/Umdreher.java | 114 +++++++ .../main/java/vs/UmdreherReuseProducers.java | 127 +++++++ .../src/main/resources/jndi.properties | 6 + 05-jms/jms.tasks_solution/justfile | 6 + 05-jms/jms.tasks_solution/pom.xml | 22 ++ .../src/main/java/vs/Conf.java | 6 + .../java/vs/PasswordCandidateGenerator.java | 90 +++++ .../java/vs/PasswordCandidateValidator.java | 101 ++++++ .../src/main/resources/jndi.properties | 6 + 05-jms/justfile | 4 + 05-jms/pom.xml | 22 ++ 06-mqtt/.gitignore | 1 + 06-mqtt/justfile | 8 + 06-mqtt/mqtt.code-workspace | 27 ++ 06-mqtt/mqtt.logger/justfile | 6 + 06-mqtt/mqtt.logger/pom.xml | 14 + .../mqtt.logger/src/main/java/vs/Conf.java | 7 + .../src/main/java/vs/Publisher.java | 24 ++ .../src/main/java/vs/Subscriber.java | 38 +++ 06-mqtt/mqtt.logger_solution/justfile | 6 + 06-mqtt/mqtt.logger_solution/pom.xml | 14 + .../src/main/java/vs/Conf.java | 16 + .../src/main/java/vs/Publisher.java | 41 +++ .../src/main/java/vs/Subscriber.java | 52 +++ 06-mqtt/mqtt.smarthome_solution/justfile | 20 ++ 06-mqtt/mqtt.smarthome_solution/pom.xml | 14 + .../src/main/java/vs/AlarmSubscriber.java | 76 +++++ .../src/main/java/vs/Conf.java | 22 ++ .../src/main/java/vs/FloorPlotter.java | 141 ++++++++ .../src/main/java/vs/LoggingSubscriber.java | 60 ++++ .../src/main/java/vs/Sensor.java | 77 +++++ .../main/java/vs/SensorSelfDescribung.java | 93 ++++++ 06-mqtt/pom.xml | 21 ++ 07-http/http.webserver/justfile | 6 + 07-http/http.webserver/pom.xml | 13 + .../src/main/java/vs/WebServer.java | 59 ++++ .../src/main/resources/docs/form.html | 14 + .../src/main/resources/docs/img/by-nc-sa1.png | Bin 0 -> 22475 bytes 07-http/http.webserver_solution/justfile | 6 + 07-http/http.webserver_solution/pom.xml | 13 + .../src/main/java/vs/WebServer.java | 123 +++++++ .../src/main/resources/docs/form.html | 13 + .../main/resources/docs/http/WebServer.java | 123 +++++++ .../src/main/resources/docs/img/by-nc-sa1.png | Bin 0 -> 22475 bytes 07-http/pom.xml | 14 + 08-servlet/justfile | 7 + 08-servlet/pom.xml | 37 +++ 08-servlet/servlet.hello/justfile | 4 + 08-servlet/servlet.hello/pom.xml | 14 + .../src/main/java/vs/HelloWorld.java | 84 +++++ .../src/main/webapp/META-INF/MANIFEST.MF | 3 + .../src/main/webapp/WEB-INF/web.xml | 12 + .../src/main/webapp/dir/form1.html | 16 + .../servlet.hello/src/main/webapp/form1.html | 16 + .../servlet.hello/src/main/webapp/form2.html | 16 + .../servlet.hello/src/main/webapp/index.html | 19 ++ .../target/classes/vs/HelloWorld.class | Bin 0 -> 1360 bytes .../compile/default-compile/createdFiles.lst | 1 + .../compile/default-compile/inputFiles.lst | 1 + 08-servlet/servlet.media_solution/justfile | 4 + 08-servlet/servlet.media_solution/pom.xml | 14 + .../src/main/java/vs/DocDeliveryServlet.java | 79 +++++ .../src/main/webapp/META-INF/MANIFEST.MF | 3 + .../src/main/webapp/doc/VAR1-Cover.pdf | Bin 0 -> 7011253 bytes .../src/main/webapp/doc/VAR2-Cover.pdf | Bin 0 -> 10465472 bytes .../src/main/webapp/doc/VAR3-Cover.pdf | Bin 0 -> 1027829 bytes .../src/main/webapp/doc/VAR4-Cover.pdf | Bin 0 -> 2925951 bytes .../src/main/webapp/index.html | 20 ++ 08-servlet/servlet.poll/justfile | 4 + 08-servlet/servlet.poll/pom.xml | 14 + .../src/main/java/vs/BallotBox.java | 37 +++ .../src/main/java/vs/BallotBoxServlet.java | 63 ++++ .../src/main/webapp/META-INF/MANIFEST.MF | 3 + .../servlet.poll/src/main/webapp/index.html | 34 ++ 08-servlet/servlet.wahlen/justfile | 4 + 08-servlet/servlet.wahlen/pom.xml | 14 + .../src/main/java/vs/WahlenController.java | 59 ++++ .../servlet.wahlen/src/main/webapp/index.html | 20 ++ 09-cloud/justfile | 22 ++ 09-cloud/pom.xml | 42 +++ 09-cloud/src/main/java/vs/BallotBox.java | 37 +++ .../src/main/java/vs/BallotBoxServlet.java | 62 ++++ 09-cloud/src/main/webapp/META-INF/MANIFEST.MF | 3 + .../src/main/webapp/WEB-INF/appengine-web.xml | 7 + .../src/main/webapp/WEB-INF/lib/jstl-1.2.jar | Bin 0 -> 414240 bytes 09-cloud/src/main/webapp/WEB-INF/web.xml | 15 + 09-cloud/src/main/webapp/favicon.ico | Bin 0 -> 32038 bytes 09-cloud/src/main/webapp/index.html | 0 09-cloud/src/main/webapp/wahl.html | 34 ++ 15-protobuf/justfile | 4 + 15-protobuf/pom.xml | 55 ++++ 15-protobuf/protobuf.syslog/.gitignore | 1 + 15-protobuf/protobuf.syslog/justfile | 6 + 15-protobuf/protobuf.syslog/pom.xml | 13 + .../src/main/java/vs/ReadLogMessage.java | 13 + .../src/main/java/vs/WriteLogMessage.java | 34 ++ .../src/main/proto/syslog.proto | 41 +++ .../protobuf.syslog/src/main/proto/test.proto | 11 + 18-rest/justfile | 7 + 18-rest/pom.xml | 47 +++ 18-rest/rest.hello/justfile | 6 + 18-rest/rest.hello/pom.xml | 14 + .../src/main/java/vs/HelloMoon.java | 15 + .../src/main/java/vs/HelloWorld.java | 60 ++++ .../src/main/java/vs/HelloWorld2.java | 36 ++ .../src/main/java/vs/TestClient.java | 36 ++ .../src/main/webapp/WEB-INF/web.xml | 18 + 18-rest/rest.hello/src/main/webapp/index.html | 0 18-rest/rest.hello/src/main/webapp/test.html | 21 ++ 20-websocket/.gitignore | 1 + 20-websocket/justfile | 7 + 20-websocket/pom.xml | 48 +++ 20-websocket/websocket.chat/justfile | 4 + 20-websocket/websocket.chat/pom.xml | 14 + .../src/main/java/vs/ChatServer.java | 56 ++++ .../src/main/webapp/META-INF/MANIFEST.MF | 3 + .../websocket.chat/src/main/webapp/chat.html | 39 +++ .../websocket.chat/src/main/webapp/index.html | 12 + 20-websocket/websocket.chat_solution/justfile | 4 + 20-websocket/websocket.chat_solution/pom.xml | 14 + .../src/main/java/vs/ChatServer.java | 56 ++++ .../src/main/webapp/META-INF/MANIFEST.MF | 3 + .../src/main/webapp/chat.html | 39 +++ .../src/main/webapp/index.html | 12 + .../websocket.datasensor_solution/justfile | 4 + .../websocket.datasensor_solution/pom.xml | 28 ++ .../src/main/java/vs/DataDecoder.java | 45 +++ .../src/main/java/vs/DataEncoder.java | 32 ++ .../src/main/java/vs/Messung.java | 87 +++++ .../src/main/java/vs/MessungsService.java | 25 ++ .../src/main/java/vs/SensorSimulator.java | 54 +++ .../src/main/webapp/META-INF/MANIFEST.MF | 3 + .../src/main/webapp/datasensor.html | 35 ++ .../src/main/webapp/index.html | 12 + 20-websocket/websocket.echo/justfile | 4 + 20-websocket/websocket.echo/pom.xml | 14 + .../src/main/java/vs/EchoServer.java | 20 ++ .../src/main/java/vs/Service.java | 25 ++ .../src/main/webapp/META-INF/MANIFEST.MF | 3 + .../websocket.echo/src/main/webapp/echo.html | 37 +++ .../src/main/webapp/echoNickname.html | 37 +++ .../websocket.echo/src/main/webapp/index.html | 13 + 20-websocket/websocket.echo_solution/justfile | 4 + 20-websocket/websocket.echo_solution/pom.xml | 14 + .../src/main/java/vs/EchoServer.java | 20 ++ .../src/main/java/vs/Service.java | 25 ++ .../src/main/webapp/META-INF/MANIFEST.MF | 3 + .../src/main/webapp/echo.html | 37 +++ .../src/main/webapp/echoNickname.html | 37 +++ .../src/main/webapp/index.html | 13 + .../websocket.sensor_solution/justfile | 4 + .../websocket.sensor_solution/pom.xml | 13 + .../src/main/java/vs/MessungsService.java | 25 ++ .../src/main/java/vs/SensorSimulator.java | 43 +++ .../src/main/webapp/META-INF/MANIFEST.MF | 3 + .../src/main/webapp/index.html | 13 + .../src/main/webapp/sensor.html | 31 ++ .../src/main/webapp/sensoren.html | 43 +++ 21-graphql/graphql.election/README.md | 19 ++ 21-graphql/graphql.election/justfile | 23 ++ 21-graphql/graphql.election/pom.xml | 14 + .../src/main/java/vs/BallotBox.java | 61 ++++ .../src/main/java/vs/BallotBoxServlet.java | 63 ++++ .../src/main/java/vs/GraphQLEndpoint.java | 27 ++ .../src/main/java/vs/Main.java | 13 + .../src/main/java/vs/Query.java | 15 + .../src/main/java/vs/Vote.java | 54 +++ .../src/main/resources/schema.graphqls | 13 + .../src/main/webapp/graphiql/index.html | 156 +++++++++ .../src/main/webapp/index.html | 37 +++ .../graphql.election_solution/README.md | 30 ++ 21-graphql/graphql.election_solution/justfile | 32 ++ 21-graphql/graphql.election_solution/pom.xml | 14 + .../src/main/java/vs/BallotBox.java | 61 ++++ .../src/main/java/vs/BallotBoxServlet.java | 63 ++++ .../src/main/java/vs/GraphQLEndpoint.java | 27 ++ .../src/main/java/vs/Main.java | 14 + .../src/main/java/vs/Mutation.java | 15 + .../src/main/java/vs/Query.java | 19 ++ .../src/main/java/vs/Test.java | 41 +++ .../src/main/java/vs/Vote.java | 56 ++++ .../src/main/resources/schema.graphqls | 20 ++ .../src/main/webapp/META-INF/MANIFEST.MF | 3 + .../src/main/webapp/WEB-INF/web.xml | 12 + .../src/main/webapp/graphiql/index.html | 156 +++++++++ .../src/main/webapp/index.html | 37 +++ 21-graphql/justfile | 7 + 21-graphql/pom.xml | 47 +++ 22-grpc/grpc.quarkus_solution/.dockerignore | 5 + 22-grpc/grpc.quarkus_solution/.gitignore | 39 +++ .../.mvn/wrapper/MavenWrapperDownloader.java | 117 +++++++ .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 50710 bytes .../.mvn/wrapper/maven-wrapper.properties | 2 + 22-grpc/grpc.quarkus_solution/README.md | 51 +++ 22-grpc/grpc.quarkus_solution/justfile | 17 + 22-grpc/grpc.quarkus_solution/mvnw | 310 ++++++++++++++++++ 22-grpc/grpc.quarkus_solution/mvnw.cmd | 182 ++++++++++ 22-grpc/grpc.quarkus_solution/pom.xml | 118 +++++++ .../src/main/docker/Dockerfile.jvm | 41 +++ .../src/main/docker/Dockerfile.legacy-jar | 37 +++ .../src/main/docker/Dockerfile.native | 27 ++ .../main/docker/Dockerfile.native-distroless | 23 ++ .../src/main/java/vs/SyslogService.java | 38 +++ .../src/main/proto/syslog.proto | 52 +++ .../src/main/resources/application.properties | 0 22-grpc/grpc.syslog/justfile | 7 + 22-grpc/grpc.syslog/pom.xml | 13 + .../src/main/java/vs/SyslogClient.java | 42 +++ .../src/main/java/vs/SyslogServer.java | 53 +++ .../grpc.syslog/src/main/proto/syslog.proto | 52 +++ 22-grpc/justfile | 4 + 22-grpc/pom.xml | 72 ++++ 99-microservices/quarkus-rest/.dockerignore | 5 + 99-microservices/quarkus-rest/.gitignore | 45 +++ 99-microservices/quarkus-rest/.justfile | 13 + 99-microservices/quarkus-rest/README.md | 66 ++++ 99-microservices/quarkus-rest/pom.xml | 124 +++++++ .../src/main/docker/Dockerfile.jvm | 97 ++++++ .../src/main/docker/Dockerfile.legacy-jar | 93 ++++++ .../src/main/docker/Dockerfile.native | 27 ++ .../src/main/docker/Dockerfile.native-micro | 30 ++ .../src/main/java/vs/GreetingResource.java | 16 + .../src/main/resources/application.properties | 0 .../src/test/java/vs/GreetingResourceIT.java | 8 + .../test/java/vs/GreetingResourceTest.java | 20 ++ .../quarkus_solution/.dockerignore | 5 + 99-microservices/quarkus_solution/.gitignore | 39 +++ .../.mvn/wrapper/MavenWrapperDownloader.java | 117 +++++++ .../.mvn/wrapper/maven-wrapper.properties | 2 + 99-microservices/quarkus_solution/README.md | 73 +++++ 99-microservices/quarkus_solution/mvnw | 310 ++++++++++++++++++ 99-microservices/quarkus_solution/mvnw.cmd | 182 ++++++++++ 99-microservices/quarkus_solution/pom.xml | 143 ++++++++ .../src/main/docker/Dockerfile.jvm | 41 +++ .../src/main/docker/Dockerfile.legacy-jar | 37 +++ .../src/main/docker/Dockerfile.native | 27 ++ .../main/docker/Dockerfile.native-distroless | 23 ++ .../election/BallotBox.java | 63 ++++ .../election/BallotBoxServlet.java | 63 ++++ .../verteiltearchitekturen/election/Vote.java | 56 ++++ .../graphql/GraphQLEndpoint.java | 27 ++ .../verteiltearchitekturen/graphql/Main.java | 15 + .../graphql/Mutation.java | 16 + .../verteiltearchitekturen/graphql/Query.java | 20 ++ .../syslog/GreetingResource.java | 16 + .../syslog/StartWebSocket.java | 40 +++ .../syslog/SyslogService.java | 37 +++ .../src/main/proto/syslog.proto | 52 +++ .../resources/META-INF/resources/index.html | 190 +++++++++++ .../src/main/resources/application.properties | 0 LICENSE | 170 ++++++++++ README.md | 29 ++ justfile | 18 + pom.xml | 55 ++++ 377 files changed, 13199 insertions(+) create mode 100644 02-udp/justfile create mode 100644 02-udp/pom.xml create mode 100644 02-udp/udp.code-workspace create mode 100644 02-udp/udp.echo/justfile create mode 100644 02-udp/udp.echo/pom.xml create mode 100644 02-udp/udp.echo/src/main/java/vs/EchoClient.java create mode 100644 02-udp/udp.echo/src/main/java/vs/EchoServer.java create mode 100644 02-udp/udp.echo_solution/justfile create mode 100644 02-udp/udp.echo_solution/pom.xml create mode 100644 02-udp/udp.echo_solution/src/main/java/vs/EchoClient.java create mode 100644 02-udp/udp.echo_solution/src/main/java/vs/EchoServer.java create mode 100644 02-udp/udp.game_solution/justfile create mode 100644 02-udp/udp.game_solution/pom.xml create mode 100644 02-udp/udp.game_solution/src/main/java/vs/ReactionGameClient.java create mode 100644 02-udp/udp.game_solution/src/main/java/vs/ReactionGameServer.java create mode 100644 02-udp/udp.messwerte/justfile create mode 100644 02-udp/udp.messwerte/pom.xml create mode 100644 02-udp/udp.messwerte/src/main/java/vs/MesswertClient.java create mode 100644 02-udp/udp.messwerte/src/main/java/vs/MesswertServer.java create mode 100644 02-udp/udp.messwerte_solution/justfile create mode 100644 02-udp/udp.messwerte_solution/pom.xml create mode 100644 02-udp/udp.messwerte_solution/src/main/java/vs/MesswertClient.java create mode 100644 02-udp/udp.messwerte_solution/src/main/java/vs/MesswertServer.java create mode 100644 02-udp/udp.time/justfile create mode 100644 02-udp/udp.time/pom.xml create mode 100644 02-udp/udp.time/src/main/java/vs/TimeClient.java create mode 100644 02-udp/udp.time/src/main/java/vs/TimeServer.java create mode 100644 02-udp/udp.time_solution/justfile create mode 100644 02-udp/udp.time_solution/pom.xml create mode 100644 02-udp/udp.time_solution/src/main/java/vs/TimeClient.java create mode 100644 02-udp/udp.time_solution/src/main/java/vs/TimeServer.java create mode 100644 03-tcp/justfile create mode 100644 03-tcp/pom.xml create mode 100644 03-tcp/tcp.code-workspace create mode 100644 03-tcp/tcp.echo/justfile create mode 100644 03-tcp/tcp.echo/pom.xml create mode 100644 03-tcp/tcp.echo/src/main/java/vs/EchoClient.java create mode 100644 03-tcp/tcp.echo/src/main/java/vs/EchoServerIterativ.java create mode 100644 03-tcp/tcp.echo/src/main/java/vs/EchoServerThreaded.java create mode 100644 03-tcp/tcp.echo_solution/justfile create mode 100644 03-tcp/tcp.echo_solution/pom.xml create mode 100644 03-tcp/tcp.echo_solution/src/main/java/vs/EchoClient.java create mode 100644 03-tcp/tcp.echo_solution/src/main/java/vs/EchoServerIterativ.java create mode 100644 03-tcp/tcp.echo_solution/src/main/java/vs/EchoServerThreadPool.java create mode 100644 03-tcp/tcp.echo_solution/src/main/java/vs/EchoServerThreaded.java create mode 100644 03-tcp/tcp.filer/justfile create mode 100644 03-tcp/tcp.filer/pom.xml create mode 100644 03-tcp/tcp.filer/src/main/java/vs/FileClient.java create mode 100644 03-tcp/tcp.filer/src/main/java/vs/FileServerIterativ.java create mode 100644 03-tcp/tcp.filer/src/main/java/vs/FileServerThreaded.java create mode 100644 03-tcp/tcp.filer/src/main/resources/message.txt create mode 100644 03-tcp/tcp.filer_solution/justfile create mode 100644 03-tcp/tcp.filer_solution/pom.xml create mode 100644 03-tcp/tcp.filer_solution/src/main/java/vs/FileClient.java create mode 100644 03-tcp/tcp.filer_solution/src/main/java/vs/FileServerIterativ.java create mode 100644 03-tcp/tcp.filer_solution/src/main/java/vs/FileServerThreadPool.java create mode 100644 03-tcp/tcp.filer_solution/src/main/java/vs/FileServerThreaded.java create mode 100644 03-tcp/tcp.filer_solution/src/main/resources/message.txt create mode 100644 03-tcp/tcp.time/justfile create mode 100644 03-tcp/tcp.time/pom.xml create mode 100644 03-tcp/tcp.time/src/main/java/vs/TimeClient.java create mode 100644 03-tcp/tcp.time/src/main/java/vs/TimeLongServer.java create mode 100644 03-tcp/tcp.time/src/main/java/vs/TimeTextServer.java create mode 100644 03-tcp/tcp.time_solution/justfile create mode 100644 03-tcp/tcp.time_solution/pom.xml create mode 100644 03-tcp/tcp.time_solution/src/main/java/vs/TimeClient.java create mode 100644 03-tcp/tcp.time_solution/src/main/java/vs/TimeLongServer.java create mode 100644 03-tcp/tcp.time_solution/src/main/java/vs/TimeTextServer.java create mode 100644 05-jms/jms.chat/justfile create mode 100644 05-jms/jms.chat/pom.xml create mode 100644 05-jms/jms.chat/src/main/java/vs/ChatClient.java create mode 100644 05-jms/jms.chat/src/main/resources/jndi.properties create mode 100644 05-jms/jms.chat_solution/justfile create mode 100644 05-jms/jms.chat_solution/pom.xml create mode 100644 05-jms/jms.chat_solution/src/main/java/vs/ChatClient.java create mode 100644 05-jms/jms.chat_solution/src/main/java/vs/ChatClientUserProperty.java create mode 100644 05-jms/jms.chat_solution/src/main/java/vs/Conf.java create mode 100644 05-jms/jms.chat_solution/src/main/resources/jndi.properties create mode 100644 05-jms/jms.client/justfile create mode 100644 05-jms/jms.client/pom.xml create mode 100644 05-jms/jms.client/src/main/java/vs/JMSClient.java create mode 100644 05-jms/jms.client/src/main/resources/jndi.properties create mode 100644 05-jms/jms.client_solution/justfile create mode 100644 05-jms/jms.client_solution/pom.xml create mode 100644 05-jms/jms.client_solution/src/main/java/vs/JMSClient.java create mode 100644 05-jms/jms.client_solution/src/main/resources/jndi.properties create mode 100644 05-jms/jms.code-workspace create mode 100644 05-jms/jms.echo/justfile create mode 100644 05-jms/jms.echo/pom.xml create mode 100644 05-jms/jms.echo/src/main/java/vs/Conf.java create mode 100644 05-jms/jms.echo/src/main/java/vs/EchoReplierNode.java create mode 100644 05-jms/jms.echo/src/main/java/vs/EchoRequesterNode.java create mode 100644 05-jms/jms.echo/src/main/resources/jndi.properties create mode 100644 05-jms/jms.echo/target/classes/jndi.properties create mode 100644 05-jms/jms.echo/target/classes/vs/Conf.class create mode 100644 05-jms/jms.echo/target/classes/vs/EchoReplierNode.class create mode 100644 05-jms/jms.echo/target/classes/vs/EchoRequesterNode.class create mode 100644 05-jms/jms.echo_solution/justfile create mode 100644 05-jms/jms.echo_solution/pom.xml create mode 100644 05-jms/jms.echo_solution/src/main/java/vs/Conf.java create mode 100644 05-jms/jms.echo_solution/src/main/java/vs/EchoReplierNode.java create mode 100644 05-jms/jms.echo_solution/src/main/java/vs/EchoRequesterNode.java create mode 100644 05-jms/jms.echo_solution/src/main/resources/jndi.properties create mode 100644 05-jms/jms.logger/justfile create mode 100644 05-jms/jms.logger/pom.xml create mode 100644 05-jms/jms.logger/src/main/java/vs/Conf.java create mode 100644 05-jms/jms.logger/src/main/java/vs/ConsumerCallbackNode.java create mode 100644 05-jms/jms.logger/src/main/java/vs/ConsumerFilteredNode.java create mode 100644 05-jms/jms.logger/src/main/java/vs/ConsumerPullNode.java create mode 100644 05-jms/jms.logger/src/main/java/vs/ProducerNode.java create mode 100644 05-jms/jms.logger/src/main/resources/jndi.properties create mode 100644 05-jms/jms.logger_solution/justfile create mode 100644 05-jms/jms.logger_solution/pom.xml create mode 100644 05-jms/jms.logger_solution/src/main/java/vs/Conf.java create mode 100644 05-jms/jms.logger_solution/src/main/java/vs/ConsumerCallbackNode.java create mode 100644 05-jms/jms.logger_solution/src/main/java/vs/ConsumerFilteredNode.java create mode 100644 05-jms/jms.logger_solution/src/main/java/vs/ConsumerPullNode.java create mode 100644 05-jms/jms.logger_solution/src/main/java/vs/ProducerNode.java create mode 100644 05-jms/jms.logger_solution/src/main/resources/jndi.properties create mode 100644 05-jms/jms.revers_solution/justfile create mode 100644 05-jms/jms.revers_solution/pom.xml create mode 100644 05-jms/jms.revers_solution/src/main/java/vs/Anfrager.java create mode 100644 05-jms/jms.revers_solution/src/main/java/vs/Conf.java create mode 100644 05-jms/jms.revers_solution/src/main/java/vs/Umdreher.java create mode 100644 05-jms/jms.revers_solution/src/main/java/vs/UmdreherReuseProducers.java create mode 100644 05-jms/jms.revers_solution/src/main/resources/jndi.properties create mode 100644 05-jms/jms.tasks_solution/justfile create mode 100644 05-jms/jms.tasks_solution/pom.xml create mode 100644 05-jms/jms.tasks_solution/src/main/java/vs/Conf.java create mode 100644 05-jms/jms.tasks_solution/src/main/java/vs/PasswordCandidateGenerator.java create mode 100644 05-jms/jms.tasks_solution/src/main/java/vs/PasswordCandidateValidator.java create mode 100644 05-jms/jms.tasks_solution/src/main/resources/jndi.properties create mode 100644 05-jms/justfile create mode 100644 05-jms/pom.xml create mode 100644 06-mqtt/.gitignore create mode 100644 06-mqtt/justfile create mode 100644 06-mqtt/mqtt.code-workspace create mode 100644 06-mqtt/mqtt.logger/justfile create mode 100644 06-mqtt/mqtt.logger/pom.xml create mode 100644 06-mqtt/mqtt.logger/src/main/java/vs/Conf.java create mode 100644 06-mqtt/mqtt.logger/src/main/java/vs/Publisher.java create mode 100644 06-mqtt/mqtt.logger/src/main/java/vs/Subscriber.java create mode 100644 06-mqtt/mqtt.logger_solution/justfile create mode 100644 06-mqtt/mqtt.logger_solution/pom.xml create mode 100644 06-mqtt/mqtt.logger_solution/src/main/java/vs/Conf.java create mode 100644 06-mqtt/mqtt.logger_solution/src/main/java/vs/Publisher.java create mode 100644 06-mqtt/mqtt.logger_solution/src/main/java/vs/Subscriber.java create mode 100644 06-mqtt/mqtt.smarthome_solution/justfile create mode 100644 06-mqtt/mqtt.smarthome_solution/pom.xml create mode 100644 06-mqtt/mqtt.smarthome_solution/src/main/java/vs/AlarmSubscriber.java create mode 100644 06-mqtt/mqtt.smarthome_solution/src/main/java/vs/Conf.java create mode 100644 06-mqtt/mqtt.smarthome_solution/src/main/java/vs/FloorPlotter.java create mode 100644 06-mqtt/mqtt.smarthome_solution/src/main/java/vs/LoggingSubscriber.java create mode 100644 06-mqtt/mqtt.smarthome_solution/src/main/java/vs/Sensor.java create mode 100644 06-mqtt/mqtt.smarthome_solution/src/main/java/vs/SensorSelfDescribung.java create mode 100644 06-mqtt/pom.xml create mode 100644 07-http/http.webserver/justfile create mode 100644 07-http/http.webserver/pom.xml create mode 100644 07-http/http.webserver/src/main/java/vs/WebServer.java create mode 100644 07-http/http.webserver/src/main/resources/docs/form.html create mode 100644 07-http/http.webserver/src/main/resources/docs/img/by-nc-sa1.png create mode 100644 07-http/http.webserver_solution/justfile create mode 100644 07-http/http.webserver_solution/pom.xml create mode 100644 07-http/http.webserver_solution/src/main/java/vs/WebServer.java create mode 100644 07-http/http.webserver_solution/src/main/resources/docs/form.html create mode 100644 07-http/http.webserver_solution/src/main/resources/docs/http/WebServer.java create mode 100644 07-http/http.webserver_solution/src/main/resources/docs/img/by-nc-sa1.png create mode 100644 07-http/pom.xml create mode 100644 08-servlet/justfile create mode 100644 08-servlet/pom.xml create mode 100644 08-servlet/servlet.hello/justfile create mode 100644 08-servlet/servlet.hello/pom.xml create mode 100644 08-servlet/servlet.hello/src/main/java/vs/HelloWorld.java create mode 100644 08-servlet/servlet.hello/src/main/webapp/META-INF/MANIFEST.MF create mode 100644 08-servlet/servlet.hello/src/main/webapp/WEB-INF/web.xml create mode 100644 08-servlet/servlet.hello/src/main/webapp/dir/form1.html create mode 100644 08-servlet/servlet.hello/src/main/webapp/form1.html create mode 100644 08-servlet/servlet.hello/src/main/webapp/form2.html create mode 100644 08-servlet/servlet.hello/src/main/webapp/index.html create mode 100644 08-servlet/servlet.hello/target/classes/vs/HelloWorld.class create mode 100644 08-servlet/servlet.hello/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst create mode 100644 08-servlet/servlet.hello/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst create mode 100644 08-servlet/servlet.media_solution/justfile create mode 100644 08-servlet/servlet.media_solution/pom.xml create mode 100644 08-servlet/servlet.media_solution/src/main/java/vs/DocDeliveryServlet.java create mode 100644 08-servlet/servlet.media_solution/src/main/webapp/META-INF/MANIFEST.MF create mode 100644 08-servlet/servlet.media_solution/src/main/webapp/doc/VAR1-Cover.pdf create mode 100644 08-servlet/servlet.media_solution/src/main/webapp/doc/VAR2-Cover.pdf create mode 100644 08-servlet/servlet.media_solution/src/main/webapp/doc/VAR3-Cover.pdf create mode 100644 08-servlet/servlet.media_solution/src/main/webapp/doc/VAR4-Cover.pdf create mode 100644 08-servlet/servlet.media_solution/src/main/webapp/index.html create mode 100644 08-servlet/servlet.poll/justfile create mode 100644 08-servlet/servlet.poll/pom.xml create mode 100644 08-servlet/servlet.poll/src/main/java/vs/BallotBox.java create mode 100644 08-servlet/servlet.poll/src/main/java/vs/BallotBoxServlet.java create mode 100644 08-servlet/servlet.poll/src/main/webapp/META-INF/MANIFEST.MF create mode 100644 08-servlet/servlet.poll/src/main/webapp/index.html create mode 100644 08-servlet/servlet.wahlen/justfile create mode 100644 08-servlet/servlet.wahlen/pom.xml create mode 100644 08-servlet/servlet.wahlen/src/main/java/vs/WahlenController.java create mode 100644 08-servlet/servlet.wahlen/src/main/webapp/index.html create mode 100644 09-cloud/justfile create mode 100644 09-cloud/pom.xml create mode 100644 09-cloud/src/main/java/vs/BallotBox.java create mode 100644 09-cloud/src/main/java/vs/BallotBoxServlet.java create mode 100644 09-cloud/src/main/webapp/META-INF/MANIFEST.MF create mode 100644 09-cloud/src/main/webapp/WEB-INF/appengine-web.xml create mode 100644 09-cloud/src/main/webapp/WEB-INF/lib/jstl-1.2.jar create mode 100644 09-cloud/src/main/webapp/WEB-INF/web.xml create mode 100644 09-cloud/src/main/webapp/favicon.ico create mode 100644 09-cloud/src/main/webapp/index.html create mode 100644 09-cloud/src/main/webapp/wahl.html create mode 100644 15-protobuf/justfile create mode 100644 15-protobuf/pom.xml create mode 100644 15-protobuf/protobuf.syslog/.gitignore create mode 100644 15-protobuf/protobuf.syslog/justfile create mode 100644 15-protobuf/protobuf.syslog/pom.xml create mode 100644 15-protobuf/protobuf.syslog/src/main/java/vs/ReadLogMessage.java create mode 100644 15-protobuf/protobuf.syslog/src/main/java/vs/WriteLogMessage.java create mode 100644 15-protobuf/protobuf.syslog/src/main/proto/syslog.proto create mode 100644 15-protobuf/protobuf.syslog/src/main/proto/test.proto create mode 100644 18-rest/justfile create mode 100644 18-rest/pom.xml create mode 100644 18-rest/rest.hello/justfile create mode 100644 18-rest/rest.hello/pom.xml create mode 100644 18-rest/rest.hello/src/main/java/vs/HelloMoon.java create mode 100644 18-rest/rest.hello/src/main/java/vs/HelloWorld.java create mode 100644 18-rest/rest.hello/src/main/java/vs/HelloWorld2.java create mode 100644 18-rest/rest.hello/src/main/java/vs/TestClient.java create mode 100644 18-rest/rest.hello/src/main/webapp/WEB-INF/web.xml create mode 100644 18-rest/rest.hello/src/main/webapp/index.html create mode 100644 18-rest/rest.hello/src/main/webapp/test.html create mode 100644 20-websocket/.gitignore create mode 100644 20-websocket/justfile create mode 100644 20-websocket/pom.xml create mode 100644 20-websocket/websocket.chat/justfile create mode 100644 20-websocket/websocket.chat/pom.xml create mode 100644 20-websocket/websocket.chat/src/main/java/vs/ChatServer.java create mode 100644 20-websocket/websocket.chat/src/main/webapp/META-INF/MANIFEST.MF create mode 100644 20-websocket/websocket.chat/src/main/webapp/chat.html create mode 100644 20-websocket/websocket.chat/src/main/webapp/index.html create mode 100644 20-websocket/websocket.chat_solution/justfile create mode 100644 20-websocket/websocket.chat_solution/pom.xml create mode 100644 20-websocket/websocket.chat_solution/src/main/java/vs/ChatServer.java create mode 100644 20-websocket/websocket.chat_solution/src/main/webapp/META-INF/MANIFEST.MF create mode 100644 20-websocket/websocket.chat_solution/src/main/webapp/chat.html create mode 100644 20-websocket/websocket.chat_solution/src/main/webapp/index.html create mode 100644 20-websocket/websocket.datasensor_solution/justfile create mode 100644 20-websocket/websocket.datasensor_solution/pom.xml create mode 100644 20-websocket/websocket.datasensor_solution/src/main/java/vs/DataDecoder.java create mode 100644 20-websocket/websocket.datasensor_solution/src/main/java/vs/DataEncoder.java create mode 100644 20-websocket/websocket.datasensor_solution/src/main/java/vs/Messung.java create mode 100644 20-websocket/websocket.datasensor_solution/src/main/java/vs/MessungsService.java create mode 100644 20-websocket/websocket.datasensor_solution/src/main/java/vs/SensorSimulator.java create mode 100644 20-websocket/websocket.datasensor_solution/src/main/webapp/META-INF/MANIFEST.MF create mode 100644 20-websocket/websocket.datasensor_solution/src/main/webapp/datasensor.html create mode 100644 20-websocket/websocket.datasensor_solution/src/main/webapp/index.html create mode 100644 20-websocket/websocket.echo/justfile create mode 100644 20-websocket/websocket.echo/pom.xml create mode 100644 20-websocket/websocket.echo/src/main/java/vs/EchoServer.java create mode 100644 20-websocket/websocket.echo/src/main/java/vs/Service.java create mode 100644 20-websocket/websocket.echo/src/main/webapp/META-INF/MANIFEST.MF create mode 100644 20-websocket/websocket.echo/src/main/webapp/echo.html create mode 100644 20-websocket/websocket.echo/src/main/webapp/echoNickname.html create mode 100644 20-websocket/websocket.echo/src/main/webapp/index.html create mode 100644 20-websocket/websocket.echo_solution/justfile create mode 100644 20-websocket/websocket.echo_solution/pom.xml create mode 100644 20-websocket/websocket.echo_solution/src/main/java/vs/EchoServer.java create mode 100644 20-websocket/websocket.echo_solution/src/main/java/vs/Service.java create mode 100644 20-websocket/websocket.echo_solution/src/main/webapp/META-INF/MANIFEST.MF create mode 100644 20-websocket/websocket.echo_solution/src/main/webapp/echo.html create mode 100644 20-websocket/websocket.echo_solution/src/main/webapp/echoNickname.html create mode 100644 20-websocket/websocket.echo_solution/src/main/webapp/index.html create mode 100644 20-websocket/websocket.sensor_solution/justfile create mode 100644 20-websocket/websocket.sensor_solution/pom.xml create mode 100644 20-websocket/websocket.sensor_solution/src/main/java/vs/MessungsService.java create mode 100644 20-websocket/websocket.sensor_solution/src/main/java/vs/SensorSimulator.java create mode 100644 20-websocket/websocket.sensor_solution/src/main/webapp/META-INF/MANIFEST.MF create mode 100644 20-websocket/websocket.sensor_solution/src/main/webapp/index.html create mode 100644 20-websocket/websocket.sensor_solution/src/main/webapp/sensor.html create mode 100644 20-websocket/websocket.sensor_solution/src/main/webapp/sensoren.html create mode 100644 21-graphql/graphql.election/README.md create mode 100644 21-graphql/graphql.election/justfile create mode 100644 21-graphql/graphql.election/pom.xml create mode 100644 21-graphql/graphql.election/src/main/java/vs/BallotBox.java create mode 100644 21-graphql/graphql.election/src/main/java/vs/BallotBoxServlet.java create mode 100644 21-graphql/graphql.election/src/main/java/vs/GraphQLEndpoint.java create mode 100644 21-graphql/graphql.election/src/main/java/vs/Main.java create mode 100644 21-graphql/graphql.election/src/main/java/vs/Query.java create mode 100644 21-graphql/graphql.election/src/main/java/vs/Vote.java create mode 100644 21-graphql/graphql.election/src/main/resources/schema.graphqls create mode 100644 21-graphql/graphql.election/src/main/webapp/graphiql/index.html create mode 100644 21-graphql/graphql.election/src/main/webapp/index.html create mode 100644 21-graphql/graphql.election_solution/README.md create mode 100644 21-graphql/graphql.election_solution/justfile create mode 100644 21-graphql/graphql.election_solution/pom.xml create mode 100644 21-graphql/graphql.election_solution/src/main/java/vs/BallotBox.java create mode 100644 21-graphql/graphql.election_solution/src/main/java/vs/BallotBoxServlet.java create mode 100644 21-graphql/graphql.election_solution/src/main/java/vs/GraphQLEndpoint.java create mode 100644 21-graphql/graphql.election_solution/src/main/java/vs/Main.java create mode 100644 21-graphql/graphql.election_solution/src/main/java/vs/Mutation.java create mode 100644 21-graphql/graphql.election_solution/src/main/java/vs/Query.java create mode 100644 21-graphql/graphql.election_solution/src/main/java/vs/Test.java create mode 100644 21-graphql/graphql.election_solution/src/main/java/vs/Vote.java create mode 100644 21-graphql/graphql.election_solution/src/main/resources/schema.graphqls create mode 100644 21-graphql/graphql.election_solution/src/main/webapp/META-INF/MANIFEST.MF create mode 100644 21-graphql/graphql.election_solution/src/main/webapp/WEB-INF/web.xml create mode 100644 21-graphql/graphql.election_solution/src/main/webapp/graphiql/index.html create mode 100644 21-graphql/graphql.election_solution/src/main/webapp/index.html create mode 100644 21-graphql/justfile create mode 100644 21-graphql/pom.xml create mode 100644 22-grpc/grpc.quarkus_solution/.dockerignore create mode 100644 22-grpc/grpc.quarkus_solution/.gitignore create mode 100644 22-grpc/grpc.quarkus_solution/.mvn/wrapper/MavenWrapperDownloader.java create mode 100644 22-grpc/grpc.quarkus_solution/.mvn/wrapper/maven-wrapper.jar create mode 100644 22-grpc/grpc.quarkus_solution/.mvn/wrapper/maven-wrapper.properties create mode 100644 22-grpc/grpc.quarkus_solution/README.md create mode 100644 22-grpc/grpc.quarkus_solution/justfile create mode 100755 22-grpc/grpc.quarkus_solution/mvnw create mode 100644 22-grpc/grpc.quarkus_solution/mvnw.cmd create mode 100644 22-grpc/grpc.quarkus_solution/pom.xml create mode 100644 22-grpc/grpc.quarkus_solution/src/main/docker/Dockerfile.jvm create mode 100644 22-grpc/grpc.quarkus_solution/src/main/docker/Dockerfile.legacy-jar create mode 100644 22-grpc/grpc.quarkus_solution/src/main/docker/Dockerfile.native create mode 100644 22-grpc/grpc.quarkus_solution/src/main/docker/Dockerfile.native-distroless create mode 100644 22-grpc/grpc.quarkus_solution/src/main/java/vs/SyslogService.java create mode 100644 22-grpc/grpc.quarkus_solution/src/main/proto/syslog.proto create mode 100644 22-grpc/grpc.quarkus_solution/src/main/resources/application.properties create mode 100644 22-grpc/grpc.syslog/justfile create mode 100644 22-grpc/grpc.syslog/pom.xml create mode 100644 22-grpc/grpc.syslog/src/main/java/vs/SyslogClient.java create mode 100644 22-grpc/grpc.syslog/src/main/java/vs/SyslogServer.java create mode 100644 22-grpc/grpc.syslog/src/main/proto/syslog.proto create mode 100644 22-grpc/justfile create mode 100644 22-grpc/pom.xml create mode 100644 99-microservices/quarkus-rest/.dockerignore create mode 100644 99-microservices/quarkus-rest/.gitignore create mode 100644 99-microservices/quarkus-rest/.justfile create mode 100644 99-microservices/quarkus-rest/README.md create mode 100644 99-microservices/quarkus-rest/pom.xml create mode 100644 99-microservices/quarkus-rest/src/main/docker/Dockerfile.jvm create mode 100644 99-microservices/quarkus-rest/src/main/docker/Dockerfile.legacy-jar create mode 100644 99-microservices/quarkus-rest/src/main/docker/Dockerfile.native create mode 100644 99-microservices/quarkus-rest/src/main/docker/Dockerfile.native-micro create mode 100644 99-microservices/quarkus-rest/src/main/java/vs/GreetingResource.java create mode 100644 99-microservices/quarkus-rest/src/main/resources/application.properties create mode 100644 99-microservices/quarkus-rest/src/test/java/vs/GreetingResourceIT.java create mode 100644 99-microservices/quarkus-rest/src/test/java/vs/GreetingResourceTest.java create mode 100755 99-microservices/quarkus_solution/.dockerignore create mode 100755 99-microservices/quarkus_solution/.gitignore create mode 100755 99-microservices/quarkus_solution/.mvn/wrapper/MavenWrapperDownloader.java create mode 100755 99-microservices/quarkus_solution/.mvn/wrapper/maven-wrapper.properties create mode 100755 99-microservices/quarkus_solution/README.md create mode 100755 99-microservices/quarkus_solution/mvnw create mode 100755 99-microservices/quarkus_solution/mvnw.cmd create mode 100755 99-microservices/quarkus_solution/pom.xml create mode 100755 99-microservices/quarkus_solution/src/main/docker/Dockerfile.jvm create mode 100755 99-microservices/quarkus_solution/src/main/docker/Dockerfile.legacy-jar create mode 100755 99-microservices/quarkus_solution/src/main/docker/Dockerfile.native create mode 100755 99-microservices/quarkus_solution/src/main/docker/Dockerfile.native-distroless create mode 100755 99-microservices/quarkus_solution/src/main/java/de/verteiltearchitekturen/election/BallotBox.java create mode 100755 99-microservices/quarkus_solution/src/main/java/de/verteiltearchitekturen/election/BallotBoxServlet.java create mode 100755 99-microservices/quarkus_solution/src/main/java/de/verteiltearchitekturen/election/Vote.java create mode 100755 99-microservices/quarkus_solution/src/main/java/de/verteiltearchitekturen/graphql/GraphQLEndpoint.java create mode 100755 99-microservices/quarkus_solution/src/main/java/de/verteiltearchitekturen/graphql/Main.java create mode 100755 99-microservices/quarkus_solution/src/main/java/de/verteiltearchitekturen/graphql/Mutation.java create mode 100755 99-microservices/quarkus_solution/src/main/java/de/verteiltearchitekturen/graphql/Query.java create mode 100755 99-microservices/quarkus_solution/src/main/java/de/verteiltearchitekturen/syslog/GreetingResource.java create mode 100755 99-microservices/quarkus_solution/src/main/java/de/verteiltearchitekturen/syslog/StartWebSocket.java create mode 100755 99-microservices/quarkus_solution/src/main/java/de/verteiltearchitekturen/syslog/SyslogService.java create mode 100755 99-microservices/quarkus_solution/src/main/proto/syslog.proto create mode 100755 99-microservices/quarkus_solution/src/main/resources/META-INF/resources/index.html create mode 100755 99-microservices/quarkus_solution/src/main/resources/application.properties create mode 100644 LICENSE create mode 100644 README.md create mode 100644 justfile create mode 100644 pom.xml diff --git a/02-udp/justfile b/02-udp/justfile new file mode 100644 index 0000000..b7e9b7b --- /dev/null +++ b/02-udp/justfile @@ -0,0 +1,4 @@ +import '../justfile' + +zed: + $VISUAL udp.echo udp.echo_solution udp.time udp.time_solution udp.messwerte udp.messwerte_solution udp.game_solution diff --git a/02-udp/pom.xml b/02-udp/pom.xml new file mode 100644 index 0000000..0862258 --- /dev/null +++ b/02-udp/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + vs + udp + 1.0-SNAPSHOT + pom + + + vs + parent + 1.0-SNAPSHOT + + + diff --git a/02-udp/udp.code-workspace b/02-udp/udp.code-workspace new file mode 100644 index 0000000..3ef8fbc --- /dev/null +++ b/02-udp/udp.code-workspace @@ -0,0 +1,43 @@ +{ + "folders": [ + { + "name": "1. Echo Service", + "path": "udp.echo", + }, + { + "name": "1. Echo Service (ML)", + "path": "udp.echo_solution", + }, + { + "name": "2. Time Service", + "path": "udp.time", + }, + { + "name": "2. Time Service (ML)", + "path": "udp.time_solution", + }, + { + "name": "3. Messwert Service", + "path": "udp.messwerte", + }, + { + "name": "3. Messwert Service (ML)", + "path": "udp.messwerte_solution", + }, + { + "name": "4. ReactionGame (ML)", + "path": "udp.game_solution", + }, + ], + "extensions": { + "recommendations": [ + "vscjava.vscode-java-pack", + "ms-azuretools.vscode-docker", + "skellock.just", + ], + }, + "settings": { + "java.dependency.syncWithFolderExplorer": true, + "java.project.explorer.showNonJavaResources": false, + }, +} diff --git a/02-udp/udp.echo/justfile b/02-udp/udp.echo/justfile new file mode 100644 index 0000000..785b05d --- /dev/null +++ b/02-udp/udp.echo/justfile @@ -0,0 +1,6 @@ +import '../justfile' + +server: + just exec vs.EchoServer "" +client message: + just exec vs.EchoClient "{{message}}" diff --git a/02-udp/udp.echo/pom.xml b/02-udp/udp.echo/pom.xml new file mode 100644 index 0000000..6a655d6 --- /dev/null +++ b/02-udp/udp.echo/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + vs + udp.echo + 1.0-SNAPSHOT + jar + + + vs + udp + 1.0-SNAPSHOT + + diff --git a/02-udp/udp.echo/src/main/java/vs/EchoClient.java b/02-udp/udp.echo/src/main/java/vs/EchoClient.java new file mode 100644 index 0000000..df54a3b --- /dev/null +++ b/02-udp/udp.echo/src/main/java/vs/EchoClient.java @@ -0,0 +1,33 @@ +package vs; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketTimeoutException; + +public class EchoClient { + private static final String HOST = "localhost"; + private static final int PORT = 4711; + private static final int BUFSIZE = 512; + private static final int TIMEOUT = 2000; + + public static void main(String[] args) { + byte[] data = args[0].getBytes(); + try (DatagramSocket socket = new DatagramSocket()) { + socket.setSoTimeout(TIMEOUT); // Zeit in ms, für wie lange ein read() auf socket blockiert. + // Bei timeout is java.net.SocketTimeoutException (TIMEOUT == 0 + // => blockiert für immer) + InetAddress iaddr = InetAddress.getByName(HOST); + DatagramPacket packetOut = new DatagramPacket(data, data.length, iaddr, PORT); + socket.send(packetOut); + DatagramPacket packetIn = new DatagramPacket(new byte[BUFSIZE], BUFSIZE); + socket.receive(packetOut); + String received = new String(packetIn.getData(), 0, packetIn.getLength()); + System.out.println("Received: " + received); + } catch (SocketTimeoutException e) { + System.err.println("Timeout: " + e.getMessage()); + } catch (Exception e) { + System.err.println(e); + } + } +} diff --git a/02-udp/udp.echo/src/main/java/vs/EchoServer.java b/02-udp/udp.echo/src/main/java/vs/EchoServer.java new file mode 100644 index 0000000..c765d4f --- /dev/null +++ b/02-udp/udp.echo/src/main/java/vs/EchoServer.java @@ -0,0 +1,31 @@ +package vs; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; + +public class EchoServer { + private static final int PORT = 4711; + private static final int BUFSIZE = 512; + + public static void main(final String[] args) { + try (DatagramSocket socket = new DatagramSocket(PORT)) { + DatagramPacket packetIn = new DatagramPacket(new byte[BUFSIZE], BUFSIZE); + DatagramPacket packetOut = new DatagramPacket(new byte[BUFSIZE], BUFSIZE); + + System.out.println("Server gestartet ..."); + + while (true) { + socket.receive(packetIn); + System.out.println( + "Received: " + packetIn.getLength() + " bytes: " + new String(packetIn.getData())); + packetOut.setData(packetIn.getData()); + packetOut.setLength(packetIn.getLength()); + // mehr Eigenschaften von packetOut setzen... + socket.send(packetOut); + } + } catch (IOException e) { + System.err.println(e); + } + } +} diff --git a/02-udp/udp.echo_solution/justfile b/02-udp/udp.echo_solution/justfile new file mode 100644 index 0000000..785b05d --- /dev/null +++ b/02-udp/udp.echo_solution/justfile @@ -0,0 +1,6 @@ +import '../justfile' + +server: + just exec vs.EchoServer "" +client message: + just exec vs.EchoClient "{{message}}" diff --git a/02-udp/udp.echo_solution/pom.xml b/02-udp/udp.echo_solution/pom.xml new file mode 100644 index 0000000..4193942 --- /dev/null +++ b/02-udp/udp.echo_solution/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + vs + udp.echo_solution + 1.0-SNAPSHOT + jar + + + vs + udp + 1.0-SNAPSHOT + + diff --git a/02-udp/udp.echo_solution/src/main/java/vs/EchoClient.java b/02-udp/udp.echo_solution/src/main/java/vs/EchoClient.java new file mode 100644 index 0000000..2261b42 --- /dev/null +++ b/02-udp/udp.echo_solution/src/main/java/vs/EchoClient.java @@ -0,0 +1,58 @@ +package vs; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketTimeoutException; + +/** + * Client for echo var.sockets.udp.echo.EchoServer service. Sendet Kommandozeilenargument an HOST, + * wartet bis TIMEOUT auf Antwort vom Server, liest sie und gibt den Inhalt aus. + * + * @author Sandro Leuchter + * + */ +public class EchoClient { + /** + * host on which server is running (IP-address or hostname) + */ + private static final String HOST = "localhost"; + /** + * port on which service is running on host + */ + private static final int PORT = 4711; + /** + * maximum size of payload in datagram + */ + private static final int BUFSIZE = 512; + /** + * timeout in ms for waiting for a response from server + */ + private static final int TIMEOUT = 2000; + + /** + * main method: entrypoint to run + * + * @param args + * must be String[1]: message to be send to server + */ + public static void main(String[] args) { + byte[] data = args[0].getBytes(); + try (DatagramSocket socket = new DatagramSocket()) { + socket.setSoTimeout(TIMEOUT); // Zeit in ms, für wie lange ein read() auf socket blockiert. + // Bei timeout is java.net.SocketTimeoutException (TIMEOUT == 0 + // => blockiert für immer) + InetAddress iaddr = InetAddress.getByName(HOST); + DatagramPacket packetOut = new DatagramPacket(data, data.length, iaddr, PORT); + socket.send(packetOut); + DatagramPacket packetIn = new DatagramPacket(new byte[BUFSIZE], BUFSIZE); + socket.receive(packetIn); + String received = new String(packetIn.getData(), 0, packetIn.getLength()); + System.out.println("Received: " + received); + } catch (SocketTimeoutException e) { + System.err.println("Timeout: " + e.getMessage()); + } catch (Exception e) { + System.err.println(e); + } + } +} diff --git a/02-udp/udp.echo_solution/src/main/java/vs/EchoServer.java b/02-udp/udp.echo_solution/src/main/java/vs/EchoServer.java new file mode 100644 index 0000000..e9742f9 --- /dev/null +++ b/02-udp/udp.echo_solution/src/main/java/vs/EchoServer.java @@ -0,0 +1,50 @@ +package vs; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; + +/** + * Server for var.sockets.udp.echo.EchoServer service. Empfängt ANfrage von Clients und sendet den + * Inhalt jeweils an den Client zurück + * + * @author Sandro Leuchter + * + */ +public class EchoServer { + /** + * port on which service is running on host + */ + private static final int PORT = 4711; + /** + * maximum size of payload in datagram + */ + private static final int BUFSIZE = 512; + + /** + * main method: entrypoint to run + * + * @param args + * ignored + */ + public static void main(final String[] args) { + try (DatagramSocket socket = new DatagramSocket(PORT)) { + DatagramPacket packetIn = new DatagramPacket(new byte[BUFSIZE], BUFSIZE); + DatagramPacket packetOut = new DatagramPacket(new byte[BUFSIZE], BUFSIZE); + + System.out.println("Server gestartet ..."); + + while (true) { + socket.receive(packetIn); + System.out.println("Received: " + packetIn.getLength() + " bytes: " + + new String(packetIn.getData(), 0, packetIn.getLength())); + packetOut.setData(packetIn.getData()); + packetOut.setLength(packetIn.getLength()); + packetOut.setSocketAddress(packetIn.getSocketAddress()); + socket.send(packetOut); + } + } catch (IOException e) { + System.err.println(e); + } + } +} diff --git a/02-udp/udp.game_solution/justfile b/02-udp/udp.game_solution/justfile new file mode 100644 index 0000000..bbb9452 --- /dev/null +++ b/02-udp/udp.game_solution/justfile @@ -0,0 +1,6 @@ +import '../justfile' + +server: + just exec vs.ReactionGameServer "" +client: + just exec vs.ReactionGameClient "" diff --git a/02-udp/udp.game_solution/pom.xml b/02-udp/udp.game_solution/pom.xml new file mode 100644 index 0000000..fb0df6b --- /dev/null +++ b/02-udp/udp.game_solution/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + vs + udp.game_solution + 1.0-SNAPSHOT + jar + + + vs + udp + 1.0-SNAPSHOT + + diff --git a/02-udp/udp.game_solution/src/main/java/vs/ReactionGameClient.java b/02-udp/udp.game_solution/src/main/java/vs/ReactionGameClient.java new file mode 100644 index 0000000..82b3bec --- /dev/null +++ b/02-udp/udp.game_solution/src/main/java/vs/ReactionGameClient.java @@ -0,0 +1,42 @@ +package vs; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; + +/** + * Client for echo var.sockets.udp.game.ReactionGameServer service. Sendet leerees Paket an HOST. + * + * @author Sandro Leuchter + * + */ +public class ReactionGameClient { + /** + * host on which server is running (IP-address or hostname) + */ + private static final String HOST = "localhost"; + /** + * port on which service is running on host + */ + private static final int PORT = 4714; + /** + * maximum size of payload in datagram + */ + private static final int BUFSIZE = 0; + + /** + * main method: entrypoint to run + * + * @param args + * ignored + */ + public static void main(String[] args) { + try (DatagramSocket socket = new DatagramSocket()) { + InetAddress iaddr = InetAddress.getByName(HOST); + DatagramPacket packetOut = new DatagramPacket(new byte[BUFSIZE], BUFSIZE, iaddr, PORT); + socket.send(packetOut); + } catch (Exception e) { + System.err.println(e); + } + } +} diff --git a/02-udp/udp.game_solution/src/main/java/vs/ReactionGameServer.java b/02-udp/udp.game_solution/src/main/java/vs/ReactionGameServer.java new file mode 100644 index 0000000..d3c4109 --- /dev/null +++ b/02-udp/udp.game_solution/src/main/java/vs/ReactionGameServer.java @@ -0,0 +1,63 @@ +package vs; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.SocketTimeoutException; +import java.util.Random; + +/** + * Server for var.sockets.udp.game.ReactionGameServer service. Waits a random time less than + * MAX_WAITING_TIME_MS ms, then opens Gate for GATE_OPEN_DURATION_MS ms on port PORT, waiting for a + * UDP packet to receive. + * + * @author Sandro Leuchter + * + */ +public class ReactionGameServer { + /** + * port on which service is running on host + */ + private static final int PORT = 4714; + private static final int GATE_OPEN_DURATION_MS = 2000; + private static final int MAX_WAITING_TIME_MS = 4000; + private static final Random random = new Random(System.currentTimeMillis()); + /** + * maximum size of payload in datagram + */ + private static final int BUFSIZE = 512; + + /** + * main method: entrypoint to run + * + * @param args + * ignored + * @throws InterruptedException + * if interrupt during random sleeping period + */ + public static void main(final String[] args) throws InterruptedException { + try (DatagramSocket socket = new DatagramSocket(PORT)) { + socket.setSoTimeout(GATE_OPEN_DURATION_MS); + DatagramPacket packetIn = new DatagramPacket(new byte[BUFSIZE], BUFSIZE); + + System.out.println("Server gestartet ..."); + + Thread.sleep(random.nextInt(MAX_WAITING_TIME_MS)); + boolean timeout = false; + System.out.println("offen für Empfang"); + try { + socket.receive(packetIn); + } catch (SocketTimeoutException e) { + timeout = true; + } + System.out.println("Empfang geschlossen"); + if (timeout) { + System.out.println("nicht schnell genug!"); + } else { + System.out.println("Paket hat es geschafft"); + } + } catch (IOException e) { + System.err.println(e); + } + } +} diff --git a/02-udp/udp.messwerte/justfile b/02-udp/udp.messwerte/justfile new file mode 100644 index 0000000..1e8ebeb --- /dev/null +++ b/02-udp/udp.messwerte/justfile @@ -0,0 +1,6 @@ +import '../justfile' + +server: + just exec vs.MesswertServer "" +client: + just exec vs.MesswertClient "" diff --git a/02-udp/udp.messwerte/pom.xml b/02-udp/udp.messwerte/pom.xml new file mode 100644 index 0000000..39b2a87 --- /dev/null +++ b/02-udp/udp.messwerte/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + vs + udp.messwerte + 1.0-SNAPSHOT + jar + + + vs + udp + 1.0-SNAPSHOT + + diff --git a/02-udp/udp.messwerte/src/main/java/vs/MesswertClient.java b/02-udp/udp.messwerte/src/main/java/vs/MesswertClient.java new file mode 100644 index 0000000..d4501b3 --- /dev/null +++ b/02-udp/udp.messwerte/src/main/java/vs/MesswertClient.java @@ -0,0 +1,22 @@ +package vs; + +import java.util.Date; +import java.util.Random; + +public class MesswertClient { + + public static void main(String[] args) { + Random rg = new Random(); + try { + // ... + while (true) { + String jetzt = (new Date()).toString(); + String messung = Double.toString(rg.nextDouble() * 100.0); + // ... + Thread.sleep(5000); + } + } catch (Exception e) { + System.err.println(e); + } + } +} diff --git a/02-udp/udp.messwerte/src/main/java/vs/MesswertServer.java b/02-udp/udp.messwerte/src/main/java/vs/MesswertServer.java new file mode 100644 index 0000000..5fc9e36 --- /dev/null +++ b/02-udp/udp.messwerte/src/main/java/vs/MesswertServer.java @@ -0,0 +1,8 @@ +package vs; + +public class MesswertServer { + + public static void main(String[] args) { + // TODO Auto-generated method stub + } +} diff --git a/02-udp/udp.messwerte_solution/justfile b/02-udp/udp.messwerte_solution/justfile new file mode 100644 index 0000000..1e8ebeb --- /dev/null +++ b/02-udp/udp.messwerte_solution/justfile @@ -0,0 +1,6 @@ +import '../justfile' + +server: + just exec vs.MesswertServer "" +client: + just exec vs.MesswertClient "" diff --git a/02-udp/udp.messwerte_solution/pom.xml b/02-udp/udp.messwerte_solution/pom.xml new file mode 100644 index 0000000..b8d43ad --- /dev/null +++ b/02-udp/udp.messwerte_solution/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + vs + udp.messwerte_solution + 1.0-SNAPSHOT + jar + + + vs + udp + 1.0-SNAPSHOT + + diff --git a/02-udp/udp.messwerte_solution/src/main/java/vs/MesswertClient.java b/02-udp/udp.messwerte_solution/src/main/java/vs/MesswertClient.java new file mode 100644 index 0000000..2c54927 --- /dev/null +++ b/02-udp/udp.messwerte_solution/src/main/java/vs/MesswertClient.java @@ -0,0 +1,56 @@ +package vs; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketTimeoutException; +import java.util.Random; + +/** + * Client for var.sockets.udp.messwerte.MesswertServer service. Sendet fortwährend Messwerte + * + * @author Sandro Leuchter + * + */ +public class MesswertClient { + /** + * host on which server is running (IP-address or hostname) + */ + private static final String HOST = "localhost"; + /** + * port on which service is running on host + */ + private static final int PORT = 4713; + /** + * timeout in ms for waiting for a response from server + */ + private static final int TIMEOUT = 2000; + + /** + * main method: entrypoint to run + * + * @param args + * ignored + */ + public static void main(String[] args) { + Random randomGenerator = new Random(); + try (DatagramSocket socket = new DatagramSocket()) { + socket.setSoTimeout(TIMEOUT); // Zeit in ms, für wie lange ein read() auf socket blockiert. + // Bei timeout is java.net.SocketTimeoutException (TIMEOUT == 0 + // => blockiert für immer) + InetAddress iaddr = InetAddress.getByName(HOST); + while (true) { + String messung = Double.toString(randomGenerator.nextDouble() * 100.0); + DatagramPacket packetOut = new DatagramPacket(messung.getBytes(), messung.length(), iaddr, + PORT); + socket.send(packetOut); + Thread.sleep(5000); + } + } catch (SocketTimeoutException e) { + System.err.println("Timeout: " + e.getMessage()); + } catch (Exception e) { + System.err.println(e); + } + } + +} diff --git a/02-udp/udp.messwerte_solution/src/main/java/vs/MesswertServer.java b/02-udp/udp.messwerte_solution/src/main/java/vs/MesswertServer.java new file mode 100644 index 0000000..40e0b8b --- /dev/null +++ b/02-udp/udp.messwerte_solution/src/main/java/vs/MesswertServer.java @@ -0,0 +1,47 @@ +package vs; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.util.Date; + +/** + * Server for var.sockets.udp.messwerte.MesswertServer service. Empfängt Messwerte von Clients und + * gibt sie aus. + * + * @author Sandro Leuchter + * + */ +public class MesswertServer { + /** + * port on which service is running on host + */ + private static final int PORT = 4713; + /** + * maximum size of payload in datagram + */ + private static final int BUFSIZE = 512; + + /** + * main method: entrypoint to run + * + * @param args + * ignored + */ + public static void main(final String[] args) { + try (DatagramSocket socket = new DatagramSocket(PORT)) { + DatagramPacket packetIn = new DatagramPacket(new byte[BUFSIZE], BUFSIZE); + + System.out.println("Server gestartet ..."); + + while (true) { + socket.receive(packetIn); + String jetzt = (new Date()).toString(); + System.out.println(packetIn.getAddress().getHostAddress() + ":" + packetIn.getPort() + " " + + jetzt + " " + new String(packetIn.getData())); + } + } catch (IOException e) { + System.err.println(e); + } + } +} diff --git a/02-udp/udp.time/justfile b/02-udp/udp.time/justfile new file mode 100644 index 0000000..7fedffd --- /dev/null +++ b/02-udp/udp.time/justfile @@ -0,0 +1,6 @@ +import '../justfile' + +server: + just exec vs.TimeServer "" +client: + just exec vs.TimeClient "" diff --git a/02-udp/udp.time/pom.xml b/02-udp/udp.time/pom.xml new file mode 100644 index 0000000..086d35b --- /dev/null +++ b/02-udp/udp.time/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + vs + udp.time + 1.0-SNAPSHOT + jar + + + vs + udp + 1.0-SNAPSHOT + + diff --git a/02-udp/udp.time/src/main/java/vs/TimeClient.java b/02-udp/udp.time/src/main/java/vs/TimeClient.java new file mode 100644 index 0000000..49a9aff --- /dev/null +++ b/02-udp/udp.time/src/main/java/vs/TimeClient.java @@ -0,0 +1,8 @@ +package vs; + +public class TimeClient { + + public static void main(String[] args) { + // TODO Auto-generated method stub + } +} diff --git a/02-udp/udp.time/src/main/java/vs/TimeServer.java b/02-udp/udp.time/src/main/java/vs/TimeServer.java new file mode 100644 index 0000000..0d419f8 --- /dev/null +++ b/02-udp/udp.time/src/main/java/vs/TimeServer.java @@ -0,0 +1,8 @@ +package vs; + +public class TimeServer { + + public static void main(String[] args) { + // TODO Auto-generated method stub + } +} diff --git a/02-udp/udp.time_solution/justfile b/02-udp/udp.time_solution/justfile new file mode 100644 index 0000000..7fedffd --- /dev/null +++ b/02-udp/udp.time_solution/justfile @@ -0,0 +1,6 @@ +import '../justfile' + +server: + just exec vs.TimeServer "" +client: + just exec vs.TimeClient "" diff --git a/02-udp/udp.time_solution/pom.xml b/02-udp/udp.time_solution/pom.xml new file mode 100644 index 0000000..a6d2c80 --- /dev/null +++ b/02-udp/udp.time_solution/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + vs + udp.time_solution + 1.0-SNAPSHOT + jar + + + vs + udp + 1.0-SNAPSHOT + + diff --git a/02-udp/udp.time_solution/src/main/java/vs/TimeClient.java b/02-udp/udp.time_solution/src/main/java/vs/TimeClient.java new file mode 100644 index 0000000..159a46a --- /dev/null +++ b/02-udp/udp.time_solution/src/main/java/vs/TimeClient.java @@ -0,0 +1,57 @@ +package vs; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketTimeoutException; + +/** + * Client for echo var.sockets.udp.time.TimeServer service. Sendet leeres Paket an Server, wartet + * bis TIMEOUT aus Antwort vom Server, liest die Antwort und gibt sie aus + * + * @author Sandro Leuchter + * + */ +public class TimeClient { + /** + * host on which server is running (IP-address or hostname) + */ + private static final String HOST = "localhost"; + /** + * port on which service is running on host + */ + private static final int PORT = 4712; + /** + * maximum size of payload in datagram + */ + private static final int BUFSIZE = 512; + /** + * timeout in ms for waiting for a response from server + */ + private static final int TIMEOUT = 2000; + + /** + * main method: entrypoint to run + * + * @param args + * ignored + */ + public static void main(String[] args) { + try (DatagramSocket socket = new DatagramSocket()) { + socket.setSoTimeout(TIMEOUT); // Zeit in ms, für wie lange ein read() auf socket blockiert. + // Bei timeout is java.net.SocketTimeoutException (TIMEOUT == 0 + // => blockiert für immer) + InetAddress iaddr = InetAddress.getByName(HOST); + DatagramPacket packetOut = new DatagramPacket(new byte[0], 0, iaddr, PORT); + socket.send(packetOut); + DatagramPacket packetIn = new DatagramPacket(new byte[BUFSIZE], BUFSIZE); + socket.receive(packetIn); + String received = new String(packetIn.getData(), 0, packetIn.getLength()); + System.out.println("Received: " + received); + } catch (SocketTimeoutException e) { + System.err.println("Timeout: " + e.getMessage()); + } catch (Exception e) { + System.err.println(e); + } + } +} diff --git a/02-udp/udp.time_solution/src/main/java/vs/TimeServer.java b/02-udp/udp.time_solution/src/main/java/vs/TimeServer.java new file mode 100644 index 0000000..1740631 --- /dev/null +++ b/02-udp/udp.time_solution/src/main/java/vs/TimeServer.java @@ -0,0 +1,53 @@ +package vs; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.util.Date; + +/** + * Server for echo var.sockets.udp.time.TimeServer service. Empfängt Datagramm von Client, liest + * Absenderinformationen daraus und sendet Zeitinformation zurück. + * + * @author Sandro Leuchter + * + */ +public class TimeServer { + /** + * port on which service is running on host + */ + private static final int PORT = 4712; + /** + * maximum size of payload in datagram + */ + private static final int BUFSIZE = 512; + + /** + * main method: entrypoint to run + * + * @param args + * ignored + */ + public static void main(String[] args) { + try (DatagramSocket socket = new DatagramSocket(PORT)) { + DatagramPacket packetIn = new DatagramPacket(new byte[BUFSIZE], BUFSIZE); + DatagramPacket packetOut = new DatagramPacket(new byte[BUFSIZE], BUFSIZE); + + System.out.println("Server gestartet ..."); + + while (true) { + socket.receive(packetIn); + System.out.println( + "Received from: " + packetIn.getAddress().getHostAddress() + ":" + packetIn.getPort()); + String jetzt = (new Date()).toString(); + packetOut.setData(jetzt.getBytes()); + packetOut.setLength(jetzt.length()); + packetOut.setSocketAddress(packetIn.getSocketAddress()); + socket.send(packetOut); + } + } catch (final IOException e) { + System.err.println(e); + } + } + +} diff --git a/03-tcp/justfile b/03-tcp/justfile new file mode 100644 index 0000000..ad5bd2f --- /dev/null +++ b/03-tcp/justfile @@ -0,0 +1,4 @@ +import '../justfile' + +zed: + $VISUAL tcp.echo tcp.echo_solution tcp.filer tcp.filer_solution tcp.time tcp.time_solution diff --git a/03-tcp/pom.xml b/03-tcp/pom.xml new file mode 100644 index 0000000..bc444a2 --- /dev/null +++ b/03-tcp/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + vs + tcp + 1.0-SNAPSHOT + pom + + + vs + parent + 1.0-SNAPSHOT + + + diff --git a/03-tcp/tcp.code-workspace b/03-tcp/tcp.code-workspace new file mode 100644 index 0000000..a4d330c --- /dev/null +++ b/03-tcp/tcp.code-workspace @@ -0,0 +1,39 @@ +{ + "folders": [ + { + "name": "1. Echo Service", + "path": "tcp.echo", + }, + { + "name": "1. Echo Service (ML)", + "path": "tcp.echo_solution", + }, + { + "name": "2. File Service", + "path": "tcp.filer", + }, + { + "name": "2. File Service (ML)", + "path": "tcp.filer_solution", + }, + { + "name": "3. Time Service", + "path": "tcp.time", + }, + { + "name": "3. Time Service (ML)", + "path": "tcp.time_solution", + }, + ], + "extensions": { + "recommendations": [ + "vscjava.vscode-java-pack", + "ms-azuretools.vscode-docker", + "skellock.just", + ], + }, + "settings": { + "java.dependency.syncWithFolderExplorer": true, + "java.project.explorer.showNonJavaResources": false, + }, +} diff --git a/03-tcp/tcp.echo/justfile b/03-tcp/tcp.echo/justfile new file mode 100644 index 0000000..6284451 --- /dev/null +++ b/03-tcp/tcp.echo/justfile @@ -0,0 +1,11 @@ +import '../justfile' + +port := "4747" + +server-iterativ backlog_size: + just exec vs.EchoServerIterativ "{{port}} {{backlog_size}}" +server-threaded: + just exec vs.EchoServerThreaded {{port}} +client host: + just exec vs.EchoClient "{{host}} {{port}}" + diff --git a/03-tcp/tcp.echo/pom.xml b/03-tcp/tcp.echo/pom.xml new file mode 100644 index 0000000..decc71a --- /dev/null +++ b/03-tcp/tcp.echo/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + vs + tcp.echo + 1.0-SNAPSHOT + jar + + + vs + tcp + 1.0-SNAPSHOT + + diff --git a/03-tcp/tcp.echo/src/main/java/vs/EchoClient.java b/03-tcp/tcp.echo/src/main/java/vs/EchoClient.java new file mode 100644 index 0000000..690c196 --- /dev/null +++ b/03-tcp/tcp.echo/src/main/java/vs/EchoClient.java @@ -0,0 +1,37 @@ +package vs; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.Socket; + +public class EchoClient { + public static void main(String[] args) { + String host = args[0]; + int port = Integer.parseInt(args[1]); + + try (Socket socket = new Socket(host, port); + BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + PrintWriter out = new PrintWriter(socket.getOutputStream(), true); + BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in))) { + + // Begrüßung vom Server empfangen und auf Konsole ausgeben + String msg = in.readLine(); + System.out.println(msg); + + // Zeile von Konsole einlesen, an Server senden und Antwort von + // Server auf Konsole ausgeben, bis eingegebene Zeile == "q" + while (true) { + System.out.print(">> "); + String line = stdin.readLine(); + if ("q".equals(line)) { + break; + } + out.println(line); + System.out.println(in.readLine()); + } + } catch (Exception e) { + System.err.println(e); + } + } +} diff --git a/03-tcp/tcp.echo/src/main/java/vs/EchoServerIterativ.java b/03-tcp/tcp.echo/src/main/java/vs/EchoServerIterativ.java new file mode 100644 index 0000000..7e60198 --- /dev/null +++ b/03-tcp/tcp.echo/src/main/java/vs/EchoServerIterativ.java @@ -0,0 +1,60 @@ +package vs; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; + +public class EchoServerIterativ { + private int port; + private int backlog; + + public EchoServerIterativ(int port, int backlog) { + this.port = port; + this.backlog = backlog; + } + + public void start() { + try (ServerSocket serverSocket = new ServerSocket(port, backlog)) { + System.out.println("EchoServer (iterativ) auf " + serverSocket.getLocalSocketAddress() + " gestartet ..."); + while (true) { + handleClient(serverSocket); + } + } catch (IOException e) { + System.err.println(e); + } + } + + private void handleClient(ServerSocket server) { + SocketAddress socketAddress = null; + try (Socket socket = server.accept(); + BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) { + socketAddress = socket.getRemoteSocketAddress(); + System.out.println("Verbindung zu " + socketAddress + " aufgebaut"); + out.println("Server ist bereit ..."); + String input; + while ((input = in.readLine()) != null) { + System.out.println(socketAddress + ">> [" + input + "]"); + out.println("echo: " + input); + } + } catch (IOException e) { + System.err.println(e); + } finally { + System.out.println("Verbindung zu " + socketAddress + " abgebaut"); + } + } + + public static void main(String[] args) { + int port = Integer.parseInt(args[0]); + int backlog = 50; + if (args.length == 2) { + backlog = Integer.parseInt(args[1]); + } + + new EchoServerIterativ(port, backlog).start(); + } +} diff --git a/03-tcp/tcp.echo/src/main/java/vs/EchoServerThreaded.java b/03-tcp/tcp.echo/src/main/java/vs/EchoServerThreaded.java new file mode 100644 index 0000000..cb585c6 --- /dev/null +++ b/03-tcp/tcp.echo/src/main/java/vs/EchoServerThreaded.java @@ -0,0 +1,41 @@ +package vs; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + +public class EchoServerThreaded { + private int port; + + public EchoServerThreaded(int port) { + this.port = port; + } + + public void start() { + try (ServerSocket serverSocket = new ServerSocket(port)) { + System.out.println("EchoServer (threaded) auf " + serverSocket.getLocalSocketAddress() + " gestartet ..."); + // hier müssen Verbindungswünsche von Clients in einem neuen Thread + // angenommen werden + } catch (IOException e) { + System.err.println(e); + } + } + + private class EchoThread extends Thread { + private Socket socket; + + public EchoThread(Socket socket) { + this.socket = socket; + } + + public void run() { + // hier muss die Verbindung mit dem Client über this.socket + // abgearbeitet werden + } + } + + public static void main(String[] args) { + int port = Integer.parseInt(args[0]); + new EchoServerThreaded(port).start(); + } +} diff --git a/03-tcp/tcp.echo_solution/justfile b/03-tcp/tcp.echo_solution/justfile new file mode 100644 index 0000000..6255554 --- /dev/null +++ b/03-tcp/tcp.echo_solution/justfile @@ -0,0 +1,13 @@ +import '../justfile' + +port := "4747" + +server-iterativ backlog_size: + just exec vs.EchoServerIterativ "{{port}} {{backlog_size}}" +server-threaded: + just exec vs.EchoServerThreaded {{port}} +server-pool: + just exec vs.EchoServerThreadPool {{port}} +client host: + just exec vs.EchoClient "{{host}} {{port}}" + diff --git a/03-tcp/tcp.echo_solution/pom.xml b/03-tcp/tcp.echo_solution/pom.xml new file mode 100644 index 0000000..133a856 --- /dev/null +++ b/03-tcp/tcp.echo_solution/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + vs + tcp.echo_solution + 1.0-SNAPSHOT + jar + + + vs + tcp + 1.0-SNAPSHOT + + diff --git a/03-tcp/tcp.echo_solution/src/main/java/vs/EchoClient.java b/03-tcp/tcp.echo_solution/src/main/java/vs/EchoClient.java new file mode 100644 index 0000000..b7f69b2 --- /dev/null +++ b/03-tcp/tcp.echo_solution/src/main/java/vs/EchoClient.java @@ -0,0 +1,53 @@ +package vs; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.Socket; + +/** + * Client for echo var.sockets.tcp.echo.EchoServer* service. Liest zeilenweise + * von der Console und sendet zum Server. Der Server sendet eine Zeichenkette + * zurück, die auf der Konsole ausgegeben wird. + * + * @author Sandro Leuchter + * + */ +public class EchoClient { + + /** + * main method: entrypoint to run + * + * @param args address of service to connect to (must be String[0]: host + * (IP-address or DNS hostname), String[1]: port) + * + */ + public static void main(String[] args) { + String host = args[0]; + int port = Integer.parseInt(args[1]); + + try (Socket socket = new Socket(host, port); + BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + PrintWriter out = new PrintWriter(socket.getOutputStream(), true); + BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in))) { + + // Begrüßung vom Server empfangen und auf Konsole ausgeben + String msg = in.readLine(); + System.out.println(msg); + + // Zeile von Konsole einlesen, an Server senden und Antwort von + // Server auf Konsole ausgeben, bis eingegebene Zeile == "q" + while (true) { + System.out.print(">> "); + String line = stdin.readLine(); + if ("q".equals(line)) { + break; + } + out.println(line); + System.out.println(in.readLine()); + } + } catch (Exception e) { + System.err.println(e); + } + } +} diff --git a/03-tcp/tcp.echo_solution/src/main/java/vs/EchoServerIterativ.java b/03-tcp/tcp.echo_solution/src/main/java/vs/EchoServerIterativ.java new file mode 100644 index 0000000..a422816 --- /dev/null +++ b/03-tcp/tcp.echo_solution/src/main/java/vs/EchoServerIterativ.java @@ -0,0 +1,98 @@ +package vs; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; + +/** + * iterative server for var.sockets.tcp.echo Echo service. waits for the next + * client to connect, sends greeting message to client, reads line by line from + * client and sends it back adding "echo: " in front of each line until + * connection is closed by client. + * + * @author Sandro Leuchter + * + */ +public class EchoServerIterativ { + /** + * port on which this service is currently listening on localhost + */ + private final int port; + /** + * current maximum length of the queue of incoming connections. + */ + private final int backlog; + + /** + * the only constructor for this class + * + * @param port port on which this service will be listening on localhost + * @param backlog requested maximum length of the queue of incoming connections. + */ + public EchoServerIterativ(int port, int backlog) { + this.port = port; + this.backlog = backlog; + } + + /** + * creates server socket on localhost:port, infinitely handles connections to + * clients one after another + */ + public void start() { + try (ServerSocket serverSocket = new ServerSocket(this.port, this.backlog)) { + System.out.println("EchoServer (iterativ) auf " + serverSocket.getLocalSocketAddress() + " gestartet ..."); + while (true) { + handleClient(serverSocket); + } + } catch (IOException e) { + System.err.println(e); + } + } + + /** + * waits for the next client to connect to server, sends greeting message to + * client, reads line by line from client and sends it back adding "echo: " in + * front of each line until connection is closed by client. + * + * @param server "welcome socket" on which server is listening for clients + */ + private void handleClient(ServerSocket server) { + SocketAddress socketAddress = null; + try (Socket socket = server.accept(); + BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) { + socketAddress = socket.getRemoteSocketAddress(); + System.out.println("Verbindung zu " + socketAddress + " aufgebaut"); + out.println("Server ist bereit ..."); + String input; + while ((input = in.readLine()) != null) { + System.out.println(socketAddress + ">> [" + input + "]"); + out.println("echo: " + input); + } + } catch (IOException e) { + System.err.println(e); + } finally { + System.out.println("Verbindung zu " + socketAddress + " abgebaut"); + } + } + + /** + * main method: entrypoint to run service + * + * @param args args[0] must be the port number of the server (int); rest of args + * is ignored + */ + public static void main(String[] args) { + int port = Integer.parseInt(args[0]); + int backlog = 50; + if (args.length == 2) { + backlog = Integer.parseInt(args[1]); + } + + new EchoServerIterativ(port, backlog).start(); + } +} diff --git a/03-tcp/tcp.echo_solution/src/main/java/vs/EchoServerThreadPool.java b/03-tcp/tcp.echo_solution/src/main/java/vs/EchoServerThreadPool.java new file mode 100644 index 0000000..062f9d2 --- /dev/null +++ b/03-tcp/tcp.echo_solution/src/main/java/vs/EchoServerThreadPool.java @@ -0,0 +1,115 @@ +package vs; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +/** + * threaded server for var.sockets.tcp.echo Echo service. waits for the next + * client to connect, creates thread and handles connection in concurrently: + * sends greeting message to client, reads line by line from client and sends it + * back adding "echo: " in front of each line until connection is closed by + * client. + * + * @author Sandro Leuchter + * + */ +public class EchoServerThreadPool { + /** + * port on which this service is currently listening on localhost + */ + private final int port; + /** + * thread pool of this server + */ + private final Executor threadPool; + + /** + * the only constructor for this class + * + * @param port port on which this service will be listening on localhost + */ + public EchoServerThreadPool(int port) { + this.port = port; + // threadPool = Executors.newSingleThreadExecutor(); + // threadPool = Executors.newCachedThreadPool(); + this.threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2); + } + + /** + * creates server socket on localhost:port, infinitely handles connections to + * clients concurrently + */ + public void start() { + try (ServerSocket serverSocket = new ServerSocket(this.port)) { + System.out.println("EchoServer (threaded) auf " + serverSocket.getLocalSocketAddress() + " gestartet ..."); + while (true) { + Socket socket = serverSocket.accept(); + this.threadPool.execute(new EchoThread(socket)); + } + } catch (IOException e) { + System.err.println(e); + } + } + + /** + * Each connection is handled with an instance of this class. + */ + private class EchoThread implements Runnable { + /** + * TCP connection to client + */ + private final Socket socket; + + /** + * the only constructor for this class + * + * @param socket the individual socket that the server created on accepting a + * client that this EchoThread instance will be communicating with + */ + public EchoThread(Socket socket) { + this.socket = socket; + } + + /** + * defines the behavior of this Thread instance, will be executed concurrently + * if start() is called on instance + * + */ + @Override + public void run() { + SocketAddress socketAddress = this.socket.getRemoteSocketAddress(); + System.out.println("Verbindung zu " + socketAddress + " aufgebaut"); + try (BufferedReader in = new BufferedReader(new InputStreamReader(this.socket.getInputStream())); + PrintWriter out = new PrintWriter(this.socket.getOutputStream(), true)) { + out.println("Server ist bereit ..."); + String input; + while ((input = in.readLine()) != null) { + System.out.println(socketAddress + ">> [" + input + "]"); + out.println("echo: " + input); + } + } catch (Exception e) { + System.err.println(e); + } finally { + System.out.println("Verbindung zu " + socketAddress + " abgebaut"); + } + } + } + + /** + * main method: entrypoint to run service + * + * @param args args[0] must be the port number of the server (int); rest of args + * is ignored + */ + public static void main(String[] args) { + int port = Integer.parseInt(args[0]); + new EchoServerThreadPool(port).start(); + } +} diff --git a/03-tcp/tcp.echo_solution/src/main/java/vs/EchoServerThreaded.java b/03-tcp/tcp.echo_solution/src/main/java/vs/EchoServerThreaded.java new file mode 100644 index 0000000..990e234 --- /dev/null +++ b/03-tcp/tcp.echo_solution/src/main/java/vs/EchoServerThreaded.java @@ -0,0 +1,106 @@ +package vs; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; + +/** + * threaded server for var.sockets.tcp.echo Echo service. waits for the next + * client to connect, creates thread and handles connection in concurrently: + * sends greeting message to client, reads line by line from client and sends it + * back adding "echo: " in front of each line until connection is closed by + * client. + * + * @author Sandro Leuchter + * + */ +public class EchoServerThreaded { + /** + * port on which this service is currently listening on localhost + */ + private final int port; + + /** + * the only constructor for this class + * + * @param port port on which this service will be listening on localhost + */ + public EchoServerThreaded(int port) { + this.port = port; + } + + /** + * creates server socket on localhost:port, infinitely handles connections to + * clients concurrently + */ + public void start() { + try (ServerSocket serverSocket = new ServerSocket(this.port)) { + System.out.println("EchoServer (threaded) auf " + serverSocket.getLocalSocketAddress() + " gestartet ..."); + while (true) { + Socket socket = serverSocket.accept(); + new EchoThread(socket).start(); + } + } catch (IOException e) { + System.err.println(e); + } + } + + /** + * Each connection is handled with an instance of this class. + */ + private class EchoThread extends Thread { + /** + * TCP connection to client + */ + private final Socket socket; + + /** + * the only constructor for this class + * + * @param socket the individual socket that the server created on accepting a + * client that this EchoThread instance will be communicating with + */ + public EchoThread(Socket socket) { + this.socket = socket; + } + + /** + * defines the behavior of this Thread instance, will be executed concurrently + * if start() is called on instance + * + */ + @Override + public void run() { + SocketAddress socketAddress = this.socket.getRemoteSocketAddress(); + System.out.println("Verbindung zu " + socketAddress + " aufgebaut"); + try (BufferedReader in = new BufferedReader(new InputStreamReader(this.socket.getInputStream())); + PrintWriter out = new PrintWriter(this.socket.getOutputStream(), true)) { + out.println("Server ist bereit ..."); + String input; + while ((input = in.readLine()) != null) { + System.out.println(socketAddress + ">> [" + input + "]"); + out.println("echo: " + input); + } + } catch (Exception e) { + System.err.println(e); + } finally { + System.out.println("Verbindung zu " + socketAddress + " abgebaut"); + } + } + } + + /** + * main method: entrypoint to run service + * + * @param args args[0] must be the port number of the server (int); rest of args + * is ignored + */ + public static void main(String[] args) { + int port = Integer.parseInt(args[0]); + new EchoServerThreaded(port).start(); + } +} diff --git a/03-tcp/tcp.filer/justfile b/03-tcp/tcp.filer/justfile new file mode 100644 index 0000000..d9c06d8 --- /dev/null +++ b/03-tcp/tcp.filer/justfile @@ -0,0 +1,10 @@ +import '../justfile' + +port := "4747" + +server-iterativ backlog_size: + just exec vs.FileServerIterativ "{{port}} {{backlog_size}}" +server-threaded: + just exec vs.FileServerThreaded {{port}} +client host: + just exec vs.FileClient "{{host}} {{port}}" diff --git a/03-tcp/tcp.filer/pom.xml b/03-tcp/tcp.filer/pom.xml new file mode 100644 index 0000000..ce9311f --- /dev/null +++ b/03-tcp/tcp.filer/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + vs + tcp.filer + 1.0-SNAPSHOT + jar + + + vs + tcp + 1.0-SNAPSHOT + + diff --git a/03-tcp/tcp.filer/src/main/java/vs/FileClient.java b/03-tcp/tcp.filer/src/main/java/vs/FileClient.java new file mode 100644 index 0000000..18697e5 --- /dev/null +++ b/03-tcp/tcp.filer/src/main/java/vs/FileClient.java @@ -0,0 +1,22 @@ +package vs; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.Socket; + +public class FileClient { + public static void main(String[] args) { + String host = args[0]; + int port = Integer.parseInt(args[1]); + + try (Socket socket = new Socket(host, port); + BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) { + String line; + while ((line = in.readLine()) != null) { + System.out.println(line); + } + } catch (Exception e) { + System.err.println(e); + } + } +} diff --git a/03-tcp/tcp.filer/src/main/java/vs/FileServerIterativ.java b/03-tcp/tcp.filer/src/main/java/vs/FileServerIterativ.java new file mode 100644 index 0000000..00f816c --- /dev/null +++ b/03-tcp/tcp.filer/src/main/java/vs/FileServerIterativ.java @@ -0,0 +1,61 @@ +package vs; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; + +public class FileServerIterativ { + private static final String FILE = "target/classes/message.txt"; + private int port; + private int backlog; + + public FileServerIterativ(int port, int backlog) { + this.port = port; + this.backlog = backlog; + } + + public void start() { + try (ServerSocket serverSocket = new ServerSocket(port, backlog)) { + System.out.println("FileServer (iterativ) auf " + serverSocket.getLocalSocketAddress() + " gestartet ..."); + File file = new File(FILE); + if (file.exists()) { + System.out.println("\"" + file.getAbsolutePath() + "\" soll gesendet werden."); + while (true) { + handleClient(serverSocket); + } + } + } catch (IOException e) { + System.err.println(e); + } + } + + private void handleClient(ServerSocket server) { + SocketAddress socketAddress = null; + try (Socket socket = server.accept(); + BufferedReader in = new BufferedReader(new FileReader(FILE)); + PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) { + socketAddress = socket.getRemoteSocketAddress(); + System.out.println("Verbindung zu " + socketAddress + " aufgebaut"); + // Inhalt von in zeilenweise an out senden + } catch (IOException e) { + System.err.println(e); + } finally { + System.out.println("Verbindung zu " + socketAddress + " abgebaut"); + } + } + + public static void main(String[] args) { + int port = Integer.parseInt(args[0]); + int backlog = 50; + if (args.length == 2) { + backlog = Integer.parseInt(args[1]); + } + + new FileServerIterativ(port, backlog).start(); + } +} diff --git a/03-tcp/tcp.filer/src/main/java/vs/FileServerThreaded.java b/03-tcp/tcp.filer/src/main/java/vs/FileServerThreaded.java new file mode 100644 index 0000000..e2883e0 --- /dev/null +++ b/03-tcp/tcp.filer/src/main/java/vs/FileServerThreaded.java @@ -0,0 +1,49 @@ +package vs; + +import java.io.File; +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + +public class FileServerThreaded { + private static final String FILE = "target/classes/message.txt"; + private int port; + + public FileServerThreaded(int port) { + this.port = port; + } + + public void start() { + try (ServerSocket serverSocket = new ServerSocket(port)) { + System.out.println("FileServer (threaded) auf " + serverSocket.getLocalSocketAddress() + " gestartet ..."); + File file = new File(FILE); + if (file.exists()) { + System.out.println("\"" + file.getAbsolutePath() + "\" soll gesendet werden."); + while (true) { + // hier müssen Verbindungswünsche von Clients in einem neuen + // Thread angenommen werden + } + } + } catch (IOException e) { + System.err.println(e); + } + } + + private class FileThread extends Thread { + private Socket socket; + + public FileThread(Socket socket) { + this.socket = socket; + } + + public void run() { + // hier muss die Verbindung mit dem Client über this.socket + // abgearbeitet werden + } + } + + public static void main(String[] args) { + int port = Integer.parseInt(args[0]); + new FileServerThreaded(port).start(); + } +} diff --git a/03-tcp/tcp.filer/src/main/resources/message.txt b/03-tcp/tcp.filer/src/main/resources/message.txt new file mode 100644 index 0000000..8f8b45d --- /dev/null +++ b/03-tcp/tcp.filer/src/main/resources/message.txt @@ -0,0 +1,25 @@ +Mannheimer Mittelstandsmesse 2017 +================================= + +Zum zehnten Mal lädt die Hochschule Mannheim zur Mittelstandsmesse (MaMi) ein. 14 Unternehmen, +die sich beim Mannheimer Modell Mittelstands-Stipendien engagieren, präsentierten sich in +der Aula der Hochschule + +Studierende der Hochschule haben am 04.04.2017 von 12.00 – 16.00 Uhr wieder die Gelegenheit, +Kontakte zu mittelständischen Unternehmen der Metropolregion zu knüpfen, Möglichkeiten für +Praktika auszuloten oder mit Personalverantwortlichen über Stellenangebote zu sprechen. Auch +für Lehrende und Forschende ist die Messe eine gute Gelegenheit, mit interessierten Unternehmen +Kooperationen anzubahnen oder zu vertiefen. + +Ziel der Messe ist, die Sichtbarkeit von mittelständischen Unternehmen in der Metropolregion +Rhein-Neckar zu erhöhen und Hochschulabsolventen die Attraktivität einer beruflichen Karriere +insbesondere im Mittelstand deutlich zu machen. Mittelständische Unternehmen prägen die +Wirtschaftsstruktur in Deutschland. 99 Prozent aller Unternehmen werden den mittelständischen +Unternehmen zugerechnet, sie beschäftigen rund 2/3 aller Erwerbstätigen. + +Parallel zur Eröffnung der MaMi wird auch die Förderrunde 2017/18 für die Mannheimer +Mittelstands-Stipendien ausgeschrieben. Durch das seit 2007 etablierte Stipendienmodell, das +in tatkräftiger Kooperation der Hochschule mit mittelständischen Unternehmen und unterstützt +von der Metropolregion Rhein-Neckar ins Leben gerufen wurde, können im Studienjahr 30-40 +Stipendien in Höhe von je 1.000 € vergeben werden. So ist die MaMi auch eine gute Gelegenheit +für Studierende, sich an den Ständen der Unternehmen als potenzielle Stipendiaten zu präsentieren. diff --git a/03-tcp/tcp.filer_solution/justfile b/03-tcp/tcp.filer_solution/justfile new file mode 100644 index 0000000..6ea8821 --- /dev/null +++ b/03-tcp/tcp.filer_solution/justfile @@ -0,0 +1,12 @@ +import '../justfile' + +port := "4747" + +server-iterativ backlog_size: + just exec vs.FileServerIterativ "{{port}} {{backlog_size}}" +server-threaded: + just exec vs.FileServerThreaded {{port}} +server-pool: + just exec vs.FileServerThreadPool {{port}} +client host: + just exec vs.FileClient "{{host}} {{port}}" diff --git a/03-tcp/tcp.filer_solution/pom.xml b/03-tcp/tcp.filer_solution/pom.xml new file mode 100644 index 0000000..a67ee1a --- /dev/null +++ b/03-tcp/tcp.filer_solution/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + vs + tcp.filer_solution + 1.0-SNAPSHOT + jar + + + vs + tcp + 1.0-SNAPSHOT + + diff --git a/03-tcp/tcp.filer_solution/src/main/java/vs/FileClient.java b/03-tcp/tcp.filer_solution/src/main/java/vs/FileClient.java new file mode 100644 index 0000000..c6b18b6 --- /dev/null +++ b/03-tcp/tcp.filer_solution/src/main/java/vs/FileClient.java @@ -0,0 +1,39 @@ +package vs; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.Socket; + +/** + * Client for echo var.sockets.tcp.filer.FileServer* service. Verbindet sich mit + * Server, empfängt dann zeilenweise vom Server und gibt auf der Konsole aus, + * was empfangen wurde. Empfängt und gibt so lange aus, bis der Server die + * Kommunikation beendet und den Socket schließt. + * + * @author Sandro Leuchter + * + */ +public class FileClient { + + /** + * main method: entrypoint to run + * + * @param args address of service to connect to (must be String[0]: host + * (IP-address or DNS hostname), String[1]: port) + * + */ + public static void main(String[] args) { + String host = args[0]; + int port = Integer.parseInt(args[1]); + + try (Socket socket = new Socket(host, port); + BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) { + String line; + while ((line = in.readLine()) != null) { + System.out.println(line); + } + } catch (Exception e) { + System.err.println(e); + } + } +} diff --git a/03-tcp/tcp.filer_solution/src/main/java/vs/FileServerIterativ.java b/03-tcp/tcp.filer_solution/src/main/java/vs/FileServerIterativ.java new file mode 100644 index 0000000..c867759 --- /dev/null +++ b/03-tcp/tcp.filer_solution/src/main/java/vs/FileServerIterativ.java @@ -0,0 +1,109 @@ +package vs; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; + +/** + * iterative server for var.sockets.tcp.filer File service. waits for the next + * client to connect. Upon connection sends a manually defined file back to + * client. closes the connection directly afterwards and handles then next + * client + * + * @author Sandro Leuchter + * + */ +public class FileServerIterativ { + /** + * path to file which will be sent to clients; relative to current working + * directory (e.g. project root) + */ + private static final String FILE = "target/classes/message.txt"; + /** + * port on which this service is currently listening on localhost + */ + private final int port; + /** + * requested maximum length of the queue of incoming connections. + */ + private final int backlog; + + /** + * the only constructor for this class + * + * @param port port on which this service will be listening on localhost + * @param backlog requested maximum length of the queue of incoming connections. + */ + public FileServerIterativ(int port, int backlog) { + this.port = port; + this.backlog = backlog; + } + + /** + * creates server socket on localhost:port, infinitely handles connections to + * clients one after another + */ + public void start() { + try (ServerSocket serverSocket = new ServerSocket(this.port, this.backlog)) { + System.out.println("FileServer (iterativ) auf " + serverSocket.getLocalSocketAddress() + " gestartet ..."); + File file = new File(FILE); + if (file.exists()) { + System.out.println("\"" + file.getAbsolutePath() + "\" soll gesendet werden."); + while (true) { + handleClient(serverSocket); + } + } + } catch (IOException e) { + System.err.println(e); + } + } + + /** + * waits for the next client to connect. Upon connection sends a manually + * defined file back to client. closes the connection directly afterwards and + * handles then next client + * + * @param server "welcome socket" on which server is listening for clients + */ + private void handleClient(ServerSocket server) { + SocketAddress socketAddress = null; + try (Socket socket = server.accept(); + BufferedReader in = new BufferedReader(new FileReader(FILE)); + PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) { + socketAddress = socket.getRemoteSocketAddress(); + System.out.println("Verbindung zu " + socketAddress + " aufgebaut"); + // Inhalt von in zeilenweise an out senden: + System.out.println("Übertragung zu " + socketAddress + " begonnen"); + String input; + while ((input = in.readLine()) != null) { + out.println(input); + } + System.out.println("Übertragung zu " + socketAddress + " beendet"); + } catch (IOException e) { + System.err.println(e); + } finally { + System.out.println("Verbindung zu " + socketAddress + " abgebaut"); + } + } + + /** + * main method: entrypoint to run service + * + * @param args args[0] must be the port number of the server (int); rest of args + * is ignored + */ + public static void main(String[] args) { + int port = Integer.parseInt(args[0]); + int backlog = 50; + if (args.length == 2) { + backlog = Integer.parseInt(args[1]); + } + + new FileServerIterativ(port, backlog).start(); + } +} diff --git a/03-tcp/tcp.filer_solution/src/main/java/vs/FileServerThreadPool.java b/03-tcp/tcp.filer_solution/src/main/java/vs/FileServerThreadPool.java new file mode 100644 index 0000000..d87474c --- /dev/null +++ b/03-tcp/tcp.filer_solution/src/main/java/vs/FileServerThreadPool.java @@ -0,0 +1,128 @@ +package vs; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +/** + * threaded server for var.sockets.tcp.filer File service. waits for clients to + * connect. Upon connection sends concurrently to other client connections a + * manually defined file back to client. closes the connection directly + * afterwards. + * + * @author Sandro Leuchter + * + */ +public class FileServerThreadPool { + /** + * path to file which will be sent to clients; relative to current working + * directory (e.g. project root) + */ + private static final String FILE = "target/classes/message.txt"; + /** + * port on which this service is currently listening on localhost + */ + private final int port; + /** + * thread pool of this server + */ + private final Executor threadPool; + + /** + * the only constructor for this class + * + * @param port port on which this service will be listening on localhost + */ + public FileServerThreadPool(int port) { + this.port = port; + this.threadPool = Executors.newSingleThreadExecutor(); + // threadPool = Executors.newCachedThreadPool(); + // threadPool = + // Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*2); + } + + /** + * creates server socket on localhost:port, infinitely handles connections to + * clients concurrently + */ + public void start() { + try (ServerSocket serverSocket = new ServerSocket(this.port)) { + System.out.println("FileServer (threaded) auf " + serverSocket.getLocalSocketAddress() + " gestartet ..."); + File file = new File(FILE); + if (file.exists()) { + System.out.println("\"" + file.getAbsolutePath() + "\" soll gesendet werden."); + while (true) { + Socket socket = serverSocket.accept(); + this.threadPool.execute(new FileThread(socket)); + } + } + } catch (IOException e) { + System.err.println(e); + } + } + + /** + * Each connection is handled with an instance of this class. + */ + private class FileThread implements Runnable { + /** + * TCP connection to client + */ + private final Socket socket; + + /** + * the only constructor for this class + * + * @param socket the individual socket that the server created on accepting a + * client that this EchoThread instance will be communicating with + */ + public FileThread(Socket socket) { + this.socket = socket; + } + + /** + * defines the behavior of this Thread instance, will be executed concurrently + * if start() is called on instance + * + */ + @Override + public void run() { + SocketAddress socketAddress = null; + try (BufferedReader in = new BufferedReader(new FileReader(FILE)); + PrintWriter out = new PrintWriter(this.socket.getOutputStream(), true)) { + socketAddress = this.socket.getRemoteSocketAddress(); + System.out.println("Verbindung zu " + socketAddress + " aufgebaut"); + // Inhalt von in zeilenweise an out senden: + System.out.println("Übertragung zu " + socketAddress + " begonnen"); + String input; + while ((input = in.readLine()) != null) { + out.println(input); + // Thread.sleep(1000); + } + System.out.println("Übertragung zu " + socketAddress + " beendet"); + } catch (Exception e) { + System.err.println(e); + } finally { + System.out.println("Verbindung zu " + socketAddress + " abgebaut"); + } + } + } + + /** + * main method: entrypoint to run service + * + * @param args args[0] must be the port number of the server (int); rest of args + * is ignored + */ + public static void main(String[] args) { + int port = Integer.parseInt(args[0]); + new FileServerThreadPool(port).start(); + } +} diff --git a/03-tcp/tcp.filer_solution/src/main/java/vs/FileServerThreaded.java b/03-tcp/tcp.filer_solution/src/main/java/vs/FileServerThreaded.java new file mode 100644 index 0000000..9bd946a --- /dev/null +++ b/03-tcp/tcp.filer_solution/src/main/java/vs/FileServerThreaded.java @@ -0,0 +1,118 @@ +package vs; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; + +/** + * threaded server for var.sockets.tcp.filer File service. waits for clients to + * connect. Upon connection sends concurrently to other client connections a + * manually defined file back to client. closes the connection directly + * afterwards. + * + * @author Sandro Leuchter + * + */ +public class FileServerThreaded { + /** + * path to file which will be sent to clients; relative to current working + * directory (e.g. project root) + */ + private static final String FILE = "target/classes/message.txt"; + /** + * port on which this service is currently listening on localhost + */ + private final int port; + + /** + * the only constructor for this class + * + * @param port port on which this service will be listening on localhost + */ + public FileServerThreaded(int port) { + this.port = port; + } + + /** + * creates server socket on localhost:port, infinitely handles connections to + * clients concurrently + */ + public void start() { + try (ServerSocket serverSocket = new ServerSocket(this.port)) { + System.out.println("FileServer (threaded) auf " + serverSocket.getLocalSocketAddress() + " gestartet ..."); + File file = new File(FILE); + if (file.exists()) { + System.out.println("\"" + file.getAbsolutePath() + "\" soll gesendet werden."); + while (true) { + Socket socket = serverSocket.accept(); + new FileThread(socket).start(); + } + } + } catch (IOException e) { + System.err.println(e); + } + } + + /** + * Each connection is handled with an instance of this class. + */ + private class FileThread extends Thread { + /** + * TCP connection to client + */ + private final Socket socket; + + /** + * the only constructor for this class + * + * @param socket the individual socket that the server created on accepting a + * client that this EchoThread instance will be communicating with + */ + public FileThread(Socket socket) { + this.socket = socket; + } + + /** + * defines the behavior of this Thread instance, will be executed concurrently + * if start() is called on instance + * + */ + @Override + public void run() { + SocketAddress socketAddress = null; + try (BufferedReader in = new BufferedReader(new FileReader(FILE)); + PrintWriter out = new PrintWriter(this.socket.getOutputStream(), true)) { + socketAddress = this.socket.getRemoteSocketAddress(); + System.out.println("Verbindung zu " + socketAddress + " aufgebaut"); + // Inhalt von in zeilenweise an out senden: + System.out.println("Übertragung zu " + socketAddress + " begonnen"); + String input; + while ((input = in.readLine()) != null) { + out.println(input); + // Thread.sleep(1000); + } + System.out.println("Übertragung zu " + socketAddress + " beendet"); + } catch (Exception e) { + System.err.println(e); + } finally { + System.out.println("Verbindung zu " + socketAddress + " abgebaut"); + } + } + } + + /** + * main method: entrypoint to run service + * + * @param args args[0] must be the port number of the server (int); rest of args + * is ignored + */ + public static void main(String[] args) { + int port = Integer.parseInt(args[0]); + new FileServerThreaded(port).start(); + } +} diff --git a/03-tcp/tcp.filer_solution/src/main/resources/message.txt b/03-tcp/tcp.filer_solution/src/main/resources/message.txt new file mode 100644 index 0000000..8f8b45d --- /dev/null +++ b/03-tcp/tcp.filer_solution/src/main/resources/message.txt @@ -0,0 +1,25 @@ +Mannheimer Mittelstandsmesse 2017 +================================= + +Zum zehnten Mal lädt die Hochschule Mannheim zur Mittelstandsmesse (MaMi) ein. 14 Unternehmen, +die sich beim Mannheimer Modell Mittelstands-Stipendien engagieren, präsentierten sich in +der Aula der Hochschule + +Studierende der Hochschule haben am 04.04.2017 von 12.00 – 16.00 Uhr wieder die Gelegenheit, +Kontakte zu mittelständischen Unternehmen der Metropolregion zu knüpfen, Möglichkeiten für +Praktika auszuloten oder mit Personalverantwortlichen über Stellenangebote zu sprechen. Auch +für Lehrende und Forschende ist die Messe eine gute Gelegenheit, mit interessierten Unternehmen +Kooperationen anzubahnen oder zu vertiefen. + +Ziel der Messe ist, die Sichtbarkeit von mittelständischen Unternehmen in der Metropolregion +Rhein-Neckar zu erhöhen und Hochschulabsolventen die Attraktivität einer beruflichen Karriere +insbesondere im Mittelstand deutlich zu machen. Mittelständische Unternehmen prägen die +Wirtschaftsstruktur in Deutschland. 99 Prozent aller Unternehmen werden den mittelständischen +Unternehmen zugerechnet, sie beschäftigen rund 2/3 aller Erwerbstätigen. + +Parallel zur Eröffnung der MaMi wird auch die Förderrunde 2017/18 für die Mannheimer +Mittelstands-Stipendien ausgeschrieben. Durch das seit 2007 etablierte Stipendienmodell, das +in tatkräftiger Kooperation der Hochschule mit mittelständischen Unternehmen und unterstützt +von der Metropolregion Rhein-Neckar ins Leben gerufen wurde, können im Studienjahr 30-40 +Stipendien in Höhe von je 1.000 € vergeben werden. So ist die MaMi auch eine gute Gelegenheit +für Studierende, sich an den Ständen der Unternehmen als potenzielle Stipendiaten zu präsentieren. diff --git a/03-tcp/tcp.time/justfile b/03-tcp/tcp.time/justfile new file mode 100644 index 0000000..98f9ffc --- /dev/null +++ b/03-tcp/tcp.time/justfile @@ -0,0 +1,10 @@ +import '../justfile' + +port := "4747" + +server-long: + just exec vs.TimeLongServer {{port}} +server-text: + just exec vs.TimeTextServer {{port}} +client host: + just exec vs.TimeClient "{{host}} {{port}}" diff --git a/03-tcp/tcp.time/pom.xml b/03-tcp/tcp.time/pom.xml new file mode 100644 index 0000000..11d0d2c --- /dev/null +++ b/03-tcp/tcp.time/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + vs + tcp.time + 1.0-SNAPSHOT + jar + + + vs + tcp + 1.0-SNAPSHOT + + diff --git a/03-tcp/tcp.time/src/main/java/vs/TimeClient.java b/03-tcp/tcp.time/src/main/java/vs/TimeClient.java new file mode 100644 index 0000000..11bfda0 --- /dev/null +++ b/03-tcp/tcp.time/src/main/java/vs/TimeClient.java @@ -0,0 +1,23 @@ +package vs; + +import java.io.InputStream; +import java.net.Socket; + +public class TimeClient { + public static void main(String[] args) { + try (Socket socket = new Socket(args[0], Integer.parseInt(args[1])); + InputStream in = socket.getInputStream()) { + StringBuilder stringBuilder = new StringBuilder(); + + int c; + while ((c = in.read()) != -1) { + stringBuilder.append((char) c); + } + + // stringBuilder-Inhalt in ein Date-Objekt konvertieren und ausgeben + + } catch (Exception e) { + System.err.println(e); + } + } +} diff --git a/03-tcp/tcp.time/src/main/java/vs/TimeLongServer.java b/03-tcp/tcp.time/src/main/java/vs/TimeLongServer.java new file mode 100644 index 0000000..99bde96 --- /dev/null +++ b/03-tcp/tcp.time/src/main/java/vs/TimeLongServer.java @@ -0,0 +1,38 @@ +package vs; + +import java.io.IOException; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.text.DateFormat; +import java.util.Date; + +public class TimeLongServer { + private int port; + + public TimeLongServer(int port) { + this.port = port; + } + + public void startServer() { + try (ServerSocket serverSocket = new ServerSocket(port)) { + while (true) { + try (Socket socket = serverSocket.accept(); + PrintWriter out = new PrintWriter(socket.getOutputStream())) { + Date now = new Date(); + long currentTime = // Zeit von now in ms seit 01.01.1970 00:00:00 GMT abrufen + out.print(currentTime); + out.flush(); + } catch (IOException e) { + System.err.println(e); + } + } + } catch (IOException e) { + System.err.println(e); + } + } + + public static void main(String[] args) { + new TimeLongServer(Integer.parseInt(args[0])).startServer(); + } +} diff --git a/03-tcp/tcp.time/src/main/java/vs/TimeTextServer.java b/03-tcp/tcp.time/src/main/java/vs/TimeTextServer.java new file mode 100644 index 0000000..5df1508 --- /dev/null +++ b/03-tcp/tcp.time/src/main/java/vs/TimeTextServer.java @@ -0,0 +1,38 @@ +package vs; + +import java.io.IOException; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.text.DateFormat; +import java.util.Date; + +public class TimeTextServer { + private int port; + + public TimeTextServer(int port) { + this.port = port; + } + + public void startServer() { + try (ServerSocket serverSocket = new ServerSocket(port)) { + while (true) { + try (Socket socket = serverSocket.accept(); + PrintWriter out = new PrintWriter(socket.getOutputStream())) { + Date now = new Date(); + String currentTime = // DateFormat Instanz holen und mit dessen format Methode now zum String machen + out.print(currentTime); + out.flush(); + } catch (IOException e) { + System.err.println(e); + } + } + } catch (IOException e) { + System.err.println(e); + } + } + + public static void main(String[] args) { + new TimeTextServer(Integer.parseInt(args[0])).startServer(); + } +} diff --git a/03-tcp/tcp.time_solution/justfile b/03-tcp/tcp.time_solution/justfile new file mode 100644 index 0000000..98f9ffc --- /dev/null +++ b/03-tcp/tcp.time_solution/justfile @@ -0,0 +1,10 @@ +import '../justfile' + +port := "4747" + +server-long: + just exec vs.TimeLongServer {{port}} +server-text: + just exec vs.TimeTextServer {{port}} +client host: + just exec vs.TimeClient "{{host}} {{port}}" diff --git a/03-tcp/tcp.time_solution/pom.xml b/03-tcp/tcp.time_solution/pom.xml new file mode 100644 index 0000000..b5a8e94 --- /dev/null +++ b/03-tcp/tcp.time_solution/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + vs + tcp.time_solution + 1.0-SNAPSHOT + jar + + + vs + tcp + 1.0-SNAPSHOT + + diff --git a/03-tcp/tcp.time_solution/src/main/java/vs/TimeClient.java b/03-tcp/tcp.time_solution/src/main/java/vs/TimeClient.java new file mode 100644 index 0000000..54e440a --- /dev/null +++ b/03-tcp/tcp.time_solution/src/main/java/vs/TimeClient.java @@ -0,0 +1,63 @@ +package vs; + +import java.io.InputStream; +import java.net.Socket; +import java.text.DateFormat; +import java.text.ParseException; +import java.util.Date; + +/** + * Client for echo var.sockets.tcp.time.Time*Server service. Verbindet sich mit + * dem Server und empfängt eine Repräsentation eines Zeitstempels. Das Format + * des Zeitstempels kann entweder die Zeit in ms seit dem 01.01.1970 00:00:00 + * GMT als ASCII-Zeichen sein oder ein String, der die Zeit kompatibel zu ISO + * 8601 enthält. + * + * @author Sandro Leuchter + * + */ +public class TimeClient { + + /** + * main method: entrypoint to run + * + * @param args address of service to connect to (must be String[0]: host + * (IP-address or DNS hostname), String[1]: port) + * + */ + public static void main(String[] args) { + try (Socket socket = new Socket(args[0], Integer.parseInt(args[1])); InputStream in = socket.getInputStream()) { + StringBuilder stringBuilder = new StringBuilder(); + + int c; + while ((c = in.read()) != -1) { + stringBuilder.append((char) c); + } + + // stringBuilder-Inhalt in ein Date-Objekt konvertieren und ausgeben + DateFormat dateFormatter = DateFormat.getInstance(); + Date date = null; + try { + date = dateFormatter.parse(stringBuilder.toString()); + } catch (ParseException parseException) { + try { + date = new Date(Long.parseLong(stringBuilder.toString())); + } catch (NumberFormatException numberException) { + // weder verständliches Textformat, noch long-Zahl (ms. seit + // 01.01.1970 00:00) + // System.err.println(numberException); + } + } + System.out.println("empfangen: \"" + stringBuilder.toString() + "\""); + if (date != null) { + System.out.println("gewandelt: " + date); + } else { + // weder verständliches Textformat, noch long-Zahl (ms. seit + // 01.01.1970 00:00) + System.err.println("es war nicht mögich ein Date-Objekt daraus zu erzeugen."); + } + } catch (Exception e) { + System.err.println(e); + } + } +} diff --git a/03-tcp/tcp.time_solution/src/main/java/vs/TimeLongServer.java b/03-tcp/tcp.time_solution/src/main/java/vs/TimeLongServer.java new file mode 100644 index 0000000..29587c6 --- /dev/null +++ b/03-tcp/tcp.time_solution/src/main/java/vs/TimeLongServer.java @@ -0,0 +1,65 @@ +package vs; + +import java.io.IOException; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Date; + +/** + * iterative server for var.sockets.tcp.time Time service. waits for the next + * client to connect, then sends time back. format for time is ASCII + * representation of ms since begin of epoch: Jan 1, 1970 00:00:00 GMT. + * + * @author Sandro Leuchter + * + */ +public class TimeLongServer { + /** + * port on which this service is currently listening on localhost + */ + private final int port; + + /** + * the only constructor for this class + * + * @param port port on which this service will be listening on localhost + */ + public TimeLongServer(int port) { + this.port = port; + } + + /** + * creates server socket on localhost:port, infinitely handles connections to + * clients one after another: waits for the next client to connect, send time + * back. format for time is ASCII representation of ms since begin of epoch: Jan + * 1, 1970 00:00:00 GMT. + */ + public void startServer() { + try (ServerSocket serverSocket = new ServerSocket(this.port)) { + while (true) { + try (Socket socket = serverSocket.accept(); + PrintWriter out = new PrintWriter(socket.getOutputStream())) { + Date now = new Date(); + long currentTime = now.getTime(); + out.print(currentTime); + out.flush(); + } catch (IOException e) { + System.err.println(e); + } + } + } catch (IOException e) { + System.err.println(e); + } + } + + /** + * main method: entrypoint to run service + * + * @param args args[0] must be the port number of the server (int); rest of args + * is ignored + */ + public static void main(String[] args) { + new TimeLongServer(Integer.parseInt(args[0])).startServer(); + } +} diff --git a/03-tcp/tcp.time_solution/src/main/java/vs/TimeTextServer.java b/03-tcp/tcp.time_solution/src/main/java/vs/TimeTextServer.java new file mode 100644 index 0000000..eb4f528 --- /dev/null +++ b/03-tcp/tcp.time_solution/src/main/java/vs/TimeTextServer.java @@ -0,0 +1,65 @@ +package vs; + +import java.io.IOException; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.text.DateFormat; +import java.util.Date; + +/** + * iterative server for var.sockets.tcp.time Time service. waits for the next + * client to connect, then sends time back. format for time is short date and + * time according to current locale. + * + * @author Sandro Leuchter + * + */ +public class TimeTextServer { + /** + * port on which this service is currently listening on localhost + */ + private final int port; + + /** + * the only constructor for this class + * + * @param port port on which this service will be listening on localhost + */ + public TimeTextServer(int port) { + this.port = port; + } + + /** + * creates server socket on localhost:port, infinitely handles connections to + * clients one after another: waits for the next client to connect, send time + * back. format for time is short date and time according to current locale. + */ + public void startServer() { + try (ServerSocket serverSocket = new ServerSocket(this.port)) { + while (true) { + try (Socket socket = serverSocket.accept(); + PrintWriter out = new PrintWriter(socket.getOutputStream())) { + Date now = new Date(); + String currentTime = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(now); + out.print(currentTime); + out.flush(); + } catch (IOException e) { + System.err.println(e); + } + } + } catch (IOException e) { + System.err.println(e); + } + } + + /** + * main method: entrypoint to run + * + * @param args args[0] must be the port number of the server (int); rest of args + * is ignored + */ + public static void main(String[] args) { + new TimeTextServer(Integer.parseInt(args[0])).startServer(); + } +} diff --git a/05-jms/jms.chat/justfile b/05-jms/jms.chat/justfile new file mode 100644 index 0000000..e619b7f --- /dev/null +++ b/05-jms/jms.chat/justfile @@ -0,0 +1,8 @@ +import '../justfile' + +chatter1: + just chatter Dave +chatter2: + just chatter HAL9000 +chatter name: + just exec vs.ChatClient "{{name}}" diff --git a/05-jms/jms.chat/pom.xml b/05-jms/jms.chat/pom.xml new file mode 100644 index 0000000..92ec090 --- /dev/null +++ b/05-jms/jms.chat/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + vs + jms.chat + 1.0-SNAPSHOT + jar + + + vs + jms + 1.0-SNAPSHOT + + + diff --git a/05-jms/jms.chat/src/main/java/vs/ChatClient.java b/05-jms/jms.chat/src/main/java/vs/ChatClient.java new file mode 100644 index 0000000..8a39f1a --- /dev/null +++ b/05-jms/jms.chat/src/main/java/vs/ChatClient.java @@ -0,0 +1,69 @@ +package vs; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.Destination; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageListener; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +// Code aus JMS-Client mit Umbenennung des Typs von JMSClient zu ChatClient und Anpassung des packages +public class ChatClient implements MessageListener { + private Connection connection; + private Session session; + private MessageConsumer consumer; + + public ChatClient() throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + Destination queue = (Destination) ctx.lookup(Conf.QUEUE); + connection = factory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = session.createConsumer(queue); + consumer.setMessageListener(this); + connection.start(); + } + + @Override + public void onMessage(Message message) { + try { + if (message instanceof TextMessage) { + TextMessage textMessage = (TextMessage) message; + String messageText = textMessage.getText(); + String priority = textMessage.getStringProperty("Priority"); + System.out.println(messageText + " [Priority=" + priority + "]"); + } + } catch (JMSException e) { + System.err.println(e); + } + + } + + public static void main(String[] args) { + long wait = Long.parseLong(args[0]); + ChatClient node = null; + try { + node = new ChatClient(); + Thread.sleep(wait); + } catch (InterruptedException | NamingException | JMSException e) { + System.err.println(e); + } finally { + try { + if (node != null && node.consumer != null) + node.consumer.close(); + if (node != null && node.session != null) + node.session.close(); + if (node != null && node.connection != null) + node.connection.close(); + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.chat/src/main/resources/jndi.properties b/05-jms/jms.chat/src/main/resources/jndi.properties new file mode 100644 index 0000000..f76bbf7 --- /dev/null +++ b/05-jms/jms.chat/src/main/resources/jndi.properties @@ -0,0 +1,5 @@ +java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory +java.naming.provider.url = tcp://localhost:61616 + +topic.vs.channel = topic4735 + diff --git a/05-jms/jms.chat_solution/justfile b/05-jms/jms.chat_solution/justfile new file mode 100644 index 0000000..d400190 --- /dev/null +++ b/05-jms/jms.chat_solution/justfile @@ -0,0 +1,15 @@ +import '../justfile' + +chatter1: + just chatter Dave +chatter2: + just chatter HAL9000 +chatter name: + just exec vs.ChatClient "{{name}}" + +chatterA: + just chatter-prop Dave +chatterB: + just chatter-prop HAL9000 +chatter-prop name: + just exec vs.ChatClientUserProperty "{{name}}" diff --git a/05-jms/jms.chat_solution/pom.xml b/05-jms/jms.chat_solution/pom.xml new file mode 100644 index 0000000..0f95fee --- /dev/null +++ b/05-jms/jms.chat_solution/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + vs + jms.chat_solution + 1.0-SNAPSHOT + jar + + + vs + jms + 1.0-SNAPSHOT + + + diff --git a/05-jms/jms.chat_solution/src/main/java/vs/ChatClient.java b/05-jms/jms.chat_solution/src/main/java/vs/ChatClient.java new file mode 100644 index 0000000..6d9c8ab --- /dev/null +++ b/05-jms/jms.chat_solution/src/main/java/vs/ChatClient.java @@ -0,0 +1,111 @@ +package vs; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.Destination; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageListener; +import jakarta.jms.MessageProducer; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +/** + * Chat Client using publish/subscribe on JMS provider Topic; represents user + * name as part of message payload + * + * @author Sandro Leuchter + * + */ +public class ChatClient implements MessageListener { + private Connection connection; + private Session session; + private MessageProducer producer; + private MessageConsumer consumer; + + /** + * constructor, establishes and starts connection to JMS provider specified in + * JNDI (via jndi.properties), afterwards producer and consumer are ready + * + * @param sendDest Destination for producer + * @param receiveDest Destination for consumer + * + * @throws NamingException JNDI exceptions + * @throws JMSException JMS exceptions + * @see jakarta.jms.Destination + */ + public ChatClient(String sendDest, String receiveDest) throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + this.connection = factory.createConnection(); + this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destOut = (Destination) ctx.lookup(sendDest); + Destination destIn = (Destination) ctx.lookup(receiveDest); + this.producer = this.session.createProducer(destOut); + this.consumer = this.session.createConsumer(destIn); + this.consumer.setMessageListener(this); + this.connection.start(); + } + + /** + * asynchronous message consumption + * + * @see jakarta.jms.MessageListener + */ + @Override + public void onMessage(Message message) { + if (message instanceof TextMessage) { + TextMessage textMessage = (TextMessage) message; + try { + System.out.println(textMessage.getText()); + } catch (JMSException e) { + System.err.println(e); + } + } + } + + /** + * main routine and starting point of program + * + * @param args[0] user name + */ + public static void main(String[] args) { + ChatClient node = null; + try { + node = new ChatClient(Conf.TOPIC, Conf.TOPIC); + BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); + String line; + while (true) { + line = input.readLine(); + node.producer.send(node.session.createTextMessage(args[0] + "> " + line)); + } + } catch (NamingException | JMSException | IOException e) { + System.err.println(e); + } finally { + try { + if ((node != null) && (node.producer != null)) { + node.producer.close(); + } + if ((node != null) && (node.consumer != null)) { + node.consumer.close(); + } + if ((node != null) && (node.session != null)) { + node.session.close(); + } + if ((node != null) && (node.connection != null)) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.chat_solution/src/main/java/vs/ChatClientUserProperty.java b/05-jms/jms.chat_solution/src/main/java/vs/ChatClientUserProperty.java new file mode 100644 index 0000000..d850031 --- /dev/null +++ b/05-jms/jms.chat_solution/src/main/java/vs/ChatClientUserProperty.java @@ -0,0 +1,113 @@ +package vs; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.Destination; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageListener; +import jakarta.jms.MessageProducer; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +/** + * Chat Client using publish/subscribe on JMS provider Topic; represents user + * name as String property of message + * + * @author Sandro Leuchter + * + */ +public class ChatClientUserProperty implements MessageListener { + private Connection connection; + private Session session; + private MessageProducer producer; + private MessageConsumer consumer; + + /** + * constructor, establishes and starts connection to JMS provider specified in + * JNDI (via jndi.properties), afterwards producer and consumer are ready + * + * @param sendDest Destination for producer + * @param receiveDest Destination for consumer + * + * @throws NamingException JNDI exceptions + * @throws JMSException JMS exceptions + * @see jakarta.jms.Destination + */ + public ChatClientUserProperty(String sendDest, String receiveDest) throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + this.connection = factory.createConnection(); + this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destOut = (Destination) ctx.lookup(sendDest); + Destination destIn = (Destination) ctx.lookup(receiveDest); + this.producer = this.session.createProducer(destOut); + this.consumer = this.session.createConsumer(destIn); + this.consumer.setMessageListener(this); + this.connection.start(); + } + + /** + * asynchronous message consumption + * + * @see jakarta.jms.MessageListener + */ + @Override + public void onMessage(Message message) { + if (message instanceof TextMessage) { + TextMessage textMessage = (TextMessage) message; + try { + System.out.println(textMessage.getStringProperty("user") + "> " + textMessage.getText()); + } catch (JMSException e) { + System.err.println(e); + } + } + } + + /** + * main routine and starting point of program + * + * @param args[0] user name + */ + public static void main(String[] args) { + ChatClientUserProperty node = null; + try { + node = new ChatClientUserProperty(Conf.TOPIC, Conf.TOPIC); + BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); + String line; + while (true) { + line = input.readLine(); + TextMessage msg = node.session.createTextMessage(line); + msg.setStringProperty("user", args[0]); + node.producer.send(msg); + } + } catch (NamingException | JMSException | IOException e) { + System.err.println(e); + } finally { + try { + if ((node != null) && (node.producer != null)) { + node.producer.close(); + } + if ((node != null) && (node.consumer != null)) { + node.consumer.close(); + } + if ((node != null) && (node.session != null)) { + node.session.close(); + } + if ((node != null) && (node.connection != null)) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.chat_solution/src/main/java/vs/Conf.java b/05-jms/jms.chat_solution/src/main/java/vs/Conf.java new file mode 100644 index 0000000..a953eb1 --- /dev/null +++ b/05-jms/jms.chat_solution/src/main/java/vs/Conf.java @@ -0,0 +1,5 @@ +package vs; + +public class Conf { + public static final String TOPIC = "vs.chat"; +} diff --git a/05-jms/jms.chat_solution/src/main/resources/jndi.properties b/05-jms/jms.chat_solution/src/main/resources/jndi.properties new file mode 100644 index 0000000..ec1c480 --- /dev/null +++ b/05-jms/jms.chat_solution/src/main/resources/jndi.properties @@ -0,0 +1,5 @@ +java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory +java.naming.provider.url = tcp://localhost:61616 + +topic.vs.chat = topic4735 + diff --git a/05-jms/jms.client/justfile b/05-jms/jms.client/justfile new file mode 100644 index 0000000..3d81654 --- /dev/null +++ b/05-jms/jms.client/justfile @@ -0,0 +1,4 @@ +import '../justfile' + +client: + just exec vs.JMSClient "" diff --git a/05-jms/jms.client/pom.xml b/05-jms/jms.client/pom.xml new file mode 100644 index 0000000..dbb96ee --- /dev/null +++ b/05-jms/jms.client/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + vs + jms.client + 1.0-SNAPSHOT + jar + + + vs + jms + 1.0-SNAPSHOT + + + diff --git a/05-jms/jms.client/src/main/java/vs/JMSClient.java b/05-jms/jms.client/src/main/java/vs/JMSClient.java new file mode 100644 index 0000000..b7cb575 --- /dev/null +++ b/05-jms/jms.client/src/main/java/vs/JMSClient.java @@ -0,0 +1,84 @@ +package vs; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import jakarta.jms.BytesMessage; +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.Destination; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageListener; +import jakarta.jms.MessageProducer; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +public class JMSClient implements MessageListener { + private Connection connection; + private Session session; + private MessageProducer producer; + private MessageConsumer consumer; + + public JMSClient(String sendDest, String receiveDest) throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + connection = factory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destOut = (Destination) ctx.lookup(sendDest); + Destination destIn = (Destination) ctx.lookup(receiveDest); + producer = session.createProducer(destOut); + consumer = session.createConsumer(destIn); + consumer.setMessageListener(this); + connection.start(); + } + + @Override + public void onMessage(Message message) { + if (message instanceof TextMessage) { + TextMessage textMessage = (TextMessage) message; + try { + System.out.println(textMessage.getText()); + } catch (JMSException e) { + System.err.println(e); + } + } + } + + public static void main(String[] args) { + JMSClient node = null; + try { + node = new JMSClient("vs.queue1", "vs.queue2"); + BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); + String line; + while (true) { + line = input.readLine(); + node.producer.send(node.session.createTextMessage(line)); + } + } catch (NamingException | JMSException | IOException e) { + System.err.println(e); + } finally { + try { + if (node != null && node.producer != null) { + node.producer.close(); + } + if (node != null && node.consumer != null) { + node.consumer.close(); + } + if (node != null && node.session != null) { + node.session.close(); + } + if (node != null && node.connection != null) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.client/src/main/resources/jndi.properties b/05-jms/jms.client/src/main/resources/jndi.properties new file mode 100644 index 0000000..af6e097 --- /dev/null +++ b/05-jms/jms.client/src/main/resources/jndi.properties @@ -0,0 +1,6 @@ +java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory +java.naming.provider.url = tcp://localhost:61616 + +queue.vs.queue1 = queue4731 +queue.vs.queue2 = queue4732 + diff --git a/05-jms/jms.client_solution/justfile b/05-jms/jms.client_solution/justfile new file mode 100644 index 0000000..3d81654 --- /dev/null +++ b/05-jms/jms.client_solution/justfile @@ -0,0 +1,4 @@ +import '../justfile' + +client: + just exec vs.JMSClient "" diff --git a/05-jms/jms.client_solution/pom.xml b/05-jms/jms.client_solution/pom.xml new file mode 100644 index 0000000..9c1d99a --- /dev/null +++ b/05-jms/jms.client_solution/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + vs + jms.client_solution + 1.0-SNAPSHOT + jar + + + vs + jms + 1.0-SNAPSHOT + + + diff --git a/05-jms/jms.client_solution/src/main/java/vs/JMSClient.java b/05-jms/jms.client_solution/src/main/java/vs/JMSClient.java new file mode 100644 index 0000000..ff890bf --- /dev/null +++ b/05-jms/jms.client_solution/src/main/java/vs/JMSClient.java @@ -0,0 +1,110 @@ +package vs; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.Destination; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageListener; +import jakarta.jms.MessageProducer; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +/** + * general JMS client with one producer and one consumer + * + * @author Sandro Leuchter + * + */ +public class JMSClient implements MessageListener { + private Connection connection; + private Session session; + private MessageProducer producer; + private MessageConsumer consumer; + + /** + * constructor, establishes and starts connection to JMS provider specified in + * JNDI (via jndi.properties), afterwards producer and consumer are ready + * + * @param sendDest Destination for producer + * @param receiveDest Destination for consumer + * + * @throws NamingException JNDI exceptions + * @throws JMSException JMS exceptions + * @see jakarta.jms.Destination + */ + public JMSClient(String sendDest, String receiveDest) throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + this.connection = factory.createConnection(); + this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destOut = (Destination) ctx.lookup(sendDest); + Destination destIn = (Destination) ctx.lookup(receiveDest); + this.producer = this.session.createProducer(destOut); + this.consumer = this.session.createConsumer(destIn); + this.consumer.setMessageListener(this); + this.connection.start(); + } + + /** + * asynchronous message consumption + * + * @see jakarta.jms.MessageListener + */ + @Override + public void onMessage(Message message) { + if (message instanceof TextMessage) { + TextMessage textMessage = (TextMessage) message; + try { + System.out.println(textMessage.getText()); + } catch (JMSException e) { + System.err.println(e); + } + } + } + + /** + * main routine and starting point of program + * + * @param args not used + */ + public static void main(String[] args) { + JMSClient node = null; + try { + node = new JMSClient("vs.queue1", "vs.queue2"); + BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); + String line; + while (true) { + line = input.readLine(); + node.producer.send(node.session.createTextMessage(line)); + } + } catch (NamingException | JMSException | IOException e) { + System.err.println(e); + } finally { + try { + if ((node != null) && (node.producer != null)) { + node.producer.close(); + } + if ((node != null) && (node.consumer != null)) { + node.consumer.close(); + } + if ((node != null) && (node.session != null)) { + node.session.close(); + } + if ((node != null) && (node.connection != null)) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.client_solution/src/main/resources/jndi.properties b/05-jms/jms.client_solution/src/main/resources/jndi.properties new file mode 100644 index 0000000..af6e097 --- /dev/null +++ b/05-jms/jms.client_solution/src/main/resources/jndi.properties @@ -0,0 +1,6 @@ +java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory +java.naming.provider.url = tcp://localhost:61616 + +queue.vs.queue1 = queue4731 +queue.vs.queue2 = queue4732 + diff --git a/05-jms/jms.code-workspace b/05-jms/jms.code-workspace new file mode 100644 index 0000000..3da1dcb --- /dev/null +++ b/05-jms/jms.code-workspace @@ -0,0 +1,55 @@ +{ + "folders": [ + { + "name": "0. Client Service", + "path": "jms.client", + }, + { + "name": "0. Client Service (ML)", + "path": "jms.client_solution", + }, + { + "name": "1. Echo Service", + "path": "jms.echo", + }, + { + "name": "1. Echo Service (ML)", + "path": "jms.echo_solution", + }, + { + "name": "2. Logger Service", + "path": "jms.logger", + }, + { + "name": "2. Logger Service (ML)", + "path": "jms.logger_solution", + }, + { + "name": "3. Textumdreher Service (ML)", + "path": "jms.revers_solution", + }, + { + "name": "4. Chat Service", + "path": "jms.chat", + }, + { + "name": "4. Chat Service (ML)", + "path": "jms.chat_solution", + }, + { + "name": "5. Worker/Tasker für SHA-256 Hashes (ML)", + "path": "jms.tasks_solution", + }, + ], + "extensions": { + "recommendations": [ + "vscjava.vscode-java-pack", + "ms-azuretools.vscode-docker", + "skellock.just", + ], + }, + "settings": { + "java.dependency.syncWithFolderExplorer": true, + "java.project.explorer.showNonJavaResources": false, + }, +} diff --git a/05-jms/jms.echo/justfile b/05-jms/jms.echo/justfile new file mode 100644 index 0000000..fce18a7 --- /dev/null +++ b/05-jms/jms.echo/justfile @@ -0,0 +1,6 @@ +import '../justfile' + +requester text: + just exec vs.EchoRequesterNode "{{text}}" +replier: + just exec vs.EchoReplierNode "" diff --git a/05-jms/jms.echo/pom.xml b/05-jms/jms.echo/pom.xml new file mode 100644 index 0000000..c0d4a87 --- /dev/null +++ b/05-jms/jms.echo/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + vs + jms.echo + 1.0-SNAPSHOT + jar + + + vs + jms + 1.0-SNAPSHOT + + + diff --git a/05-jms/jms.echo/src/main/java/vs/Conf.java b/05-jms/jms.echo/src/main/java/vs/Conf.java new file mode 100644 index 0000000..6f992ef --- /dev/null +++ b/05-jms/jms.echo/src/main/java/vs/Conf.java @@ -0,0 +1,5 @@ +package vs; + +public class Conf { + public static final String QUEUE = "vs.echo"; +} diff --git a/05-jms/jms.echo/src/main/java/vs/EchoReplierNode.java b/05-jms/jms.echo/src/main/java/vs/EchoReplierNode.java new file mode 100644 index 0000000..b9b830e --- /dev/null +++ b/05-jms/jms.echo/src/main/java/vs/EchoReplierNode.java @@ -0,0 +1,74 @@ +package vs; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageListener; +import jakarta.jms.MessageProducer; +import jakarta.jms.Queue; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +public class EchoReplierNode implements MessageListener { + private Connection connection; + private Session session; + private MessageConsumer consumer; + + public EchoReplierNode() throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + Queue queue = (Queue) ctx.lookup(Conf.QUEUE); + connection = factory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = session.createConsumer(queue); + consumer.setMessageListener(this); + connection.start(); + } + + @Override + public void onMessage(Message request) { + try { + if (request instanceof TextMessage) { + TextMessage requestText = (TextMessage) request; + System.out.println("empfangen: " + requestText.getText()); + MessageProducer replyProducer = session.createProducer(request.getJMSReplyTo()); + TextMessage reply = session.createTextMessage(); + reply.setText("echo: " + requestText.getText()); + Thread.sleep(5000); + replyProducer.send(reply); + replyProducer.close(); + } + } catch (JMSException | InterruptedException e) { + System.err.println(e); + } + + } + + public static void main(String[] args) { + EchoReplierNode node = null; + try { + node = new EchoReplierNode(); + while (true) { + Thread.sleep(1000); + } + } catch (InterruptedException | NamingException | JMSException e) { + System.err.println(e); + } finally { + try { + if (node != null && node.consumer != null) + node.consumer.close(); + if (node != null && node.session != null) + node.session.close(); + if (node != null && node.connection != null) + node.connection.close(); + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.echo/src/main/java/vs/EchoRequesterNode.java b/05-jms/jms.echo/src/main/java/vs/EchoRequesterNode.java new file mode 100644 index 0000000..d7219e3 --- /dev/null +++ b/05-jms/jms.echo/src/main/java/vs/EchoRequesterNode.java @@ -0,0 +1,85 @@ +package vs; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageProducer; +import jakarta.jms.Queue; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +public class EchoRequesterNode { + private Connection connection; + private Session session; + private MessageProducer producer; + private MessageConsumer consumer; + private Queue replyQueue; + + public EchoRequesterNode() throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + connection = factory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = (Queue) ctx.lookup(Conf.QUEUE); + producer = session.createProducer(queue); + replyQueue = session.createTemporaryQueue(); + consumer = session.createConsumer(replyQueue); + connection.start(); + } + + public void receiveAndPrintMessages() throws JMSException { + Message request; + while ((request = consumer.receive()) != null) { + try { + if (request instanceof TextMessage) { + TextMessage requestText = (TextMessage) request; + String messageText = requestText.getText(); + System.out.println("empfangen: " + messageText); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } + + public void sendMessage(String text) throws JMSException { + TextMessage message = session.createTextMessage(); + message.setText(text); + message.setJMSReplyTo(replyQueue); + producer.send(message); + } + + public static void main(String[] args) { + String text = args[0]; + EchoRequesterNode node = null; + try { + node = new EchoRequesterNode(); + node.sendMessage(text); + node.receiveAndPrintMessages(); + } catch (NamingException | JMSException e) { + System.err.println(e); + } finally { + try { + if (node != null && node.producer != null) { + node.producer.close(); + } + if (node != null && node.consumer != null) { + node.consumer.close(); + } + if (node != null && node.session != null) { + node.session.close(); + } + if (node != null && node.connection != null) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.echo/src/main/resources/jndi.properties b/05-jms/jms.echo/src/main/resources/jndi.properties new file mode 100644 index 0000000..a659ecb --- /dev/null +++ b/05-jms/jms.echo/src/main/resources/jndi.properties @@ -0,0 +1,6 @@ +java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory +java.naming.provider.url = tcp://localhost:61616 + +queue.vs.echo = queue4734 + + diff --git a/05-jms/jms.echo/target/classes/jndi.properties b/05-jms/jms.echo/target/classes/jndi.properties new file mode 100644 index 0000000..a659ecb --- /dev/null +++ b/05-jms/jms.echo/target/classes/jndi.properties @@ -0,0 +1,6 @@ +java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory +java.naming.provider.url = tcp://localhost:61616 + +queue.vs.echo = queue4734 + + diff --git a/05-jms/jms.echo/target/classes/vs/Conf.class b/05-jms/jms.echo/target/classes/vs/Conf.class new file mode 100644 index 0000000000000000000000000000000000000000..fb658823f38b2b1f0907dae137c2034b71b87e44 GIT binary patch literal 317 zcmYLEyH3ME5S(@FICdNo0u+>VKoNfck0weg3xq=4pUsh6WbP#Uoc~INM8OB}QHVV& z63yJs?#|BK&+peafCpTJ@Cf0)N#{nthwurLo!E=C5_*$97du&6Lh!O)tQUl7_CH(M zTItOlVZ_SD3T<;ywQ_){yEl{N))4ylN-O(F=w09B1b=ScWQ-n862ur1#+lOcsr@Kq z{VIw|IuBEdDi^hK{MhvERyBkuI|gOjcxBqUluPAAkxM^w;cx{u&SaR2}S literal 0 HcmV?d00001 diff --git a/05-jms/jms.echo/target/classes/vs/EchoReplierNode.class b/05-jms/jms.echo/target/classes/vs/EchoReplierNode.class new file mode 100644 index 0000000000000000000000000000000000000000..23914a98afb7c57be5b1a12ca86a06d8c40a1e79 GIT binary patch literal 3738 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 + 4.0.0 + vs + jms.echo_solution + 1.0-SNAPSHOT + jar + + + vs + jms + 1.0-SNAPSHOT + + + diff --git a/05-jms/jms.echo_solution/src/main/java/vs/Conf.java b/05-jms/jms.echo_solution/src/main/java/vs/Conf.java new file mode 100644 index 0000000..da885d7 --- /dev/null +++ b/05-jms/jms.echo_solution/src/main/java/vs/Conf.java @@ -0,0 +1,16 @@ +package vs; + +/** + * global configuration for echo service + * + * @author Sandro Leuchter + * + */ +public class Conf { + /** + * String constant for requests to the destination of echo service + * + * @see javax.jms.Destination + */ + public static final String QUEUE = "vs.echo"; +} diff --git a/05-jms/jms.echo_solution/src/main/java/vs/EchoReplierNode.java b/05-jms/jms.echo_solution/src/main/java/vs/EchoReplierNode.java new file mode 100644 index 0000000..53f820f --- /dev/null +++ b/05-jms/jms.echo_solution/src/main/java/vs/EchoReplierNode.java @@ -0,0 +1,100 @@ +package vs; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageListener; +import jakarta.jms.MessageProducer; +import jakarta.jms.Queue; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +/** + * replier node for the echo service + * + * @author Sandro Leuchter + * + */ +public class EchoReplierNode implements MessageListener { + private Connection connection; + private Session session; + private MessageConsumer consumer; + + /** + * constructor, establishes and starts connection to JMS provider specified in + * JNDI (via jndi.properties), afterwards consumer is ready + * + * @throws NamingException JNDI exceptions + * @throws JMSException JMS exceptions + */ + public EchoReplierNode() throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + Queue queue = (Queue) ctx.lookup(Conf.QUEUE); + this.connection = factory.createConnection(); + this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + this.consumer = this.session.createConsumer(queue); + this.consumer.setMessageListener(this); + this.connection.start(); + } + + /** + * asynchronous message consumption + * + * @see jakarta.jms.MessageListener + */ + @Override + public void onMessage(Message request) { + try { + if (request instanceof TextMessage) { + TextMessage requestText = (TextMessage) request; + System.out.println("empfangen: " + requestText.getText()); + MessageProducer replyProducer = this.session.createProducer(request.getJMSReplyTo()); + TextMessage reply = this.session.createTextMessage(); + reply.setText("echo: " + requestText.getText()); + Thread.sleep(5000); + replyProducer.send(reply); + replyProducer.close(); + } + } catch (JMSException | InterruptedException e) { + System.err.println(e); + } + + } + + /** + * main routine and starting point of program + * + * @param args not used + */ + public static void main(String[] args) { + EchoReplierNode node = null; + try { + node = new EchoReplierNode(); + while (true) { + Thread.sleep(1000); + } + } catch (InterruptedException | NamingException | JMSException e) { + System.err.println(e); + } finally { + try { + if ((node != null) && (node.consumer != null)) { + node.consumer.close(); + } + if ((node != null) && (node.session != null)) { + node.session.close(); + } + if ((node != null) && (node.connection != null)) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.echo_solution/src/main/java/vs/EchoRequesterNode.java b/05-jms/jms.echo_solution/src/main/java/vs/EchoRequesterNode.java new file mode 100644 index 0000000..c5f5a30 --- /dev/null +++ b/05-jms/jms.echo_solution/src/main/java/vs/EchoRequesterNode.java @@ -0,0 +1,117 @@ +package vs; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageProducer; +import jakarta.jms.Queue; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +/** + * requester node for the echo service + * + * @author Sandro Leuchter + * + */ +public class EchoRequesterNode { + private Connection connection; + private Session session; + private MessageProducer producer; + private MessageConsumer consumer; + private Queue replyQueue; + + /** + * constructor, establishes and starts connection to JMS provider specified in + * JNDI (via jndi.properties), afterwards producer and consumer are ready + * + * @throws NamingException JNDI exceptions + * @throws JMSException JMS exceptions + */ + public EchoRequesterNode() throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + this.connection = factory.createConnection(); + this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = (Queue) ctx.lookup(Conf.QUEUE); + this.producer = this.session.createProducer(queue); + this.replyQueue = this.session.createTemporaryQueue(); + this.consumer = this.session.createConsumer(this.replyQueue); + this.connection.start(); + } + + /** + * synchronously receives the TextMessages in an infinite loop and prints + * payload text to StdOut + * + * @see jakarta.jms.TextMessage + * @throws JMSException JMS exceptions + */ + public void receiveAndPrintMessages() throws JMSException { + Message request; + while ((request = this.consumer.receive()) != null) { + try { + if (request instanceof TextMessage) { + TextMessage requestText = (TextMessage) request; + String messageText = requestText.getText(); + System.out.println("empfangen: " + messageText); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } + + /** + * creates TextMessage for JMS provider with temporary reply queue set and sends + * it to Destination of producer, which is configured in Conf.QUEUE + * + * @param text text to be send + * @throws JMSException JMS exceptions + */ + public void sendMessage(String text) throws JMSException { + TextMessage message = this.session.createTextMessage(); + message.setText(text); + message.setJMSReplyTo(this.replyQueue); + this.producer.send(message); + } + + /** + * main routine and starting point of program + * + * @param args[0] text to be send to echo service replier + */ + public static void main(String[] args) { + String text = args[0]; + EchoRequesterNode node = null; + try { + node = new EchoRequesterNode(); + node.sendMessage(text); + node.receiveAndPrintMessages(); + } catch (NamingException | JMSException e) { + System.err.println(e); + } finally { + try { + if ((node != null) && (node.producer != null)) { + node.producer.close(); + } + if ((node != null) && (node.consumer != null)) { + node.consumer.close(); + } + if ((node != null) && (node.session != null)) { + node.session.close(); + } + if ((node != null) && (node.connection != null)) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.echo_solution/src/main/resources/jndi.properties b/05-jms/jms.echo_solution/src/main/resources/jndi.properties new file mode 100644 index 0000000..a659ecb --- /dev/null +++ b/05-jms/jms.echo_solution/src/main/resources/jndi.properties @@ -0,0 +1,6 @@ +java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory +java.naming.provider.url = tcp://localhost:61616 + +queue.vs.echo = queue4734 + + diff --git a/05-jms/jms.logger/justfile b/05-jms/jms.logger/justfile new file mode 100644 index 0000000..692c5ed --- /dev/null +++ b/05-jms/jms.logger/justfile @@ -0,0 +1,12 @@ +include '../justfile' + +wait_time_ms := "10000" + +consumer-sync: + just exec vs.ConsumerPullNode "{{wait_time_ms}}" +consumer-async-all: + just exec vs.ConsumerCallbackNode "{{wait_time_ms}}" +consumer-async-high: + just exec vs.ConsumerFilteredNode "{{wait_time_ms}}" +producer text prio: + just exec vs.ProducerNode "{{text}} {{prio}}" diff --git a/05-jms/jms.logger/pom.xml b/05-jms/jms.logger/pom.xml new file mode 100644 index 0000000..e4f372a --- /dev/null +++ b/05-jms/jms.logger/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + vs + jms.logger + 1.0-SNAPSHOT + jar + + + vs + jms + 1.0-SNAPSHOT + + + diff --git a/05-jms/jms.logger/src/main/java/vs/Conf.java b/05-jms/jms.logger/src/main/java/vs/Conf.java new file mode 100644 index 0000000..00385dd --- /dev/null +++ b/05-jms/jms.logger/src/main/java/vs/Conf.java @@ -0,0 +1,5 @@ +package vs; + +public class Conf { + public static final String QUEUE = "vs.queue"; +} diff --git a/05-jms/jms.logger/src/main/java/vs/ConsumerCallbackNode.java b/05-jms/jms.logger/src/main/java/vs/ConsumerCallbackNode.java new file mode 100644 index 0000000..c9f9cc3 --- /dev/null +++ b/05-jms/jms.logger/src/main/java/vs/ConsumerCallbackNode.java @@ -0,0 +1,68 @@ +package vs; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.Destination; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageListener; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +public class ConsumerCallbackNode implements MessageListener { + private Connection connection; + private Session session; + private MessageConsumer consumer; + + public ConsumerCallbackNode() throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + Destination queue = (Destination) ctx.lookup(Conf.QUEUE); + connection = factory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = session.createConsumer(queue); + consumer.setMessageListener(this); + connection.start(); + } + + @Override + public void onMessage(Message message) { + try { + if (message instanceof TextMessage) { + TextMessage textMessage = (TextMessage) message; + String messageText = textMessage.getText(); + String priority = textMessage.getStringProperty("Priority"); + System.out.println(messageText + " [Priority=" + priority + "]"); + } + } catch (JMSException e) { + System.err.println(e); + } + + } + + public static void main(String[] args) { + long wait = Long.parseLong(args[0]); + ConsumerCallbackNode node = null; + try { + node = new ConsumerCallbackNode(); + Thread.sleep(wait); + } catch (InterruptedException | NamingException | JMSException e) { + System.err.println(e); + } finally { + try { + if (node != null && node.consumer != null) + node.consumer.close(); + if (node != null && node.session != null) + node.session.close(); + if (node != null && node.connection != null) + node.connection.close(); + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.logger/src/main/java/vs/ConsumerFilteredNode.java b/05-jms/jms.logger/src/main/java/vs/ConsumerFilteredNode.java new file mode 100644 index 0000000..fb1bf63 --- /dev/null +++ b/05-jms/jms.logger/src/main/java/vs/ConsumerFilteredNode.java @@ -0,0 +1,68 @@ +package vs; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.Destination; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageListener; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +public class ConsumerFilteredNode implements MessageListener { + private Connection connection; + private Session session; + private MessageConsumer consumer; + + public ConsumerFilteredNode() throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + Destination queue = (Destination) ctx.lookup(Conf.QUEUE); + connection = factory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = session.createConsumer(queue, "Priority='high'"); + consumer.setMessageListener(this); + connection.start(); + } + + @Override + public void onMessage(Message message) { + try { + if (message instanceof TextMessage) { + TextMessage textMessage = (TextMessage) message; + String messageText = textMessage.getText(); + String priority = textMessage.getStringProperty("Priority"); + System.out.println(messageText + " [Priority=" + priority + "]"); + } + } catch (JMSException e) { + System.err.println(e); + } + } + + public static void main(String[] args) { + long wait = Long.parseLong(args[0]); + ConsumerFilteredNode node = null; + try { + node = new ConsumerFilteredNode(); + Thread.sleep(wait); + } catch (InterruptedException | NamingException | JMSException e) { + System.err.println(e); + } finally { + try { + if (node != null && node.consumer != null) + node.consumer.close(); + if (node != null && node.session != null) + node.session.close(); + if (node != null && node.connection != null) + node.connection.close(); + } catch (JMSException e) { + System.err.println(e); + } + } + } + +} diff --git a/05-jms/jms.logger/src/main/java/vs/ConsumerPullNode.java b/05-jms/jms.logger/src/main/java/vs/ConsumerPullNode.java new file mode 100644 index 0000000..5ca0d0d --- /dev/null +++ b/05-jms/jms.logger/src/main/java/vs/ConsumerPullNode.java @@ -0,0 +1,62 @@ +package vs; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.Destination; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +public class ConsumerPullNode { + private Connection connection; + private Session session; + private MessageConsumer consumer; + + public ConsumerPullNode() throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + Destination queue = (Destination) ctx.lookup(Conf.QUEUE); + connection = factory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = session.createConsumer(queue); + connection.start(); + } + + public void receiveAndPrintMessages(long timeout) throws JMSException { + Message message; + while ((message = consumer.receive(timeout)) != null) { + if (message instanceof TextMessage) { + TextMessage textMessage = (TextMessage) message; + String messageText = textMessage.getText(); + System.out.println(messageText); + } + } + } + + public static void main(String[] args) { + long timeout = Long.parseLong(args[0]); + ConsumerPullNode node = null; + try { + node = new ConsumerPullNode(); + node.receiveAndPrintMessages(timeout); + } catch (NamingException | JMSException e) { + System.err.println(e); + } finally { + try { + if (node != null && node.consumer != null) + node.consumer.close(); + if (node != null && node.session != null) + node.session.close(); + if (node != null && node.connection != null) + node.connection.close(); + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.logger/src/main/java/vs/ProducerNode.java b/05-jms/jms.logger/src/main/java/vs/ProducerNode.java new file mode 100644 index 0000000..1e04b0c --- /dev/null +++ b/05-jms/jms.logger/src/main/java/vs/ProducerNode.java @@ -0,0 +1,60 @@ +package vs; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.Destination; +import jakarta.jms.JMSException; +import jakarta.jms.MessageProducer; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +public class ProducerNode { + private Connection connection; + private Session session; + private MessageProducer producer; + + public ProducerNode() throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + connection = factory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination queue = (Destination) ctx.lookup(Conf.QUEUE); + producer = session.createProducer(queue); + } + + public void sendMessage(String text, String priority) throws JMSException { + TextMessage message = session.createTextMessage(); + message.setText(text); + message.setStringProperty("Priority", priority); + producer.send(message); + } + + public static void main(String[] args) { + String text = args[0]; + String priority = args[1]; + ProducerNode node = null; + try { + node = new ProducerNode(); + node.sendMessage(text, priority); + } catch (NamingException | JMSException e) { + System.err.println(e); + } finally { + try { + if (node != null && node.producer != null) { + node.producer.close(); + } + if (node != null && node.session != null) { + node.session.close(); + } + if (node != null && node.connection != null) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.logger/src/main/resources/jndi.properties b/05-jms/jms.logger/src/main/resources/jndi.properties new file mode 100644 index 0000000..14e1072 --- /dev/null +++ b/05-jms/jms.logger/src/main/resources/jndi.properties @@ -0,0 +1,4 @@ +java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory +java.naming.provider.url = tcp://localhost:61616 + +queue.vs.queue = queue4733 diff --git a/05-jms/jms.logger_solution/justfile b/05-jms/jms.logger_solution/justfile new file mode 100644 index 0000000..6009784 --- /dev/null +++ b/05-jms/jms.logger_solution/justfile @@ -0,0 +1,12 @@ +import '../justfile' + +wait_time_ms := "10000" + +consumer-sync: + just exec vs.ConsumerPullNode "{{wait_time_ms}}" +consumer-async-all: + just exec vs.ConsumerCallbackNode "{{wait_time_ms}}" +consumer-async-high: + just exec vs.ConsumerFilteredNode "{{wait_time_ms}}" +producer text prio: + just exec vs.ProducerNode "{{text}} {{prio}}" diff --git a/05-jms/jms.logger_solution/pom.xml b/05-jms/jms.logger_solution/pom.xml new file mode 100644 index 0000000..ffc4116 --- /dev/null +++ b/05-jms/jms.logger_solution/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + vs + jms.logger_solution + 1.0-SNAPSHOT + jar + + + vs + jms + 1.0-SNAPSHOT + + + diff --git a/05-jms/jms.logger_solution/src/main/java/vs/Conf.java b/05-jms/jms.logger_solution/src/main/java/vs/Conf.java new file mode 100644 index 0000000..d57b94a --- /dev/null +++ b/05-jms/jms.logger_solution/src/main/java/vs/Conf.java @@ -0,0 +1,16 @@ +package vs; + +/** + * global configuration for logger service + * + * @author Sandro Leuchter + * + */ +public class Conf { + /** + * String constant for the destination of logger service + * + * @see javax.jms.Destination + */ + public static final String QUEUE = "vs.queue"; +} diff --git a/05-jms/jms.logger_solution/src/main/java/vs/ConsumerCallbackNode.java b/05-jms/jms.logger_solution/src/main/java/vs/ConsumerCallbackNode.java new file mode 100644 index 0000000..427e0f7 --- /dev/null +++ b/05-jms/jms.logger_solution/src/main/java/vs/ConsumerCallbackNode.java @@ -0,0 +1,94 @@ +package vs; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.Destination; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageListener; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +/** + * asynchronous provider for the log service + * + * @author Sandro Leuchter + * + */ +public class ConsumerCallbackNode implements MessageListener { + private Connection connection; + private Session session; + private MessageConsumer consumer; + + /** + * constructor, establishes and starts connection to JMS provider specified in + * JNDI (via jndi.properties), afterwards consumer is ready + * + * @throws NamingException JNDI exceptions + * @throws JMSException JMS exceptions + */ + public ConsumerCallbackNode() throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + Destination queue = (Destination) ctx.lookup(Conf.QUEUE); + this.connection = factory.createConnection(); + this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + this.consumer = this.session.createConsumer(queue); + this.consumer.setMessageListener(this); + this.connection.start(); + } + + /** + * asynchronous message consumption + * + * @see jakarta.jms.MessageListener + */ + @Override + public void onMessage(Message message) { + try { + if (message instanceof TextMessage) { + TextMessage textMessage = (TextMessage) message; + String messageText = textMessage.getText(); + String priority = textMessage.getStringProperty("Priority"); + System.out.println(messageText + " [Priority=" + priority + "]"); + } + } catch (JMSException e) { + System.err.println(e); + } + + } + + /** + * main routine and starting point of program + * + * @param args[0] time to wait in ms + */ + public static void main(String[] args) { + long wait = Long.parseLong(args[0]); + ConsumerCallbackNode node = null; + try { + node = new ConsumerCallbackNode(); + Thread.sleep(wait); + } catch (InterruptedException | NamingException | JMSException e) { + System.err.println(e); + } finally { + try { + if ((node != null) && (node.consumer != null)) { + node.consumer.close(); + } + if ((node != null) && (node.session != null)) { + node.session.close(); + } + if ((node != null) && (node.connection != null)) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.logger_solution/src/main/java/vs/ConsumerFilteredNode.java b/05-jms/jms.logger_solution/src/main/java/vs/ConsumerFilteredNode.java new file mode 100644 index 0000000..98b45fb --- /dev/null +++ b/05-jms/jms.logger_solution/src/main/java/vs/ConsumerFilteredNode.java @@ -0,0 +1,97 @@ +package vs; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.Destination; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageListener; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +/** + * asynchronous provider for the log service, flitering only messages with + * String property "Priority"=="high" + * + * @author Sandro Leuchter + * + */ + +public class ConsumerFilteredNode implements MessageListener { + private Connection connection; + private Session session; + private MessageConsumer consumer; + + /** + * constructor, establishes and starts connection to JMS provider specified in + * JNDI (via jndi.properties), afterwards consumer is ready filtering only + * messages with String property "Priority" set to "high" + * + * @throws NamingException JNDI exceptions + * @throws JMSException JMS exceptions + */ + public ConsumerFilteredNode() throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + Destination queue = (Destination) ctx.lookup(Conf.QUEUE); + this.connection = factory.createConnection(); + this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + this.consumer = this.session.createConsumer(queue, "Priority='high'"); + this.consumer.setMessageListener(this); + this.connection.start(); + } + + /** + * asynchronous message consumption + * + * @see jakarta.jms.MessageListener + */ + @Override + public void onMessage(Message message) { + try { + if (message instanceof TextMessage) { + TextMessage textMessage = (TextMessage) message; + String messageText = textMessage.getText(); + String priority = textMessage.getStringProperty("Priority"); + System.out.println(messageText + " [Priority=" + priority + "]"); + } + } catch (JMSException e) { + System.err.println(e); + } + } + + /** + * main routine and starting point of program + * + * @param args[0] time to wait in ms + */ + public static void main(String[] args) { + long wait = Long.parseLong(args[0]); + ConsumerFilteredNode node = null; + try { + node = new ConsumerFilteredNode(); + Thread.sleep(wait); + } catch (InterruptedException | NamingException | JMSException e) { + System.err.println(e); + } finally { + try { + if ((node != null) && (node.consumer != null)) { + node.consumer.close(); + } + if ((node != null) && (node.session != null)) { + node.session.close(); + } + if ((node != null) && (node.connection != null)) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } + +} diff --git a/05-jms/jms.logger_solution/src/main/java/vs/ConsumerPullNode.java b/05-jms/jms.logger_solution/src/main/java/vs/ConsumerPullNode.java new file mode 100644 index 0000000..ec8ffd7 --- /dev/null +++ b/05-jms/jms.logger_solution/src/main/java/vs/ConsumerPullNode.java @@ -0,0 +1,92 @@ +package vs; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.Destination; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +/** + * synchronous provider for the log service + * + * @author Sandro Leuchter + * + */ + +public class ConsumerPullNode { + private Connection connection; + private Session session; + private MessageConsumer consumer; + + /** + * constructor, establishes and starts connection to JMS provider specified in + * JNDI (via jndi.properties), afterwards consumer is ready + * + * @throws NamingException JNDI exceptions + * @throws JMSException JMS exceptions + */ + public ConsumerPullNode() throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + Destination queue = (Destination) ctx.lookup(Conf.QUEUE); + this.connection = factory.createConnection(); + this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + this.consumer = this.session.createConsumer(queue); + this.connection.start(); + } + + /** + * synchronously receives the TextMessages in an infinite loop and prints + * payload text to StdOut + * + * @param timeout timeout in ms + * @see jakarta.jms.TextMessage + * @throws JMSException JMS exceptions + */ + public void receiveAndPrintMessages(long timeout) throws JMSException { + Message message; + while ((message = this.consumer.receive(timeout)) != null) { + if (message instanceof TextMessage) { + TextMessage textMessage = (TextMessage) message; + String messageText = textMessage.getText(); + System.out.println(messageText); + } + } + } + + /** + * main routine and starting point of program + * + * @param args[0] time to wait in ms + */ + public static void main(String[] args) { + long timeout = Long.parseLong(args[0]); + ConsumerPullNode node = null; + try { + node = new ConsumerPullNode(); + node.receiveAndPrintMessages(timeout); + } catch (NamingException | JMSException e) { + System.err.println(e); + } finally { + try { + if ((node != null) && (node.consumer != null)) { + node.consumer.close(); + } + if ((node != null) && (node.session != null)) { + node.session.close(); + } + if ((node != null) && (node.connection != null)) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.logger_solution/src/main/java/vs/ProducerNode.java b/05-jms/jms.logger_solution/src/main/java/vs/ProducerNode.java new file mode 100644 index 0000000..27e4cd1 --- /dev/null +++ b/05-jms/jms.logger_solution/src/main/java/vs/ProducerNode.java @@ -0,0 +1,88 @@ +package vs; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.Destination; +import jakarta.jms.JMSException; +import jakarta.jms.MessageProducer; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +/** + * client for the log service + * + * @author Sandro Leuchter + * + */ +public class ProducerNode { + private Connection connection; + private Session session; + private MessageProducer producer; + + /** + * constructor, establishes and starts connection to JMS provider specified in + * JNDI (via jndi.properties), afterwards producer is ready + * + * @throws NamingException JNDI exceptions + * @throws JMSException JMS exceptions + */ + public ProducerNode() throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + this.connection = factory.createConnection(); + this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination queue = (Destination) ctx.lookup(Conf.QUEUE); + this.producer = this.session.createProducer(queue); + } + + /** + * creates TextMessage for JMS provider sets String property "Priority" to value + * of parameter priority and sends message to Destination of producer, which is + * configured in Conf.QUEUE + * + * @param text payload of message + * @param priority value of String property "Priority" + * @throws JMSException JMS exceptions + */ + public void sendMessage(String text, String priority) throws JMSException { + TextMessage message = this.session.createTextMessage(); + message.setText(text); + message.setStringProperty("Priority", priority); + this.producer.send(message); + } + + /** + * main routine and starting point of program + * + * @param args[0] time to wait in ms + * @param args[1] of message ("high" or anything else) + */ + public static void main(String[] args) { + String text = args[0]; + String priority = args[1]; + ProducerNode node = null; + try { + node = new ProducerNode(); + node.sendMessage(text, priority); + } catch (NamingException | JMSException e) { + System.err.println(e); + } finally { + try { + if ((node != null) && (node.producer != null)) { + node.producer.close(); + } + if ((node != null) && (node.session != null)) { + node.session.close(); + } + if ((node != null) && (node.connection != null)) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.logger_solution/src/main/resources/jndi.properties b/05-jms/jms.logger_solution/src/main/resources/jndi.properties new file mode 100644 index 0000000..14e1072 --- /dev/null +++ b/05-jms/jms.logger_solution/src/main/resources/jndi.properties @@ -0,0 +1,4 @@ +java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory +java.naming.provider.url = tcp://localhost:61616 + +queue.vs.queue = queue4733 diff --git a/05-jms/jms.revers_solution/justfile b/05-jms/jms.revers_solution/justfile new file mode 100644 index 0000000..8288a5b --- /dev/null +++ b/05-jms/jms.revers_solution/justfile @@ -0,0 +1,8 @@ +import '../justfile' + +requester: + just exec vs.Anfrager "" +replier: + just exec vs.Umdreher "" +replier-reuse: + just exec vs.UmdreherReuseProducers "" diff --git a/05-jms/jms.revers_solution/pom.xml b/05-jms/jms.revers_solution/pom.xml new file mode 100644 index 0000000..edb86b0 --- /dev/null +++ b/05-jms/jms.revers_solution/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + vs + jms.revers_solution + 1.0-SNAPSHOT + jar + + + vs + jms + 1.0-SNAPSHOT + + + diff --git a/05-jms/jms.revers_solution/src/main/java/vs/Anfrager.java b/05-jms/jms.revers_solution/src/main/java/vs/Anfrager.java new file mode 100644 index 0000000..4b87cd5 --- /dev/null +++ b/05-jms/jms.revers_solution/src/main/java/vs/Anfrager.java @@ -0,0 +1,124 @@ +package vs; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageListener; +import jakarta.jms.MessageProducer; +import jakarta.jms.Queue; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +/** + * requester for String reverter service + * + * @author Sandro Leuchter + * + */ +public class Anfrager implements MessageListener { + private Connection connection; + private Session session; + private MessageProducer producer; + private MessageConsumer consumer; + private Queue replyQueue; + + /** + * constructor, establishes and starts connection to JMS provider specified in + * JNDI (via jndi.properties), afterwards producer and a consumer to a temporary + * replyQueue are ready + * + * @throws NamingException JNDI exceptions + * @throws JMSException JMS exceptions + */ + public Anfrager() throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + this.connection = factory.createConnection(); + this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = (Queue) ctx.lookup(Conf.QUEUE); + this.producer = this.session.createProducer(queue); + this.replyQueue = this.session.createTemporaryQueue(); + this.consumer = this.session.createConsumer(this.replyQueue); + this.consumer.setMessageListener(this); + this.connection.start(); + } + + /** + * asynchronous message consumption + * + * @see jakarta.jms.MessageListener + */ + @Override + public void onMessage(Message message) { + try { + if (message instanceof TextMessage) { + TextMessage textMessage = (TextMessage) message; + String messageText = textMessage.getText(); + System.out.println(messageText); + } + } catch (JMSException e) { + System.err.println(e); + } + + } + + /** + * creates TextMessage for JMS provider with temporary reply queue set and sends + * it to Destination of producer, which is configured in Conf.QUEUE + * + * @param text text to be sent + * @throws JMSException JMS exceptions + */ + public void sendMessage(String text) throws JMSException { + TextMessage message = this.session.createTextMessage(); + message.setText(text); + message.setJMSReplyTo(this.replyQueue); + this.producer.send(message); + } + + /** + * main routine and starting point of program + * + * @param args not used + */ + public static void main(String[] args) { + Anfrager node = null; + try { + node = new Anfrager(); + BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); + String line; + while (true) { + line = input.readLine(); + node.sendMessage(line); + } + } catch (NamingException | JMSException | IOException e) { + System.err.println(e); + } finally { + try { + if ((node != null) && (node.producer != null)) { + node.producer.close(); + } + if ((node != null) && (node.consumer != null)) { + node.consumer.close(); + } + if ((node != null) && (node.session != null)) { + node.session.close(); + } + if ((node != null) && (node.connection != null)) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.revers_solution/src/main/java/vs/Conf.java b/05-jms/jms.revers_solution/src/main/java/vs/Conf.java new file mode 100644 index 0000000..78724b4 --- /dev/null +++ b/05-jms/jms.revers_solution/src/main/java/vs/Conf.java @@ -0,0 +1,16 @@ +package vs; + +/** + * global configuration for String reverter service + * + * @author Sandro Leuchter + * + */ +public class Conf { + /** + * String constant for the request destination of String reverter service + * + * @see jakarta.jms.Destination + */ + public static final String QUEUE = "vs.revers"; +} diff --git a/05-jms/jms.revers_solution/src/main/java/vs/Umdreher.java b/05-jms/jms.revers_solution/src/main/java/vs/Umdreher.java new file mode 100644 index 0000000..0669ce0 --- /dev/null +++ b/05-jms/jms.revers_solution/src/main/java/vs/Umdreher.java @@ -0,0 +1,114 @@ +package vs; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageListener; +import jakarta.jms.MessageProducer; +import jakarta.jms.Queue; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +/** + * replier for String reverter service + * + * @author Sandro Leuchter + * + */ +public class Umdreher implements MessageListener { + private Connection connection; + private Session session; + private MessageConsumer consumer; + + /** + * constructor, establishes and starts connection to JMS provider specified in + * JNDI (via jndi.properties), afterwards a consumer is ready + * + * @throws NamingException JNDI exceptions + * @throws JMSException JMS exceptions + */ + public Umdreher() throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + Queue queue = (Queue) ctx.lookup(Conf.QUEUE); + this.connection = factory.createConnection(); + this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + this.consumer = this.session.createConsumer(queue); + this.consumer.setMessageListener(this); + this.connection.start(); + } + + /** + * actual implementation of reverse service + * + * @param in String to reverse + * @return reverse of in + */ + public String revers(String in) { + String out = ""; + for (char c : in.toCharArray()) { + out = c + out; + } + return out; + } + + /** + * asynchronous message consumption + * + * @see jakarta.jms.MessageListener + */ + @Override + public void onMessage(Message request) { + try { + if (request instanceof TextMessage) { + TextMessage requestText = (TextMessage) request; + System.out.println("empfangen: " + requestText.getText()); + MessageProducer replyProducer = this.session.createProducer(request.getJMSReplyTo()); + TextMessage reply = this.session.createTextMessage(); + reply.setText(revers(requestText.getText())); + replyProducer.send(reply); + replyProducer.close(); + Thread.sleep(3000); + } + } catch (JMSException | InterruptedException e) { + System.err.println(e); + } + + } + + /** + * main routine and starting point of program + * + * @param args not used + */ + public static void main(String[] args) { + Umdreher node = null; + try { + node = new Umdreher(); + while (true) { + Thread.sleep(1000); + } + } catch (InterruptedException | NamingException | JMSException e) { + System.err.println(e); + } finally { + try { + if ((node != null) && (node.consumer != null)) { + node.consumer.close(); + } + if ((node != null) && (node.session != null)) { + node.session.close(); + } + if ((node != null) && (node.connection != null)) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.revers_solution/src/main/java/vs/UmdreherReuseProducers.java b/05-jms/jms.revers_solution/src/main/java/vs/UmdreherReuseProducers.java new file mode 100644 index 0000000..5b5a25a --- /dev/null +++ b/05-jms/jms.revers_solution/src/main/java/vs/UmdreherReuseProducers.java @@ -0,0 +1,127 @@ +package vs; + +import java.util.HashMap; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.Destination; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageListener; +import jakarta.jms.MessageProducer; +import jakarta.jms.Queue; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +/** + * replier for String reverter service, reuses MessageProducer objects for + * temporary reply queues to requesters via replyProducers + * + * @author Sandro Leuchter + * + */ +public class UmdreherReuseProducers implements MessageListener { + private Connection connection; + private Session session; + private MessageConsumer consumer; + private HashMap replyProducers = new HashMap<>(); + + /** + * constructor, establishes and starts connection to JMS provider specified in + * JNDI (via jndi.properties), afterwards a consumer is ready + * + * @throws NamingException JNDI exceptions + * @throws JMSException JMS exceptions + */ + public UmdreherReuseProducers() throws NamingException, JMSException { + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + Queue queue = (Queue) ctx.lookup(Conf.QUEUE); + this.connection = factory.createConnection(); + this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + this.consumer = this.session.createConsumer(queue); + this.consumer.setMessageListener(this); + this.connection.start(); + } + + /** + * actual implementation of reverse service + * + * @param in String to reverse + * @return reverse of in + */ + public String revers(String in) { + String out = ""; + for (char c : in.toCharArray()) { + out = c + out; + } + return out; + } + + /** + * asynchronous message consumption + * + * @see jakarta.jms.MessageListener + */ + @Override + public void onMessage(Message request) { + try { + if (request instanceof TextMessage) { + TextMessage requestText = (TextMessage) request; + System.out.println("empfangen: " + requestText.getText()); + Destination replyQueue = request.getJMSReplyTo(); + MessageProducer replyProducer = null; + if (this.replyProducers.containsKey(replyQueue)) { + replyProducer = this.replyProducers.get(replyQueue); + System.out.println("Producer wird wiederverwendet: " + replyQueue.toString()); + } else { + replyProducer = this.session.createProducer(replyQueue); + this.replyProducers.put(replyQueue, replyProducer); + System.out.println("Producer wird neu erzeugt: " + replyQueue.toString()); + } + TextMessage reply = this.session.createTextMessage(); + reply.setText(revers(requestText.getText())); + replyProducer.send(reply); + Thread.sleep(1000); + } + } catch (JMSException | InterruptedException e) { + System.err.println(e); + } + + } + + /** + * main routine and starting point of program + * + * @param args not used + */ + public static void main(String[] args) { + UmdreherReuseProducers node = null; + try { + node = new UmdreherReuseProducers(); + while (true) { + Thread.sleep(1000); + } + } catch (InterruptedException | NamingException | JMSException e) { + System.err.println(e); + } finally { + try { + if ((node != null) && (node.consumer != null)) { + node.consumer.close(); + } + if ((node != null) && (node.session != null)) { + node.session.close(); + } + if ((node != null) && (node.connection != null)) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.revers_solution/src/main/resources/jndi.properties b/05-jms/jms.revers_solution/src/main/resources/jndi.properties new file mode 100644 index 0000000..16d2e40 --- /dev/null +++ b/05-jms/jms.revers_solution/src/main/resources/jndi.properties @@ -0,0 +1,6 @@ +java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory +java.naming.provider.url = tcp://localhost:61616 + +queue.vs.revers = queue4736 + + diff --git a/05-jms/jms.tasks_solution/justfile b/05-jms/jms.tasks_solution/justfile new file mode 100644 index 0000000..6596ce6 --- /dev/null +++ b/05-jms/jms.tasks_solution/justfile @@ -0,0 +1,6 @@ +import '../justfile' + +generator: + just exec vs.PasswordCandidateGenerator "" +validator: + just exec vs.PasswordCandidateValidator "" diff --git a/05-jms/jms.tasks_solution/pom.xml b/05-jms/jms.tasks_solution/pom.xml new file mode 100644 index 0000000..0d802a7 --- /dev/null +++ b/05-jms/jms.tasks_solution/pom.xml @@ -0,0 +1,22 @@ + + 4.0.0 + vs + jms.tasks_solution + 1.0-SNAPSHOT + jar + + + vs + jms + 1.0-SNAPSHOT + + + + + jakarta.xml.bind + jakarta.xml.bind-api + 4.0.2 + + + + diff --git a/05-jms/jms.tasks_solution/src/main/java/vs/Conf.java b/05-jms/jms.tasks_solution/src/main/java/vs/Conf.java new file mode 100644 index 0000000..edcfb26 --- /dev/null +++ b/05-jms/jms.tasks_solution/src/main/java/vs/Conf.java @@ -0,0 +1,6 @@ +package vs; + +public class Conf { + public static final String TASK_QUEUE = "vs.tasks"; + public static final String SUCCESS_TOPIC = "vs.tasksSuccess"; +} diff --git a/05-jms/jms.tasks_solution/src/main/java/vs/PasswordCandidateGenerator.java b/05-jms/jms.tasks_solution/src/main/java/vs/PasswordCandidateGenerator.java new file mode 100644 index 0000000..083f3f6 --- /dev/null +++ b/05-jms/jms.tasks_solution/src/main/java/vs/PasswordCandidateGenerator.java @@ -0,0 +1,90 @@ +package vs; + +import java.util.Random; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageListener; +import jakarta.jms.MessageProducer; +import jakarta.jms.Queue; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import jakarta.jms.Topic; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +public class PasswordCandidateGenerator implements MessageListener { + private Connection connection; + private Session session; + private MessageProducer producer; + private MessageConsumer consumer; + private Random random; + private boolean stopped = false; + + public PasswordCandidateGenerator() throws NamingException, JMSException { + this.random = new Random(); + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + this.connection = factory.createConnection(); + this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue taskQueue = (Queue) ctx.lookup(Conf.TASK_QUEUE); + this.producer = this.session.createProducer(taskQueue); + Topic successTopic = (Topic) ctx.lookup(Conf.SUCCESS_TOPIC); + this.consumer = this.session.createConsumer(successTopic); + this.consumer.setMessageListener(this); + this.connection.start(); + } + + @Override + public void onMessage(Message message) { + this.stopped = true; + System.out.println("Password gefunden. PasswordCandidateGenerator wird gestoppt."); + } + + public void sendMessage(String text) throws JMSException { + TextMessage message = this.session.createTextMessage(); + message.setText(text); + this.producer.send(message); + } + + public String generatePasswordCandidate(int length) { + StringBuilder buffer = new StringBuilder(length); + final int letterA = 97; + final int letterZ = 122; + for (int i = 0; i < length; i++) { + buffer.append((char) (letterA + (int) (this.random.nextFloat() * ((letterZ - letterA) + 1)))); + } + return buffer.toString(); + } + + public static void main(String[] args) { + PasswordCandidateGenerator node = null; + try { + node = new PasswordCandidateGenerator(); + while (!node.stopped) { + node.sendMessage(node.generatePasswordCandidate(8)); + } + } catch (NamingException | JMSException e) { + System.err.println(e); + } finally { + try { + if ((node != null) && (node.producer != null)) { + node.producer.close(); + } + if ((node != null) && (node.session != null)) { + node.session.close(); + } + if ((node != null) && (node.connection != null)) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } + +} diff --git a/05-jms/jms.tasks_solution/src/main/java/vs/PasswordCandidateValidator.java b/05-jms/jms.tasks_solution/src/main/java/vs/PasswordCandidateValidator.java new file mode 100644 index 0000000..23c1451 --- /dev/null +++ b/05-jms/jms.tasks_solution/src/main/java/vs/PasswordCandidateValidator.java @@ -0,0 +1,101 @@ +package vs; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +import jakarta.jms.Connection; +import jakarta.jms.ConnectionFactory; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageListener; +import jakarta.jms.Queue; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import jakarta.jms.Topic; +import jakarta.xml.bind.DatatypeConverter; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +public class PasswordCandidateValidator implements MessageListener { + private static int messageCounter = 0; + private final byte[] target; + private final MessageDigest dig; + private Connection connection; + private Session session; + private MessageConsumer taskConsumer; + private MessageConsumer successConsumer; + private boolean stopped = false; + + public PasswordCandidateValidator(String target) throws NamingException, JMSException, NoSuchAlgorithmException { + this.dig = MessageDigest.getInstance("SHA-256"); + this.target = DatatypeConverter.parseHexBinary(target); + Context ctx = new InitialContext(); + ConnectionFactory factory = (ConnectionFactory) ctx.lookup("ConnectionFactory"); + Queue queue = (Queue) ctx.lookup(Conf.TASK_QUEUE); + this.connection = factory.createConnection(); + this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + this.taskConsumer = this.session.createConsumer(queue); + this.taskConsumer.setMessageListener(this); + Topic successTopic = (Topic) ctx.lookup(Conf.SUCCESS_TOPIC); + this.successConsumer = this.session.createConsumer(successTopic); + this.successConsumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + PasswordCandidateValidator.this.stopped = true; + System.out.println("Password gefunden. PasswordCandidateValidator wird gestoppt."); + + } + }); + this.connection.start(); + } + + @Override + public void onMessage(Message message) { + synchronized (PasswordCandidateValidator.class) { + if (PasswordCandidateValidator.messageCounter++ >= 99) { + System.out.println(System.currentTimeMillis()); + PasswordCandidateValidator.messageCounter = 0; + } + } + if (message instanceof TextMessage) { + TextMessage task = (TextMessage) message; + try { + byte[] hash = this.dig.digest(task.getText().getBytes()); + if (Arrays.equals(hash, this.target)) { + System.out.println("Lösung gefunden: " + task.getText()); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } + + public static void main(String[] args) { + PasswordCandidateValidator node = null; + try { + node = new PasswordCandidateValidator("865ae56c298c677e9d4987fe13268fa915bd041646526c595d293d5448481443"); + while (!node.stopped) { + Thread.sleep(1000); + } + } catch (InterruptedException | NamingException | JMSException | NoSuchAlgorithmException e) { + System.err.println(e); + } finally { + try { + if ((node != null) && (node.taskConsumer != null)) { + node.taskConsumer.close(); + } + if ((node != null) && (node.session != null)) { + node.session.close(); + } + if ((node != null) && (node.connection != null)) { + node.connection.close(); + } + } catch (JMSException e) { + System.err.println(e); + } + } + } +} diff --git a/05-jms/jms.tasks_solution/src/main/resources/jndi.properties b/05-jms/jms.tasks_solution/src/main/resources/jndi.properties new file mode 100644 index 0000000..808fc1d --- /dev/null +++ b/05-jms/jms.tasks_solution/src/main/resources/jndi.properties @@ -0,0 +1,6 @@ +java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory +java.naming.provider.url = tcp://localhost:61616 + +queue.vs.tasks = passwordCandidates +topic.vs.tasksSuccess = passwordFound + diff --git a/05-jms/justfile b/05-jms/justfile new file mode 100644 index 0000000..8958e43 --- /dev/null +++ b/05-jms/justfile @@ -0,0 +1,4 @@ +import '../justfile' + +zed: + $VISUAL jms.client jms.client_solution jms.echo jms.echo_solution jms.logger jms.logger_solution jms.revers_solution jms.chat jms.chat_solution jms.tasks_solution diff --git a/05-jms/pom.xml b/05-jms/pom.xml new file mode 100644 index 0000000..199cd59 --- /dev/null +++ b/05-jms/pom.xml @@ -0,0 +1,22 @@ + + 4.0.0 + vs + jms + 1.0-SNAPSHOT + pom + + + vs + parent + 1.0-SNAPSHOT + + + + + org.apache.activemq + activemq-client + 6.1.3 + + + + diff --git a/06-mqtt/.gitignore b/06-mqtt/.gitignore new file mode 100644 index 0000000..6c6cee2 --- /dev/null +++ b/06-mqtt/.gitignore @@ -0,0 +1 @@ +*/paho* diff --git a/06-mqtt/justfile b/06-mqtt/justfile new file mode 100644 index 0000000..815694f --- /dev/null +++ b/06-mqtt/justfile @@ -0,0 +1,8 @@ +import '../justfile' + + +clean-paho: clean + rm -r paho* || true + +zed: + $VISUAL mqtt.logger mqtt.logger_solution mqtt.smarthome_solution diff --git a/06-mqtt/mqtt.code-workspace b/06-mqtt/mqtt.code-workspace new file mode 100644 index 0000000..69e60ae --- /dev/null +++ b/06-mqtt/mqtt.code-workspace @@ -0,0 +1,27 @@ +{ + "folders": [ + { + "name": "1. Logger", + "path": "mqtt.logger", + }, + { + "name": "1. Logger (ML)", + "path": "mqtt.logger_solution", + }, + { + "name": "2. Smarthome (ML)", + "path": "mqtt.smarthome_solution", + }, + ], + "extensions": { + "recommendations": [ + "vscjava.vscode-java-pack", + "ms-azuretools.vscode-docker", + "skellock.just", + ], + }, + "settings": { + "java.dependency.syncWithFolderExplorer": true, + "java.project.explorer.showNonJavaResources": false, + }, +} diff --git a/06-mqtt/mqtt.logger/justfile b/06-mqtt/mqtt.logger/justfile new file mode 100644 index 0000000..a3cacee --- /dev/null +++ b/06-mqtt/mqtt.logger/justfile @@ -0,0 +1,6 @@ +import '../justfile' + +publisher: + just exec vs.Publisher "" +subscriber: + just exec vs.Subscriber "" diff --git a/06-mqtt/mqtt.logger/pom.xml b/06-mqtt/mqtt.logger/pom.xml new file mode 100644 index 0000000..5971e09 --- /dev/null +++ b/06-mqtt/mqtt.logger/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + vs + mqtt.logger + 1.0-SNAPSHOT + jar + + + vs + mqtt + 1.0-SNAPSHOT + + + diff --git a/06-mqtt/mqtt.logger/src/main/java/vs/Conf.java b/06-mqtt/mqtt.logger/src/main/java/vs/Conf.java new file mode 100644 index 0000000..ba8093b --- /dev/null +++ b/06-mqtt/mqtt.logger/src/main/java/vs/Conf.java @@ -0,0 +1,7 @@ +package vs; + +public class Conf { + public static final String TOPIC = "var/mom/mqtt/4711/messages"; + // public static final String BROKER = "tcp://broker.mqttdashboard.com"; + public static final String BROKER = "tcp://localhost:1883"; +} diff --git a/06-mqtt/mqtt.logger/src/main/java/vs/Publisher.java b/06-mqtt/mqtt.logger/src/main/java/vs/Publisher.java new file mode 100644 index 0000000..85d758c --- /dev/null +++ b/06-mqtt/mqtt.logger/src/main/java/vs/Publisher.java @@ -0,0 +1,24 @@ +package vs; + +import java.util.Date; + +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; + +public class Publisher { + public static void main(String... args) { + var clientId = MqttClient.generateClientId(); + try (var client = new MqttClient(Conf.BROKER, clientId)) { + client.connect(); + var message = new MqttMessage(); + for (var i = 0; i < 30; i++) { + var m = "[" + clientId + "] message " + i + ": " + (new Date()).toString(); + message.setPayload(m.getBytes()); + client.publish(Conf.TOPIC, message); + } + } catch (MqttException e) { + System.err.println(e.getMessage()); + } + } +} diff --git a/06-mqtt/mqtt.logger/src/main/java/vs/Subscriber.java b/06-mqtt/mqtt.logger/src/main/java/vs/Subscriber.java new file mode 100644 index 0000000..89cf68f --- /dev/null +++ b/06-mqtt/mqtt.logger/src/main/java/vs/Subscriber.java @@ -0,0 +1,38 @@ +package vs; + +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttCallback; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; + +public class Subscriber { + public static void main(String... args) { + try (var client = new MqttClient(Conf.BROKER, MqttClient.generateClientId())) { + client.setCallback(new MqttCallback() { + + @Override + public void connectionLost(Throwable arg0) { + } + + @Override + public void deliveryComplete(IMqttDeliveryToken arg0) { + } + + @Override + public void messageArrived(String topic, MqttMessage m) throws Exception { + System.out.println("Topic: " + topic + ", Message: " + m.toString()); + } + }); + client.connect(); + client.subscribe(Conf.TOPIC); + while (true) { + Thread.sleep(1000); + } + } catch (MqttException e) { + System.err.println(e.getMessage()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } +} diff --git a/06-mqtt/mqtt.logger_solution/justfile b/06-mqtt/mqtt.logger_solution/justfile new file mode 100644 index 0000000..a3cacee --- /dev/null +++ b/06-mqtt/mqtt.logger_solution/justfile @@ -0,0 +1,6 @@ +import '../justfile' + +publisher: + just exec vs.Publisher "" +subscriber: + just exec vs.Subscriber "" diff --git a/06-mqtt/mqtt.logger_solution/pom.xml b/06-mqtt/mqtt.logger_solution/pom.xml new file mode 100644 index 0000000..9d6bfab --- /dev/null +++ b/06-mqtt/mqtt.logger_solution/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + vs + mqtt.logger_solution + 1.0-SNAPSHOT + jar + + + vs + mqtt + 1.0-SNAPSHOT + + + diff --git a/06-mqtt/mqtt.logger_solution/src/main/java/vs/Conf.java b/06-mqtt/mqtt.logger_solution/src/main/java/vs/Conf.java new file mode 100644 index 0000000..d5f1466 --- /dev/null +++ b/06-mqtt/mqtt.logger_solution/src/main/java/vs/Conf.java @@ -0,0 +1,16 @@ +package vs; + +public class Conf { + /** + * topic for the MQTT log service + */ + public static final String TOPIC = "vs/mqtt/topic/4715"; + + /** + * broker for the MQTT log service + */ + //public static final String BROKER = "tcp://localhost:1883"; // alternatively to + // HiveMQ + public static final String BROKER = "tcp://broker.mqttdashboard.com"; + // alternatively to ApacheMQ +} diff --git a/06-mqtt/mqtt.logger_solution/src/main/java/vs/Publisher.java b/06-mqtt/mqtt.logger_solution/src/main/java/vs/Publisher.java new file mode 100644 index 0000000..d00b941 --- /dev/null +++ b/06-mqtt/mqtt.logger_solution/src/main/java/vs/Publisher.java @@ -0,0 +1,41 @@ +package vs; + +import java.util.Date; + +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; + +/** + * client for the log service + * + * @author Sandro Leuchter + * + */ +public class Publisher { + + /** + * main routine and starting point of program + * + * @param args not used + */ + public static void main(String... args) { + var clientId = MqttClient.generateClientId(); + try (var client = new MqttClient(Conf.BROKER, clientId)) { + var options = new MqttConnectOptions(); + options.setWill(Conf.TOPIC, "LWT: Das war das Ende. Hilfe!".getBytes(), 2, false); + client.connect(options); + var message = new MqttMessage(); + for (var i = 29; i >= 0; i--) { + var m = "[" + clientId + "] message " + i + " (" + 29 / i + "): " + (new Date()).toString(); + message.setPayload(m.getBytes()); + message.setRetained(true); + client.publish(Conf.TOPIC, message); + } + client.disconnect(); + } catch (MqttException e) { + System.err.println(e.getMessage()); + } + } +} diff --git a/06-mqtt/mqtt.logger_solution/src/main/java/vs/Subscriber.java b/06-mqtt/mqtt.logger_solution/src/main/java/vs/Subscriber.java new file mode 100644 index 0000000..440f00f --- /dev/null +++ b/06-mqtt/mqtt.logger_solution/src/main/java/vs/Subscriber.java @@ -0,0 +1,52 @@ +package vs; + +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttCallback; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; + +/** + * asynchronous subscriber for the log service + * + * @author Sandro Leuchter + * + */ +public class Subscriber { + + /** + * main routine and starting point of program + * + * @param args not used + */ + public static void main(String... args) { + try (var client = new MqttClient(Conf.BROKER, MqttClient.generateClientId())) { + client.setCallback(new MqttCallback() { + + @Override + public void connectionLost(Throwable arg0) { + } + + @Override + public void deliveryComplete(IMqttDeliveryToken arg0) { + } + + @Override + public void messageArrived(String topic, MqttMessage m) throws Exception { + System.out.println("Topic: " + topic + ", Message: " + m.toString()); + } + }); + client.connect(); + client.subscribe(Conf.TOPIC); + while (true) { + Thread.sleep(1000); + } + } catch (MqttException e) { + System.err.println(e.getMessage()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } +} diff --git a/06-mqtt/mqtt.smarthome_solution/justfile b/06-mqtt/mqtt.smarthome_solution/justfile new file mode 100644 index 0000000..5b3b4c3 --- /dev/null +++ b/06-mqtt/mqtt.smarthome_solution/justfile @@ -0,0 +1,20 @@ +import '../justfile' + +scenario: + just sensor-self-descr groundfloor livingroom temperature 20.0 & + just sensor-self-descr groundfloor library temperature 16.0 & + just sensor-self-descr groundfloor kitchen temperature 24.0 & + just sensor-self-descr upstairs masterbedroom temperature 17.0 & + just plotter groundfloor temperature & + just logger + +sensor floor room type initial_double: + just exec vs.Sensor "{{floor}} {{room}} {{type}} {{initial_double}}" +sensor-self-descr floor room type initial_double: + just exec vs.Sensor "{{floor}} {{room}} {{type}} {{initial_double}}" +alarmer floor room type threshold_double: + just exec vs.AlarmSubscriber "{{floor}} {{room}} {{type}} {{threshold_double}}" +plotter floor type: + just exec vs.FloorPlotter "{{floor}} {{type}}" +logger: + just exec vs.LoggingSubscriber "" diff --git a/06-mqtt/mqtt.smarthome_solution/pom.xml b/06-mqtt/mqtt.smarthome_solution/pom.xml new file mode 100644 index 0000000..535d7d3 --- /dev/null +++ b/06-mqtt/mqtt.smarthome_solution/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + vs + mqtt.smarthome_solution + 1.0-SNAPSHOT + jar + + + vs + mqtt + 1.0-SNAPSHOT + + + diff --git a/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/AlarmSubscriber.java b/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/AlarmSubscriber.java new file mode 100644 index 0000000..b234c77 --- /dev/null +++ b/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/AlarmSubscriber.java @@ -0,0 +1,76 @@ +package vs; + +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttCallback; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; + +/** + * client for the Smart Home application: prints out alarm messages to the + * console if trigger condition in topic is detected + * + * @author Sandro Leuchter + * + */ +public class AlarmSubscriber { + /** + * trigger alarm if observation > threshold + */ + static double threshold; + + /** + * main routine and starting point of program: subscribes to topic + * Conf.TOPICSTART/args[0]/args[1]/args[2] i.e. a specific sensor and + * prints messages to console if observation > threshold + * + * @param args[0] floor where sensor is located + * @param args[1] room where sensor is located + * @param args[2] type of sensor + * @param args[3] threshold + * @throws MqttException Paho library exceptions that have something to do with MQTT + */ + public static void main(String[] args) throws MqttException { + String topic = Conf.TOPICSTART + "/" + args[0] + "/" + args[1] + "/" + args[2]; + threshold = Double.valueOf(args[3]); + MqttClient client = new MqttClient(Conf.BROKER, MqttClient.generateClientId()); + client.setCallback(new MqttCallback() { + @Override + public void messageArrived(String topic, MqttMessage m) throws Exception { + try { + double observation = Double.valueOf(m.toString()); + if (observation > threshold) { + System.out.println("ALARM: " + topic + ": " + m); + } + } catch (NumberFormatException e) { + System.out.println(m); // message is not a sensor + // observation: will be printed + // instead + } + } + + @Override + public void deliveryComplete(IMqttDeliveryToken arg0) { + } + + @Override + public void connectionLost(Throwable arg0) { + } + }); + client.connect(); + client.subscribe(topic); + try { + while (true) { + Thread.sleep(1000); + } + } catch (InterruptedException e) { + System.err.println(e.getMessage()); + } finally { + try { + client.disconnect(); + } catch (MqttException e) { + // unrecoverable + } + } + } +} diff --git a/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/Conf.java b/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/Conf.java new file mode 100644 index 0000000..a18741f --- /dev/null +++ b/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/Conf.java @@ -0,0 +1,22 @@ +package vs; + +public class Conf { + /** + * beginning topic level topic for the Smart Home Application + */ + public static final String TOPICSTART = "SmartHome4751"; // should be made + // unique + + /** + * broker for the Smart Home Application + */ + public static final String BROKER = "tcp://localhost:1883"; // alternatively + // to HiveMQ + // public static final String BROKER = "tcp://broker.mqttdashboard.com"; + // alternatively to ApacheMQ + + /** + * MQTT quality of service level for the Smart Home Application sensor messages + */ + public static final int QOS = 2; +} diff --git a/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/FloorPlotter.java b/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/FloorPlotter.java new file mode 100644 index 0000000..25e996d --- /dev/null +++ b/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/FloorPlotter.java @@ -0,0 +1,141 @@ +package vs; + +import java.awt.Color; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttCallback; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; + +/** + * client for the Smart Home application: plots graphically sensor observations + * + * @author Sandro Leuchter + * + */ +public class FloorPlotter extends Frame { + /** + * + */ + private static final long serialVersionUID = 8554414803806269611L; + private static FloorPlotter plot; + private static final int MAXX = 1000; + private static final int MAXY = 600; + private static Map topicColors = new HashMap<>(); + private static Color[] colors = { Color.red, Color.blue, Color.black, Color.cyan }; + private static int lastColor = 0; + private static Color[][] plotdata = new Color[MAXX][MAXY]; + private static long start = System.currentTimeMillis(); + private static String sensorType; + private static String floor; + + /** + * main routine and starting point of program. subscribes to all messages + * (sensor observations) on topic Conf.TOPICSTART/args[0]/+/args[1] + * i.e. all observations from a certain sensor type in all rooms on a certain + * floor. + * + * @param args[0] floor where sensor is located + * @param args[1] type of sensor + * @throws MqttException Paho library exceptions that have something to do with + * MQTT + * + */ + public static void main(String[] args) throws MqttException { + floor = args[0]; + sensorType = args[1]; + String topic = Conf.TOPICSTART + "/" + floor + "/+/" + sensorType; + + plot = new FloorPlotter(); + plot.setTitle("Floor Plot: " + floor); + plot.setSize(MAXX, MAXY); + plot.setVisible(true); + + MqttClient client = new MqttClient(Conf.BROKER, MqttClient.generateClientId()); + client.setCallback(new MqttCallback() { + + @Override + public void connectionLost(Throwable arg0) { + } + + @Override + public void deliveryComplete(IMqttDeliveryToken arg0) { + } + + @Override + public void messageArrived(String topic, MqttMessage m) throws Exception { + int x = (int) ((System.currentTimeMillis() - start) / 1000.0); + try { + double messwert = Double.valueOf(m.toString()); + int y = (int) Math.round(100.0 + (messwert * 10.0)); + String[] topicLevels = topic.split("/"); + String etage = topicLevels[1]; + String raum = topicLevels[2]; + if (!topicColors.containsKey(raum)) { + topicColors.put(raum, colors[lastColor++]); + System.out + .println("Dem Plot der Etage " + etage + " wurde der " + sensorType + "-Sensor im Raum " + + raum + " in der Farbe " + topicColors.get(raum).toString() + " hinzugefügt."); + } + // System.out.format("(%3d, %3d) <- %2.2f, %s\n", x, y, + // Double.valueOf(m.toString()), raum); + plotdata[x][y] = topicColors.get(raum); + plot.repaint(); + } catch (NumberFormatException e) { + System.out.println(m); // message is not an observation: + // will be printed out instead + } + } + }); + client.connect(); + client.subscribe(topic); + try { + while (true) { + Thread.sleep(1000); + } + } catch (InterruptedException e) { + System.err.println(e.getMessage()); + } finally { + try { + client.disconnect(); + } catch (MqttException e) { + // unrecoverable + } + } + } + + /** + * constructor. initializes window and adds WindowListener for close event + */ + public FloorPlotter() { + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent ev) { + dispose(); + System.exit(0); + } + }); + } + + /** + * @see java.awt.Frame#paint(Graphics) + */ + @Override + public void paint(Graphics g) { + for (int x = 0; x < MAXX; x++) { + for (int y = 0; y < MAXY; y++) { + if (plotdata[x][y] != null) { + g.setColor(plotdata[x][y]); + g.fillOval(x, y, 3, 3); + } + } + } + } +} diff --git a/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/LoggingSubscriber.java b/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/LoggingSubscriber.java new file mode 100644 index 0000000..e9487da --- /dev/null +++ b/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/LoggingSubscriber.java @@ -0,0 +1,60 @@ +package vs; + +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttCallback; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; + +/** + * client for the Smart Home application: logs sensor observations + * + * @author Sandro Leuchter + * + */ +public class LoggingSubscriber { + + /** + * main routine and starting point of program. subscribe to topic + * Conf.TOPICSTART/# i.e. all messages in the Smart Home Application + * + * @param args not used + * @throws MqttException Paho library exceptions that have something to do with + * MQTT + * + */ + public static void main(String[] args) throws MqttException { + MqttClient client; + client = new MqttClient(Conf.BROKER, MqttClient.generateClientId()); + client.setCallback(new MqttCallback() { + + @Override + public void connectionLost(Throwable arg0) { + } + + @Override + public void deliveryComplete(IMqttDeliveryToken arg0) { + } + + @Override + public void messageArrived(String topic, MqttMessage m) throws Exception { + System.out.println(topic + ": " + m.toString()); + } + }); + client.connect(); + client.subscribe(Conf.TOPICSTART + "/#"); + try { + while (true) { + Thread.sleep(1000); + } + } catch (InterruptedException e) { + System.err.println(e.getMessage()); + } finally { + try { + client.disconnect(); + } catch (MqttException e) { + // unrecoverable + } + } + } +} diff --git a/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/Sensor.java b/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/Sensor.java new file mode 100644 index 0000000..9e8825b --- /dev/null +++ b/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/Sensor.java @@ -0,0 +1,77 @@ +package vs; + +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; + +/** + * client for the Smart Home application: sensor simulator + * + * @author Sandro Leuchter + * + */ +public class Sensor { + /** + * topic to which this sensor publishes its observations + */ + static String topic; + /** + * floor where sensor is located + */ + static String floor; + /** + * room where sensor is located + */ + static String room; + /** + * type of sensor + */ + static String sensorType; + /** + * unique name of client + */ + static String clientId = MqttClient.generateClientId(); + + /** + * main routine and starting point of program + * + * @param args[0] floor where sensor is located + * @param args[1] room where sensor is located + * @param args[2] type of sensor + * @param args[3] initial observation of sensor + * @throws MqttException Paho library exceptions that have something to do with + * MQTT + * + */ + public static void main(String[] args) throws MqttException { + floor = args[0]; + room = args[1]; + sensorType = args[2]; + topic = Conf.TOPICSTART + "/" + floor + "/" + room + "/" + sensorType; + double lastObservation = Double.valueOf(args[3]); + MqttClient client; + client = new MqttClient(Conf.BROKER, clientId); + client.connect(); + MqttMessage message = new MqttMessage(); + try { + while (true) { + if (Math.random() > 0.5) { // randomly +/- 0.1 + lastObservation += 0.1; + } else { + lastObservation -= 0.1; + } + message.setPayload(String.valueOf(lastObservation).getBytes()); + client.publish(topic, message); + Thread.sleep((int) (Math.random() * 1000)); // < 1 s waiting + } + } catch (InterruptedException e) { + System.err.println(e.getMessage()); + } finally { + try { + client.disconnect(); + } catch (MqttException e) { + // unrecoverable + } + } + } +} diff --git a/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/SensorSelfDescribung.java b/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/SensorSelfDescribung.java new file mode 100644 index 0000000..7b4b942 --- /dev/null +++ b/06-mqtt/mqtt.smarthome_solution/src/main/java/vs/SensorSelfDescribung.java @@ -0,0 +1,93 @@ +package vs; + +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; + +/** + * client for the Smart Home application: sensor simulator + * + * @author Sandro Leuchter + * + */ +public class SensorSelfDescribung { + /** + * topic to which this sensor publishes its observations + */ + static String topic; + /** + * floor where sensor is located + */ + static String floor; + /** + * room where sensor is located + */ + static String room; + /** + * type of sensor + */ + static String sensorType; + /** + * unique name of client + */ + static String clientId = MqttClient.generateClientId(); + + /** + * get the description of sensor (class) + * + * @return description of sensor + */ + public static String getDescription() { + return clientId + "\n Topic: " + topic + "\n Type: " + sensorType + "\n Location: " + floor + "." + room; + } + + /** + * main routine and starting point of program + * + * @param args[0] floor where sensor is located + * @param args[1] room where sensor is located + * @param args[2] type of sensor + * @param args[3] initial observation of sensor + * @throws MqttException Paho library exceptions that have something to do with + * MQTT + * + */ + public static void main(String[] args) throws MqttException { + floor = args[0]; + room = args[1]; + sensorType = args[2]; + topic = Conf.TOPICSTART + "/" + floor + "/" + room + "/" + sensorType; + double lastObservation = Double.valueOf(args[3]); + MqttClient client; + client = new MqttClient(Conf.BROKER, clientId); + MqttConnectOptions options = new MqttConnectOptions(); + options.setWill(topic, ("deregistering sensor: " + getDescription()).getBytes(), Conf.QOS, true); + client.connect(options); + MqttMessage selfIntroduction = new MqttMessage(); + selfIntroduction.setRetained(true); + selfIntroduction.setPayload(("registering sensor: " + getDescription()).getBytes()); + client.publish(topic, selfIntroduction); + MqttMessage message = new MqttMessage(); + try { + while (true) { + if (Math.random() > 0.5) { // randomly +/- 0.1 + lastObservation += 0.1; + } else { + lastObservation -= 0.1; + } + message.setPayload(String.valueOf(lastObservation).getBytes()); + client.publish(topic, message); + Thread.sleep((int) (Math.random() * 1000)); // < 1 s waiting + } + } catch (InterruptedException e) { + System.err.println(e.getMessage()); + } finally { + try { + client.disconnect(); + } catch (MqttException e) { + // unrecoverable + } + } + } +} diff --git a/06-mqtt/pom.xml b/06-mqtt/pom.xml new file mode 100644 index 0000000..6f38cd5 --- /dev/null +++ b/06-mqtt/pom.xml @@ -0,0 +1,21 @@ + + 4.0.0 + vs + mqtt + 1.0-SNAPSHOT + pom + + + vs + parent + 1.0-SNAPSHOT + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + 1.2.5 + + + diff --git a/07-http/http.webserver/justfile b/07-http/http.webserver/justfile new file mode 100644 index 0000000..3d38c15 --- /dev/null +++ b/07-http/http.webserver/justfile @@ -0,0 +1,6 @@ +import '../../justfile' + +server: + just exec vs.WebServer "" +client: + firefox http://localhost:8000/form.html diff --git a/07-http/http.webserver/pom.xml b/07-http/http.webserver/pom.xml new file mode 100644 index 0000000..876a94a --- /dev/null +++ b/07-http/http.webserver/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + vs + http.webserver + 1.0-SNAPSHOT + jar + + + vs + http + 1.0-SNAPSHOT + + diff --git a/07-http/http.webserver/src/main/java/vs/WebServer.java b/07-http/http.webserver/src/main/java/vs/WebServer.java new file mode 100644 index 0000000..0301600 --- /dev/null +++ b/07-http/http.webserver/src/main/java/vs/WebServer.java @@ -0,0 +1,59 @@ +package vs; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; + +public class WebServer { + public void start() { + try (ServerSocket serverSocket = new ServerSocket(8000)) { + System.out.println("WebServer gestartet ..."); + while (true) { + Socket socket = serverSocket.accept(); + new WebThread(socket).start(); + } + } catch (IOException e) { + System.err.println(e); + } + } + + private class WebThread extends Thread { + private Socket socket; + + public WebThread(Socket socket) { + this.socket = socket; + } + + @Override + public void run() { + SocketAddress socketAddress = socket.getRemoteSocketAddress(); + System.err.println("Verbindung zu " + socketAddress + " aufgebaut"); + try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) { + String input; + while (null != (input = in.readLine())) { + System.out.println(input); + } + } catch (Exception e) { + System.err.println(e); + } finally { + try { + socket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + System.err.println("Verbindung zu " + socketAddress + " abgebaut"); + } + } + + } + + public static void main(String[] args) { + new WebServer().start(); + } +} diff --git a/07-http/http.webserver/src/main/resources/docs/form.html b/07-http/http.webserver/src/main/resources/docs/form.html new file mode 100644 index 0000000..5956718 --- /dev/null +++ b/07-http/http.webserver/src/main/resources/docs/form.html @@ -0,0 +1,14 @@ + + +
+Latein
+Hochschule Mannheim
+unknown
+ +
+
+/http/WebServer.java
+../src/var/web/http/WebServer.java
+verteilteArchitekturen.html
+ + \ No newline at end of file diff --git a/07-http/http.webserver/src/main/resources/docs/img/by-nc-sa1.png b/07-http/http.webserver/src/main/resources/docs/img/by-nc-sa1.png new file mode 100644 index 0000000000000000000000000000000000000000..b9a55533c0cb035de1769b2a5ac63ce9b194fc69 GIT binary patch literal 22475 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 V_bKxY2;ODV(a=9ucJy?}e*pE>jWz%P literal 0 HcmV?d00001 diff --git a/07-http/http.webserver_solution/justfile b/07-http/http.webserver_solution/justfile new file mode 100644 index 0000000..3d38c15 --- /dev/null +++ b/07-http/http.webserver_solution/justfile @@ -0,0 +1,6 @@ +import '../../justfile' + +server: + just exec vs.WebServer "" +client: + firefox http://localhost:8000/form.html diff --git a/07-http/http.webserver_solution/pom.xml b/07-http/http.webserver_solution/pom.xml new file mode 100644 index 0000000..8db8ef0 --- /dev/null +++ b/07-http/http.webserver_solution/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + vs + http.webserver_solution + 1.0-SNAPSHOT + jar + + + vs + http + 1.0-SNAPSHOT + + diff --git a/07-http/http.webserver_solution/src/main/java/vs/WebServer.java b/07-http/http.webserver_solution/src/main/java/vs/WebServer.java new file mode 100644 index 0000000..8797f3c --- /dev/null +++ b/07-http/http.webserver_solution/src/main/java/vs/WebServer.java @@ -0,0 +1,123 @@ +package vs; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; + +enum Type { + REQ1, REQ2, FILE, UNKNOWN; +} + +public class WebServer { + public void start() { + try (ServerSocket serverSocket = new ServerSocket(8000)) { + System.out.println("WebServer gestartet ..."); + while (true) { + Socket socket = serverSocket.accept(); + new WebThread(socket).start(); + } + } catch (IOException e) { + System.err.println(e); + } + } + + private class WebThread extends Thread { + private Socket socket; + + public WebThread(Socket socket) { + this.socket = socket; + } + + @Override + public void run() { + SocketAddress socketAddress = this.socket.getRemoteSocketAddress(); + System.err.println("Verbindung zu " + socketAddress + " aufgebaut"); + try (BufferedReader in = new BufferedReader(new InputStreamReader(this.socket.getInputStream())); + PrintWriter out = new PrintWriter(this.socket.getOutputStream(), true)) { + String input; + Type type = Type.UNKNOWN; + String fileName = ""; + input = in.readLine(); + if (input.matches("^GET /cgi/choice\\?selection=Latein HTTP/\\d\\.\\d$")) { + type = Type.REQ1; + } else if (input.matches("^GET /cgi/choice\\?selection=HS-Mannheim HTTP/\\d\\.\\d$")) { + type = Type.REQ2; + } else if (input.matches("^GET (.+) HTTP/\\d\\.\\d$")) { + type = Type.FILE; + fileName = input.substring(4); // "GET " abschneiden + fileName = fileName.substring(0, fileName.length() - 9); // " HTTPx.x" abschneiden + } else { + type = Type.UNKNOWN; + } + while (!"".equals(input = in.readLine())) { + System.out.println(input); + } + File file = null; + if (type == Type.FILE) { + file = new File("target/classes/docs" + fileName); + if (!file.canRead()) { + type = Type.UNKNOWN; + } + } + switch (type) { + case REQ1: + out.printf("HTTP/1.1 200 OK\r\n"); + out.printf("Content-Type: text/html; charset=utf-8\r\n"); + out.printf("\r\n"); + out.printf("Non scholae sed vitae discimus.\r\n"); + break; + case REQ2: + out.printf("HTTP/1.1 200 OK\r\n"); + out.printf("Content-Type: text/html; charset=utf-8\r\n"); + out.printf("\r\n"); + out.printf( + "Die Hochschule Mannheim ist bekannt für eine praxisnahe und theoretisch fundierte Ausbildung\r\n"); + break; + case FILE: + out.printf("HTTP/1.1 200 OK\r\n"); + if ("html".equalsIgnoreCase(fileName.substring(fileName.length() - 4))) { + out.printf("Content-Type: text/html; charset=utf-8\r\n"); + } else { + out.printf("Content-Type: application/octet-stream\r\n"); + } + out.printf("\r\n"); + FileInputStream fileIn = new FileInputStream(file); + OutputStream outBin = this.socket.getOutputStream(); + int c; + while ((c = fileIn.read()) != -1) { + outBin.write(c); + } + outBin.close(); + break; + case UNKNOWN: + out.printf("HTTP/1.1 404 Not Found\r\n"); + out.printf("Content-Type: text/plain; charset=utf-8\r\n"); + out.printf("\r\n"); + out.printf("nicht gefunden\r\n"); + break; + } + } catch (Exception e) { + System.err.println(e); + } finally { + try { + this.socket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + System.err.println("Verbindung zu " + socketAddress + " abgebaut"); + } + } + + } + + public static void main(String[] args) { + new WebServer().start(); + } +} diff --git a/07-http/http.webserver_solution/src/main/resources/docs/form.html b/07-http/http.webserver_solution/src/main/resources/docs/form.html new file mode 100644 index 0000000..e7d8e85 --- /dev/null +++ b/07-http/http.webserver_solution/src/main/resources/docs/form.html @@ -0,0 +1,13 @@ + + +
+Latein
+Hochschule Mannheim
+unknown
+ +
+
+/http/WebServer.java
+verteilteArchitekturen.html
+ + diff --git a/07-http/http.webserver_solution/src/main/resources/docs/http/WebServer.java b/07-http/http.webserver_solution/src/main/resources/docs/http/WebServer.java new file mode 100644 index 0000000..8797f3c --- /dev/null +++ b/07-http/http.webserver_solution/src/main/resources/docs/http/WebServer.java @@ -0,0 +1,123 @@ +package vs; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; + +enum Type { + REQ1, REQ2, FILE, UNKNOWN; +} + +public class WebServer { + public void start() { + try (ServerSocket serverSocket = new ServerSocket(8000)) { + System.out.println("WebServer gestartet ..."); + while (true) { + Socket socket = serverSocket.accept(); + new WebThread(socket).start(); + } + } catch (IOException e) { + System.err.println(e); + } + } + + private class WebThread extends Thread { + private Socket socket; + + public WebThread(Socket socket) { + this.socket = socket; + } + + @Override + public void run() { + SocketAddress socketAddress = this.socket.getRemoteSocketAddress(); + System.err.println("Verbindung zu " + socketAddress + " aufgebaut"); + try (BufferedReader in = new BufferedReader(new InputStreamReader(this.socket.getInputStream())); + PrintWriter out = new PrintWriter(this.socket.getOutputStream(), true)) { + String input; + Type type = Type.UNKNOWN; + String fileName = ""; + input = in.readLine(); + if (input.matches("^GET /cgi/choice\\?selection=Latein HTTP/\\d\\.\\d$")) { + type = Type.REQ1; + } else if (input.matches("^GET /cgi/choice\\?selection=HS-Mannheim HTTP/\\d\\.\\d$")) { + type = Type.REQ2; + } else if (input.matches("^GET (.+) HTTP/\\d\\.\\d$")) { + type = Type.FILE; + fileName = input.substring(4); // "GET " abschneiden + fileName = fileName.substring(0, fileName.length() - 9); // " HTTPx.x" abschneiden + } else { + type = Type.UNKNOWN; + } + while (!"".equals(input = in.readLine())) { + System.out.println(input); + } + File file = null; + if (type == Type.FILE) { + file = new File("target/classes/docs" + fileName); + if (!file.canRead()) { + type = Type.UNKNOWN; + } + } + switch (type) { + case REQ1: + out.printf("HTTP/1.1 200 OK\r\n"); + out.printf("Content-Type: text/html; charset=utf-8\r\n"); + out.printf("\r\n"); + out.printf("Non scholae sed vitae discimus.\r\n"); + break; + case REQ2: + out.printf("HTTP/1.1 200 OK\r\n"); + out.printf("Content-Type: text/html; charset=utf-8\r\n"); + out.printf("\r\n"); + out.printf( + "Die Hochschule Mannheim ist bekannt für eine praxisnahe und theoretisch fundierte Ausbildung\r\n"); + break; + case FILE: + out.printf("HTTP/1.1 200 OK\r\n"); + if ("html".equalsIgnoreCase(fileName.substring(fileName.length() - 4))) { + out.printf("Content-Type: text/html; charset=utf-8\r\n"); + } else { + out.printf("Content-Type: application/octet-stream\r\n"); + } + out.printf("\r\n"); + FileInputStream fileIn = new FileInputStream(file); + OutputStream outBin = this.socket.getOutputStream(); + int c; + while ((c = fileIn.read()) != -1) { + outBin.write(c); + } + outBin.close(); + break; + case UNKNOWN: + out.printf("HTTP/1.1 404 Not Found\r\n"); + out.printf("Content-Type: text/plain; charset=utf-8\r\n"); + out.printf("\r\n"); + out.printf("nicht gefunden\r\n"); + break; + } + } catch (Exception e) { + System.err.println(e); + } finally { + try { + this.socket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + System.err.println("Verbindung zu " + socketAddress + " abgebaut"); + } + } + + } + + public static void main(String[] args) { + new WebServer().start(); + } +} diff --git a/07-http/http.webserver_solution/src/main/resources/docs/img/by-nc-sa1.png b/07-http/http.webserver_solution/src/main/resources/docs/img/by-nc-sa1.png new file mode 100644 index 0000000000000000000000000000000000000000..b9a55533c0cb035de1769b2a5ac63ce9b194fc69 GIT binary patch literal 22475 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 V_bKxY2;ODV(a=9ucJy?}e*pE>jWz%P literal 0 HcmV?d00001 diff --git a/07-http/pom.xml b/07-http/pom.xml new file mode 100644 index 0000000..702ec96 --- /dev/null +++ b/07-http/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + vs + http + 1.0-SNAPSHOT + pom + + + vs + parent + 1.0-SNAPSHOT + + + diff --git a/08-servlet/justfile b/08-servlet/justfile new file mode 100644 index 0000000..dbba21b --- /dev/null +++ b/08-servlet/justfile @@ -0,0 +1,7 @@ +import '../justfile' + +serve: war + mvn jetty:run +war: + mvn war:war + touch src/main/webapp/index.html diff --git a/08-servlet/pom.xml b/08-servlet/pom.xml new file mode 100644 index 0000000..29ea3d3 --- /dev/null +++ b/08-servlet/pom.xml @@ -0,0 +1,37 @@ + + 4.0.0 + vs + servlet + 1.0-SNAPSHOT + pom + + + vs + parent + 1.0-SNAPSHOT + + + + + jakarta.servlet + jakarta.servlet-api + 6.0.0 + provided + + + + + + + org.eclipse.jetty.ee10 + jetty-ee10-maven-plugin + 12.0.14 + + + org.apache.maven.plugins + maven-war-plugin + 3.4.0 + + + + diff --git a/08-servlet/servlet.hello/justfile b/08-servlet/servlet.hello/justfile new file mode 100644 index 0000000..f8066da --- /dev/null +++ b/08-servlet/servlet.hello/justfile @@ -0,0 +1,4 @@ +import '../justfile' + +client: + firefox http://localhost:8080/ diff --git a/08-servlet/servlet.hello/pom.xml b/08-servlet/servlet.hello/pom.xml new file mode 100644 index 0000000..4bd885b --- /dev/null +++ b/08-servlet/servlet.hello/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + vs + servlet.hello + 1.0-SNAPSHOT + war + + + vs + servlet + 1.0-SNAPSHOT + + + diff --git a/08-servlet/servlet.hello/src/main/java/vs/HelloWorld.java b/08-servlet/servlet.hello/src/main/java/vs/HelloWorld.java new file mode 100644 index 0000000..e1970fa --- /dev/null +++ b/08-servlet/servlet.hello/src/main/java/vs/HelloWorld.java @@ -0,0 +1,84 @@ +package vs; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Enumeration; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * Servlet implementation class HelloWorld + */ +@WebServlet(urlPatterns = { "/HelloWorld", "/vs", "/hello" }) +public class HelloWorld extends HttpServlet { + /** + * + */ + private static final long serialVersionUID = -3570303195316235943L; + private Integer counter = 0; + + /** + * @see HttpServlet#HttpServlet() + */ + public HelloWorld() { + super(); + } + + /** + * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse + * response) + */ + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + out.println("HTTPRequest Inhalte ausgeben"); + // Header + out.println("

Header

    "); + Enumeration headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + out.println("
  • " + headerName + ": " + request.getHeader(headerName)); + } + out.println("
"); + + // Parameter + out.println("

Parameter

    "); + Enumeration parameterNames = request.getParameterNames(); + while (parameterNames.hasMoreElements()) { + String parameterName = parameterNames.nextElement(); + out.println("
  • " + parameterName + ": " + request.getParameter(parameterName)); + } + out.println("
"); + + // Zugriffszähler + out.println("

Zugriffszähler