From e6b5cac53caceb870c26b8db268a1699333f0a85 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 5 Mar 2026 13:28:04 +0100 Subject: [PATCH 01/25] Add: SessionId class to uniquely identify session in SessionRegistry --- .../casono/common/network/SessionId.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/SessionId.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/SessionId.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/SessionId.java new file mode 100644 index 0000000..a7cafa4 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/SessionId.java @@ -0,0 +1,22 @@ +package ch.unibas.dmi.dbis.cs108.casono.common.network; + +import java.util.UUID; + +public class SessionId { + /** + * The session id is used to identify a unique client connection in the SessionRegistry + */ + private final UUID value; + + public SessionId() { + this.value = UUID.randomUUID(); + } + + public SessionId(UUID value) { + this.value = value; + } + + public UUID value() { + return value; + } +} -- 2.52.0 From ff38c9d6ef8fce0bedafaba6e2489bd6484c9e64 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 5 Mar 2026 13:28:04 +0100 Subject: [PATCH 02/25] Add: SessionId class to uniquely identify session in SessionRegistry --- .../unibas/dmi/dbis/cs108/casono/common/network/SessionId.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/SessionId.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/SessionId.java index a7cafa4..fded15a 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/SessionId.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/SessionId.java @@ -4,7 +4,7 @@ import java.util.UUID; public class SessionId { /** - * The session id is used to identify a unique client connection in the SessionRegistry + * The SessionId is used to identify a unique client connection in the SessionRegistry */ private final UUID value; -- 2.52.0 From 66925bc66541c5db0275380ccd42da8efb5e864f Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 5 Mar 2026 13:46:10 +0100 Subject: [PATCH 03/25] Add: Session interface all sessions need to conform to --- .../dbis/cs108/casono/common/network/Session.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/Session.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/Session.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/Session.java new file mode 100644 index 0000000..f4ac359 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/Session.java @@ -0,0 +1,13 @@ +package ch.unibas.dmi.dbis.cs108.casono.common.network; + +public interface Session { + /** + * Outlines an interface all session implementations have to conform to + */ + + SessionId id(); + + void send(byte[] payload); + + void close(); +} \ No newline at end of file -- 2.52.0 From 91a513e2148e533ea5c77dbf56b5f2b7d99676c9 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Mon, 9 Mar 2026 15:30:50 +0100 Subject: [PATCH 04/25] Add: Readme explaining the purpose, format and links to existing blog posts --- documents/docs/blog/README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 documents/docs/blog/README.md diff --git a/documents/docs/blog/README.md b/documents/docs/blog/README.md new file mode 100644 index 0000000..aa92b15 --- /dev/null +++ b/documents/docs/blog/README.md @@ -0,0 +1,28 @@ +# Blog + +## Purpose +This folder contains a collection of blog posts documenting the development process of our application. These blogs serve two key purposes: + +1. **For External Audiences** + + The blogs provide insights into the internal program flow and the interaction between components without requiring readers to dive into the source code. They offer a mixed-level overview of how different parts of the system work together. + +2. **For Our Team** + + The blogs serve as a record of our decision-making process. By documenting what decisions were made and why, we can track the evolution of our design choices and understand the reasoning behind them. This is invaluable for maintaining consistency across the team. + +But keep in mind that these blogs **do not replace** the detailed source code documentation. + +## Format +All blog posts follow the naming convention: `_.md` + +## Blog Posts + +### General +*(No posts yet)* + +### Client +*(No posts yet)* + +### Server +*(No posts yet)* -- 2.52.0 From 9c291e4e3bcdd2cf08cac8cac4180cd15aad818e Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Mon, 9 Mar 2026 15:37:26 +0100 Subject: [PATCH 05/25] Revert "Add: Readme explaining the purpose, format and links to existing blog posts" This reverts commit 91a513e2148e533ea5c77dbf56b5f2b7d99676c9. --- documents/docs/blog/README.md | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 documents/docs/blog/README.md diff --git a/documents/docs/blog/README.md b/documents/docs/blog/README.md deleted file mode 100644 index aa92b15..0000000 --- a/documents/docs/blog/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Blog - -## Purpose -This folder contains a collection of blog posts documenting the development process of our application. These blogs serve two key purposes: - -1. **For External Audiences** - - The blogs provide insights into the internal program flow and the interaction between components without requiring readers to dive into the source code. They offer a mixed-level overview of how different parts of the system work together. - -2. **For Our Team** - - The blogs serve as a record of our decision-making process. By documenting what decisions were made and why, we can track the evolution of our design choices and understand the reasoning behind them. This is invaluable for maintaining consistency across the team. - -But keep in mind that these blogs **do not replace** the detailed source code documentation. - -## Format -All blog posts follow the naming convention: `<YYYY-MM-DD>_<Title>.md` - -## Blog Posts - -### General -*(No posts yet)* - -### Client -*(No posts yet)* - -### Server -*(No posts yet)* -- 2.52.0 From dac05de331631b3708fc6081a308c8b1bd77562b Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Wed, 11 Mar 2026 18:23:26 +0100 Subject: [PATCH 06/25] Add: Primitive first version of NetworkManager --- .../dbis/cs108/casono/server/ServerApp.java | 5 +++ .../casono/server/network/NetworkManager.java | 44 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java index 520dc6b..e7dd3f3 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java @@ -1,8 +1,13 @@ package ch.unibas.dmi.dbis.cs108.casono.server; +import ch.unibas.dmi.dbis.cs108.casono.server.network.NetworkManager; + public class ServerApp { public static void start(String arg) { int port = Integer.parseInt(arg); System.out.println("You've selected the server. It will accept connections at port " + port); + + NetworkManager networkManager = new NetworkManager(port); + networkManager.start(); } } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java new file mode 100644 index 0000000..c23f20a --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java @@ -0,0 +1,44 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.network; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import ch.unibas.dmi.dbis.cs108.casono.common.network.Session; + +public class NetworkManager implements Runnable { + private Integer port; + private Logger logger; + private Thread thread; + private Boolean running; + + public NetworkManager(Integer port) { + this.port = port; + this.logger = LogManager.getLogger(NetworkManager.class); + this.thread = new Thread(this, "networkManager"); + this.running = true; + } + + public void start() { + logger.debug("Starting server at port " + port); + thread.start(); + } + + @Override + public void run() { + try (ServerSocket serverSocket = new ServerSocket(port)) { + while (running) { + Socket clientSocket = serverSocket.accept(); + + System.out.println("Accepted connection from " + clientSocket.getRemoteSocketAddress()); + clientSocket.close(); + } + + } catch (IOException e) { + logger.fatal(e); + } + } +} -- 2.52.0 From 5ff4dcec53cb33b23d4468874efe7466d4d39fa3 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Wed, 11 Mar 2026 18:53:30 +0100 Subject: [PATCH 07/25] Move: Session and SessionId from common to server --- .../dbis/cs108/casono/{common => server}/network/Session.java | 4 ++-- .../cs108/casono/{common => server}/network/SessionId.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/main/java/ch/unibas/dmi/dbis/cs108/casono/{common => server}/network/Session.java (74%) rename src/main/java/ch/unibas/dmi/dbis/cs108/casono/{common => server}/network/SessionId.java (87%) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/Session.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java similarity index 74% rename from src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/Session.java rename to src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java index f4ac359..d4231fb 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/Session.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java @@ -1,9 +1,9 @@ -package ch.unibas.dmi.dbis.cs108.casono.common.network; +package ch.unibas.dmi.dbis.cs108.casono.server.network; public interface Session { /** * Outlines an interface all session implementations have to conform to - */ + */ SessionId id(); diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/SessionId.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionId.java similarity index 87% rename from src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/SessionId.java rename to src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionId.java index fded15a..0af06ad 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/common/network/SessionId.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionId.java @@ -1,4 +1,4 @@ -package ch.unibas.dmi.dbis.cs108.casono.common.network; +package ch.unibas.dmi.dbis.cs108.casono.server.network; import java.util.UUID; -- 2.52.0 From 5407e245f732294235ce61c18fddb38be48fcd8b Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Thu, 12 Mar 2026 13:43:35 +0100 Subject: [PATCH 08/25] Add: Modify NetworkManager to create Session uppon recieving a new connection --- .../cs108/casono/server/network/NetworkManager.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java index c23f20a..ca579ba 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java @@ -7,8 +7,9 @@ import java.net.Socket; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import ch.unibas.dmi.dbis.cs108.casono.common.network.Session; - +/** + * Creates and manages the server socket. Accepts new incomming connections and creates sessions. + */ public class NetworkManager implements Runnable { private Integer port; private Logger logger; @@ -22,6 +23,8 @@ public class NetworkManager implements Runnable { this.running = true; } + /* Starts the internal thread to accept new connections. + */ public void start() { logger.debug("Starting server at port " + port); thread.start(); @@ -32,9 +35,11 @@ public class NetworkManager implements Runnable { try (ServerSocket serverSocket = new ServerSocket(port)) { while (running) { Socket clientSocket = serverSocket.accept(); - + System.out.println("Accepted connection from " + clientSocket.getRemoteSocketAddress()); - clientSocket.close(); + + Session session = new Session(clientSocket); + session.start(); } } catch (IOException e) { -- 2.52.0 From f4a32b1649b956fe06b71a353b1bf3765f6384df Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Thu, 12 Mar 2026 13:45:30 +0100 Subject: [PATCH 09/25] Add: Session Runnable to read incomming data, decode and print it --- .../cs108/casono/server/network/Session.java | 66 +++++++++++++++++-- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java index d4231fb..855b9be 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java @@ -1,13 +1,65 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network; -public interface Session { - /** - * Outlines an interface all session implementations have to conform to - */ +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.net.Socket; +import java.nio.charset.StandardCharsets; - SessionId id(); +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; - void send(byte[] payload); +public class Session implements Runnable { + private SessionId id; + private Thread thread; + private Socket socket; + private DataInputStream in; + private DataOutputStream out; + private Logger logger; + + public Session(Socket socket) throws IOException { + this.id = new SessionId(); + this.thread = new Thread(this, "session-" + this.id.value()); + this.socket = socket; + this.in = new DataInputStream(socket.getInputStream()); + this.out = new DataOutputStream(socket.getOutputStream()); - void close(); + this.logger = LogManager.getLogger(Session.class.toString() + id.value()); + this.logger.info("Created new session"); + } + + public SessionId getId() { + return this.id; + } + + public void start() { + thread.start(); + } + + public String read() throws IOException { + int length = in.readInt(); + byte[] payload = new byte[length]; + in.readFully(payload); + return new String(payload, StandardCharsets.UTF_8); + } + + public void close() throws IOException { + socket.close(); + } + + @Override + public void run() { + while (true) { + try { + System.out.println("Recieved: " + read()); + } catch (EOFException e) { + logger.info("Client disconnected"); + break; + } catch (IOException e) { + e.printStackTrace(); + break; + } + } + } } \ No newline at end of file -- 2.52.0 From 48d77b6cbe3bb0825dfc37f330595ae57d07a352 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Thu, 12 Mar 2026 15:41:23 +0100 Subject: [PATCH 10/25] Add: TransportLayer interface to abstract direct socket access --- .../dbis/cs108/casono/server/network/TransportLayer.java | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/TransportLayer.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/TransportLayer.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/TransportLayer.java new file mode 100644 index 0000000..30aac09 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/TransportLayer.java @@ -0,0 +1,9 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.network; + +import java.io.IOException; + +public interface TransportLayer { + String read() throws IOException; + void write(String data) throws IOException; + void close() throws IOException; +} -- 2.52.0 From b073760eefd3e1c25e616e3357994fdcd0b0aa6f Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Thu, 12 Mar 2026 15:51:35 +0100 Subject: [PATCH 11/25] Add: TcpTransport class to implement TransportLayer --- .../casono/server/network/TcpTransport.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/TcpTransport.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/TcpTransport.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/TcpTransport.java new file mode 100644 index 0000000..4cb9910 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/TcpTransport.java @@ -0,0 +1,37 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.network; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.Socket; +import java.nio.charset.StandardCharsets; + +public class TcpTransport implements TransportLayer { + private Socket socket; + private DataInputStream in; + private DataOutputStream out; + + public TcpTransport(Socket socket) throws IOException { + this.socket = socket; + this.in = new DataInputStream(socket.getInputStream()); + this.out = new DataOutputStream(socket.getOutputStream()); + } + + public String read() throws IOException { + int length = in.readInt(); + byte[] payload = new byte[length]; + in.readFully(payload); + return new String(payload, StandardCharsets.UTF_8); + } + + public void write(String payload) throws IOException { + byte[] rawPayload = payload.getBytes(StandardCharsets.UTF_8); + out.writeInt(rawPayload.length); + out.write(rawPayload); + out.flush(); + } + + public void close() throws IOException { + socket.close(); + } +} -- 2.52.0 From d4bf69dc594011009560336f333fd70e1fa3a6c5 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Thu, 12 Mar 2026 15:54:06 +0100 Subject: [PATCH 12/25] Refactor: Session to use TransportLayer for socket communication --- .../casono/server/network/NetworkManager.java | 2 +- .../cs108/casono/server/network/Session.java | 31 ++++++------------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java index ca579ba..aed074a 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java @@ -38,7 +38,7 @@ public class NetworkManager implements Runnable { System.out.println("Accepted connection from " + clientSocket.getRemoteSocketAddress()); - Session session = new Session(clientSocket); + Session session = new Session(new TcpTransport(clientSocket)); session.start(); } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java index 855b9be..24b30d2 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java @@ -1,29 +1,22 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.EOFException; import java.io.IOException; -import java.net.Socket; -import java.nio.charset.StandardCharsets; - import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class Session implements Runnable { private SessionId id; private Thread thread; - private Socket socket; - private DataInputStream in; - private DataOutputStream out; + private TransportLayer transport; private Logger logger; + private Boolean running; - public Session(Socket socket) throws IOException { + public Session(TransportLayer transport) throws IOException { this.id = new SessionId(); this.thread = new Thread(this, "session-" + this.id.value()); - this.socket = socket; - this.in = new DataInputStream(socket.getInputStream()); - this.out = new DataOutputStream(socket.getOutputStream()); + this.transport = transport; + this.running = true; this.logger = LogManager.getLogger(Session.class.toString() + id.value()); this.logger.info("Created new session"); @@ -37,22 +30,16 @@ public class Session implements Runnable { thread.start(); } - public String read() throws IOException { - int length = in.readInt(); - byte[] payload = new byte[length]; - in.readFully(payload); - return new String(payload, StandardCharsets.UTF_8); - } - public void close() throws IOException { - socket.close(); + transport.close(); + this.running = false; } @Override public void run() { - while (true) { + while (running) { try { - System.out.println("Recieved: " + read()); + System.out.println("Recieved: " + transport.read()); } catch (EOFException e) { logger.info("Client disconnected"); break; -- 2.52.0 From 7fcb47ed6ffeadd8f611c1e10e8e26b72bd65f42 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Thu, 12 Mar 2026 19:12:53 +0100 Subject: [PATCH 13/25] Add: EventBus class for event handling and subscription management --- .../cs108/casono/server/network/EventBus.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java new file mode 100644 index 0000000..5802c8c --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java @@ -0,0 +1,23 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.network; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; + +public class EventBus { + private final Map<Class<?>, List<Consumer<Object>>> handlers = new ConcurrentHashMap<>(); + + public <T> void subscribe(Class<T> eventType, Consumer<T> handler) { + handlers.computeIfAbsent(eventType, k -> new CopyOnWriteArrayList<>()) + .add((Consumer<Object>) handler); + } + + public <T> void publish(T event) { + List<Consumer<Object>> subscribers = handlers.get(event.getClass()); + if (subscribers != null) { + subscribers.forEach(h -> h.accept(event)); + } + } +} -- 2.52.0 From fc8a92789ab453c4997bbb147e7060078cf4d5fa Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Thu, 12 Mar 2026 19:13:25 +0100 Subject: [PATCH 14/25] Add: DisconnectEvent as record --- .../dmi/dbis/cs108/casono/server/network/DisconnectEvent.java | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/DisconnectEvent.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/DisconnectEvent.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/DisconnectEvent.java new file mode 100644 index 0000000..a271ed6 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/DisconnectEvent.java @@ -0,0 +1,3 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.network; + +public record DisconnectEvent(SessionId sessionId) {} -- 2.52.0 From 54588276d116031bb2aad90af8bbac59cc00a749 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Thu, 12 Mar 2026 19:15:25 +0100 Subject: [PATCH 15/25] Add: Let Session publish DisconnectEvent and EventHandler subscribe and handle it --- .../dmi/dbis/cs108/casono/server/ServerApp.java | 4 +++- .../cs108/casono/server/network/NetworkManager.java | 11 +++++++++-- .../dmi/dbis/cs108/casono/server/network/Session.java | 5 ++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java index e7dd3f3..d056413 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java @@ -1,5 +1,6 @@ package ch.unibas.dmi.dbis.cs108.casono.server; +import ch.unibas.dmi.dbis.cs108.casono.server.network.EventBus; import ch.unibas.dmi.dbis.cs108.casono.server.network.NetworkManager; public class ServerApp { @@ -7,7 +8,8 @@ public class ServerApp { int port = Integer.parseInt(arg); System.out.println("You've selected the server. It will accept connections at port " + port); - NetworkManager networkManager = new NetworkManager(port); + EventBus eventBus = new EventBus(); + NetworkManager networkManager = new NetworkManager(port, eventBus); networkManager.start(); } } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java index aed074a..8699852 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java @@ -15,12 +15,15 @@ public class NetworkManager implements Runnable { private Logger logger; private Thread thread; private Boolean running; + private EventBus eventBus; - public NetworkManager(Integer port) { + public NetworkManager(Integer port, EventBus eventBus) { this.port = port; this.logger = LogManager.getLogger(NetworkManager.class); this.thread = new Thread(this, "networkManager"); this.running = true; + this.eventBus = eventBus; + this.eventBus.subscribe(DisconnectEvent.class, event -> clientDisconnected(event)); } /* Starts the internal thread to accept new connections. @@ -30,6 +33,10 @@ public class NetworkManager implements Runnable { thread.start(); } + public void clientDisconnected(DisconnectEvent event) { + logger.info("Session " + event.sessionId().value() + " disconnected adhasghd"); + } + @Override public void run() { try (ServerSocket serverSocket = new ServerSocket(port)) { @@ -38,7 +45,7 @@ public class NetworkManager implements Runnable { System.out.println("Accepted connection from " + clientSocket.getRemoteSocketAddress()); - Session session = new Session(new TcpTransport(clientSocket)); + Session session = new Session(new TcpTransport(clientSocket), eventBus); session.start(); } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java index 24b30d2..1ae946c 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java @@ -11,12 +11,14 @@ public class Session implements Runnable { private TransportLayer transport; private Logger logger; private Boolean running; + private EventBus eventBus; - public Session(TransportLayer transport) throws IOException { + public Session(TransportLayer transport, EventBus eventBus) throws IOException { this.id = new SessionId(); this.thread = new Thread(this, "session-" + this.id.value()); this.transport = transport; this.running = true; + this.eventBus = eventBus; this.logger = LogManager.getLogger(Session.class.toString() + id.value()); this.logger.info("Created new session"); @@ -42,6 +44,7 @@ public class Session implements Runnable { System.out.println("Recieved: " + transport.read()); } catch (EOFException e) { logger.info("Client disconnected"); + eventBus.publish(new DisconnectEvent(id)); break; } catch (IOException e) { e.printStackTrace(); -- 2.52.0 From 7b32fe11473b22309cb15d46d34b2e5cb33bdfb5 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Thu, 12 Mar 2026 19:16:59 +0100 Subject: [PATCH 16/25] Add: Event interface and implement it in DisconnectEvent, update EventBus to only allow Event type --- .../dmi/dbis/cs108/casono/server/network/DisconnectEvent.java | 2 +- .../ch/unibas/dmi/dbis/cs108/casono/server/network/Event.java | 3 +++ .../unibas/dmi/dbis/cs108/casono/server/network/EventBus.java | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Event.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/DisconnectEvent.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/DisconnectEvent.java index a271ed6..ea23e18 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/DisconnectEvent.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/DisconnectEvent.java @@ -1,3 +1,3 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network; -public record DisconnectEvent(SessionId sessionId) {} +public record DisconnectEvent(SessionId sessionId) implements Event {} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Event.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Event.java new file mode 100644 index 0000000..0c89aa1 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Event.java @@ -0,0 +1,3 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.network; + +interface Event {} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java index 5802c8c..e099f67 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java @@ -9,12 +9,12 @@ import java.util.function.Consumer; public class EventBus { private final Map<Class<?>, List<Consumer<Object>>> handlers = new ConcurrentHashMap<>(); - public <T> void subscribe(Class<T> eventType, Consumer<T> handler) { + public <T extends Event> void subscribe(Class<T> eventType, Consumer<T> handler) { handlers.computeIfAbsent(eventType, k -> new CopyOnWriteArrayList<>()) .add((Consumer<Object>) handler); } - public <T> void publish(T event) { + public <T extends Event> void publish(T event) { List<Consumer<Object>> subscribers = handlers.get(event.getClass()); if (subscribers != null) { subscribers.forEach(h -> h.accept(event)); -- 2.52.0 From db7892d9c423b55a7391d8c5e19a08bf76fbe524 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Thu, 12 Mar 2026 19:26:00 +0100 Subject: [PATCH 17/25] Fix: 'Type safety: Unchecked cast from ...' --- .../ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java index e099f67..a77da29 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java @@ -9,6 +9,7 @@ import java.util.function.Consumer; public class EventBus { private final Map<Class<?>, List<Consumer<Object>>> handlers = new ConcurrentHashMap<>(); + @SuppressWarnings("unchecked") // This cast is safe, because handlers only get passed the type they subscribed to public <T extends Event> void subscribe(Class<T> eventType, Consumer<T> handler) { handlers.computeIfAbsent(eventType, k -> new CopyOnWriteArrayList<>()) .add((Consumer<Object>) handler); -- 2.52.0 From e1029932d8940b7acd15821841ff1c6f2ff1aa31 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Thu, 12 Mar 2026 19:27:29 +0100 Subject: [PATCH 18/25] Fix: 'Potential null pointer access' --- .../unibas/dmi/dbis/cs108/casono/server/network/EventBus.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java index a77da29..ba8d9cd 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java @@ -2,6 +2,7 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; @@ -16,6 +17,7 @@ public class EventBus { } public <T extends Event> void publish(T event) { + Objects.requireNonNull(event, "event must not be null"); List<Consumer<Object>> subscribers = handlers.get(event.getClass()); if (subscribers != null) { subscribers.forEach(h -> h.accept(event)); -- 2.52.0 From c301039bfc13085f51292c06f63f547c7f5644cb Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Thu, 12 Mar 2026 19:34:46 +0100 Subject: [PATCH 19/25] Add: SessionManager to store all active sessions --- .../casono/server/network/SessionManager.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionManager.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionManager.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionManager.java new file mode 100644 index 0000000..3a794f9 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionManager.java @@ -0,0 +1,28 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.network; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class SessionManager { + private Map<SessionId, Session> sessions; + + public SessionManager() { + this.sessions = new ConcurrentHashMap<>(); + } + + public void addSession(Session session) { + sessions.put(session.getId(), session); + } + + public Session removeSession(SessionId id) { + return sessions.remove(id); + } + + public Session removeSession(Session session) { + return sessions.remove(session.getId()); + } + + public Session getSessionById(SessionId id) { + return sessions.get(id); + } +} -- 2.52.0 From 74566f99cf096b5be1eca15796a3b5dd8897f0e8 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Thu, 12 Mar 2026 20:12:52 +0100 Subject: [PATCH 20/25] Fix: Direct (unallowed) cast from Consumer<T> to Consumer<Object> --- .../unibas/dmi/dbis/cs108/casono/server/network/EventBus.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java index ba8d9cd..5b9d6c6 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java @@ -13,7 +13,7 @@ public class EventBus { @SuppressWarnings("unchecked") // This cast is safe, because handlers only get passed the type they subscribed to public <T extends Event> void subscribe(Class<T> eventType, Consumer<T> handler) { handlers.computeIfAbsent(eventType, k -> new CopyOnWriteArrayList<>()) - .add((Consumer<Object>) handler); + .add((Consumer<Object>) (Consumer<?>) handler); } public <T extends Event> void publish(T event) { -- 2.52.0 From 711de2e6aaa153066499e302355685fab7e7b0e0 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Thu, 12 Mar 2026 20:13:50 +0100 Subject: [PATCH 21/25] Add: Make use of SessionManager --- .../ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java | 6 +++++- .../dbis/cs108/casono/server/network/NetworkManager.java | 5 ++++- .../dbis/cs108/casono/server/network/SessionManager.java | 2 ++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java index d056413..c704d5e 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java @@ -1,7 +1,9 @@ package ch.unibas.dmi.dbis.cs108.casono.server; +import ch.unibas.dmi.dbis.cs108.casono.server.network.DisconnectEvent; import ch.unibas.dmi.dbis.cs108.casono.server.network.EventBus; import ch.unibas.dmi.dbis.cs108.casono.server.network.NetworkManager; +import ch.unibas.dmi.dbis.cs108.casono.server.network.SessionManager; public class ServerApp { public static void start(String arg) { @@ -9,7 +11,9 @@ public class ServerApp { System.out.println("You've selected the server. It will accept connections at port " + port); EventBus eventBus = new EventBus(); - NetworkManager networkManager = new NetworkManager(port, eventBus); + SessionManager sessionManager = new SessionManager(); + eventBus.subscribe(DisconnectEvent.class, event -> sessionManager.removeSession(event.sessionId())); + NetworkManager networkManager = new NetworkManager(port, sessionManager, eventBus); networkManager.start(); } } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java index 8699852..3e60e59 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java @@ -15,13 +15,15 @@ public class NetworkManager implements Runnable { private Logger logger; private Thread thread; private Boolean running; + private SessionManager sessionManager; private EventBus eventBus; - public NetworkManager(Integer port, EventBus eventBus) { + public NetworkManager(Integer port, SessionManager sessionManager, EventBus eventBus) { this.port = port; this.logger = LogManager.getLogger(NetworkManager.class); this.thread = new Thread(this, "networkManager"); this.running = true; + this.sessionManager = sessionManager; this.eventBus = eventBus; this.eventBus.subscribe(DisconnectEvent.class, event -> clientDisconnected(event)); } @@ -46,6 +48,7 @@ public class NetworkManager implements Runnable { System.out.println("Accepted connection from " + clientSocket.getRemoteSocketAddress()); Session session = new Session(new TcpTransport(clientSocket), eventBus); + sessionManager.addSession(session); session.start(); } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionManager.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionManager.java index 3a794f9..69fcdbe 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionManager.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionManager.java @@ -12,9 +12,11 @@ public class SessionManager { public void addSession(Session session) { sessions.put(session.getId(), session); + System.out.println("Added session " + session.getId().value() + " to session manager"); } public Session removeSession(SessionId id) { + System.out.println("Removed session " + id.value() + " from session manager"); return sessions.remove(id); } -- 2.52.0 From 49019075e4479014adfb5b69d3efef59d1c2c9b7 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Fri, 13 Mar 2026 14:42:19 +0100 Subject: [PATCH 22/25] Move: Network related files into respective folders --- .../dbis/cs108/casono/server/network/DisconnectEvent.java | 3 --- .../unibas/dmi/dbis/cs108/casono/server/network/Event.java | 3 --- .../dbis/cs108/casono/server/network/NetworkManager.java | 6 ++++++ .../cs108/casono/server/network/events/DisconnectEvent.java | 5 +++++ .../dmi/dbis/cs108/casono/server/network/events/Event.java | 3 +++ .../cs108/casono/server/network/{ => events}/EventBus.java | 2 +- .../cs108/casono/server/network/{ => sessions}/Session.java | 6 +++++- .../casono/server/network/{ => sessions}/SessionId.java | 2 +- .../server/network/{ => sessions}/SessionManager.java | 2 +- .../casono/server/network/{ => transport}/TcpTransport.java | 2 +- .../server/network/{ => transport}/TransportLayer.java | 2 +- 11 files changed, 24 insertions(+), 12 deletions(-) delete mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/DisconnectEvent.java delete mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Event.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/DisconnectEvent.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/Event.java rename src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/{ => events}/EventBus.java (93%) rename src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/{ => sessions}/Session.java (83%) rename src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/{ => sessions}/SessionId.java (85%) rename src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/{ => sessions}/SessionManager.java (92%) rename src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/{ => transport}/TcpTransport.java (94%) rename src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/{ => transport}/TransportLayer.java (74%) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/DisconnectEvent.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/DisconnectEvent.java deleted file mode 100644 index ea23e18..0000000 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/DisconnectEvent.java +++ /dev/null @@ -1,3 +0,0 @@ -package ch.unibas.dmi.dbis.cs108.casono.server.network; - -public record DisconnectEvent(SessionId sessionId) implements Event {} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Event.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Event.java deleted file mode 100644 index 0c89aa1..0000000 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Event.java +++ /dev/null @@ -1,3 +0,0 @@ -package ch.unibas.dmi.dbis.cs108.casono.server.network; - -interface Event {} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java index 3e60e59..880bd56 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java @@ -7,6 +7,12 @@ import java.net.Socket; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import ch.unibas.dmi.dbis.cs108.casono.server.network.events.DisconnectEvent; +import ch.unibas.dmi.dbis.cs108.casono.server.network.events.EventBus; +import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.Session; +import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionManager; +import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.TcpTransport; + /** * Creates and manages the server socket. Accepts new incomming connections and creates sessions. */ diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/DisconnectEvent.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/DisconnectEvent.java new file mode 100644 index 0000000..65f8152 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/DisconnectEvent.java @@ -0,0 +1,5 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.network.events; + +import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionId; + +public record DisconnectEvent(SessionId sessionId) implements Event {} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/Event.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/Event.java new file mode 100644 index 0000000..4fb6948 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/Event.java @@ -0,0 +1,3 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.network.events; + +interface Event {} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/EventBus.java similarity index 93% rename from src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java rename to src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/EventBus.java index 5b9d6c6..6644313 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/EventBus.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/EventBus.java @@ -1,4 +1,4 @@ -package ch.unibas.dmi.dbis.cs108.casono.server.network; +package ch.unibas.dmi.dbis.cs108.casono.server.network.events; import java.util.List; import java.util.Map; diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/Session.java similarity index 83% rename from src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java rename to src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/Session.java index 1ae946c..e2ece59 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/Session.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/Session.java @@ -1,10 +1,14 @@ -package ch.unibas.dmi.dbis.cs108.casono.server.network; +package ch.unibas.dmi.dbis.cs108.casono.server.network.sessions; import java.io.EOFException; import java.io.IOException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import ch.unibas.dmi.dbis.cs108.casono.server.network.events.DisconnectEvent; +import ch.unibas.dmi.dbis.cs108.casono.server.network.events.EventBus; +import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.TransportLayer; + public class Session implements Runnable { private SessionId id; private Thread thread; diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionId.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionId.java similarity index 85% rename from src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionId.java rename to src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionId.java index 0af06ad..117dba3 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionId.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionId.java @@ -1,4 +1,4 @@ -package ch.unibas.dmi.dbis.cs108.casono.server.network; +package ch.unibas.dmi.dbis.cs108.casono.server.network.sessions; import java.util.UUID; diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionManager.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionManager.java similarity index 92% rename from src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionManager.java rename to src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionManager.java index 69fcdbe..f583be1 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/SessionManager.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionManager.java @@ -1,4 +1,4 @@ -package ch.unibas.dmi.dbis.cs108.casono.server.network; +package ch.unibas.dmi.dbis.cs108.casono.server.network.sessions; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/TcpTransport.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/transport/TcpTransport.java similarity index 94% rename from src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/TcpTransport.java rename to src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/transport/TcpTransport.java index 4cb9910..6a761e6 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/TcpTransport.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/transport/TcpTransport.java @@ -1,4 +1,4 @@ -package ch.unibas.dmi.dbis.cs108.casono.server.network; +package ch.unibas.dmi.dbis.cs108.casono.server.network.transport; import java.io.DataInputStream; import java.io.DataOutputStream; diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/TransportLayer.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/transport/TransportLayer.java similarity index 74% rename from src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/TransportLayer.java rename to src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/transport/TransportLayer.java index 30aac09..a4453e4 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/TransportLayer.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/transport/TransportLayer.java @@ -1,4 +1,4 @@ -package ch.unibas.dmi.dbis.cs108.casono.server.network; +package ch.unibas.dmi.dbis.cs108.casono.server.network.transport; import java.io.IOException; -- 2.52.0 From 4231ca3e97918ff34a7dcc41bf381467c440788d Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Fri, 13 Mar 2026 15:12:06 +0100 Subject: [PATCH 23/25] Ammend to 49019075e4479014adfb5b69d3efef59d1c2c9b7 --- .../unibas/dmi/dbis/cs108/casono/server/ServerApp.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java index c704d5e..a7814b0 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java @@ -1,10 +1,13 @@ package ch.unibas.dmi.dbis.cs108.casono.server; -import ch.unibas.dmi.dbis.cs108.casono.server.network.DisconnectEvent; -import ch.unibas.dmi.dbis.cs108.casono.server.network.EventBus; import ch.unibas.dmi.dbis.cs108.casono.server.network.NetworkManager; -import ch.unibas.dmi.dbis.cs108.casono.server.network.SessionManager; +import ch.unibas.dmi.dbis.cs108.casono.server.network.events.DisconnectEvent; +import ch.unibas.dmi.dbis.cs108.casono.server.network.events.EventBus; +import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionManager; +/** + * Application class for starting the server. + */ public class ServerApp { public static void start(String arg) { int port = Integer.parseInt(arg); -- 2.52.0 From 38133e676151091fb6b39ebb92dc5b06523db4e8 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Fri, 13 Mar 2026 15:16:15 +0100 Subject: [PATCH 24/25] Docs: Add JavDoc for all classes and methods --- .../casono/server/network/NetworkManager.java | 20 +++++++++++-- .../network/events/DisconnectEvent.java | 3 ++ .../casono/server/network/events/Event.java | 3 ++ .../server/network/events/EventBus.java | 14 +++++++++ .../server/network/sessions/Session.java | 26 +++++++++++++++++ .../server/network/sessions/SessionId.java | 19 ++++++++++-- .../network/sessions/SessionManager.java | 29 +++++++++++++++++++ .../network/transport/TcpTransport.java | 26 +++++++++++++++++ .../network/transport/TransportLayer.java | 22 ++++++++++++++ 9 files changed, 157 insertions(+), 5 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java index 880bd56..50b53d9 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/NetworkManager.java @@ -14,7 +14,7 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionManager; import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.TcpTransport; /** - * Creates and manages the server socket. Accepts new incomming connections and creates sessions. + * Creates and manages the server socket. Accepts new incoming connections and creates sessions. */ public class NetworkManager implements Runnable { private Integer port; @@ -24,6 +24,13 @@ public class NetworkManager implements Runnable { private SessionManager sessionManager; private EventBus eventBus; + /** + * Creates a new NetworkManager with the given port, session manager, and event bus. + * + * @param port the port to listen on + * @param sessionManager the session manager to use + * @param eventBus the event bus for events + */ public NetworkManager(Integer port, SessionManager sessionManager, EventBus eventBus) { this.port = port; this.logger = LogManager.getLogger(NetworkManager.class); @@ -34,17 +41,26 @@ public class NetworkManager implements Runnable { this.eventBus.subscribe(DisconnectEvent.class, event -> clientDisconnected(event)); } - /* Starts the internal thread to accept new connections. + /** + * Starts the internal thread to accept new connections. */ public void start() { logger.debug("Starting server at port " + port); thread.start(); } + /** + * Handles client disconnection events. + * + * @param event the disconnect event + */ public void clientDisconnected(DisconnectEvent event) { logger.info("Session " + event.sessionId().value() + " disconnected adhasghd"); } + /** + * Runs the network manager loop, accepting connections. + */ @Override public void run() { try (ServerSocket serverSocket = new ServerSocket(port)) { diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/DisconnectEvent.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/DisconnectEvent.java index 65f8152..b6b0d78 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/DisconnectEvent.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/DisconnectEvent.java @@ -2,4 +2,7 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network.events; import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionId; +/** + * Represents a disconnect event for a session. + */ public record DisconnectEvent(SessionId sessionId) implements Event {} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/Event.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/Event.java index 4fb6948..75c0954 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/Event.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/Event.java @@ -1,3 +1,6 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network.events; +/** + * Marker interface for events in the event bus system. + */ interface Event {} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/EventBus.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/EventBus.java index 6644313..4141ab8 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/EventBus.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/events/EventBus.java @@ -7,15 +7,29 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; +/** + * A simple event bus for publishing and subscribing to events. + */ public class EventBus { private final Map<Class<?>, List<Consumer<Object>>> handlers = new ConcurrentHashMap<>(); + /** + * Subscribes a handler to a specific event type. + * + * @param eventType the class of the event to subscribe to + * @param handler the consumer to handle the event + */ @SuppressWarnings("unchecked") // This cast is safe, because handlers only get passed the type they subscribed to public <T extends Event> void subscribe(Class<T> eventType, Consumer<T> handler) { handlers.computeIfAbsent(eventType, k -> new CopyOnWriteArrayList<>()) .add((Consumer<Object>) (Consumer<?>) handler); } + /** + * Publishes an event to all subscribed handlers. + * + * @param event the event to publish + */ public <T extends Event> void publish(T event) { Objects.requireNonNull(event, "event must not be null"); List<Consumer<Object>> subscribers = handlers.get(event.getClass()); diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/Session.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/Session.java index e2ece59..9b2f344 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/Session.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/Session.java @@ -9,6 +9,9 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.events.DisconnectEvent; import ch.unibas.dmi.dbis.cs108.casono.server.network.events.EventBus; import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.TransportLayer; +/** + * Represents a client session in the network server. + */ public class Session implements Runnable { private SessionId id; private Thread thread; @@ -17,6 +20,13 @@ public class Session implements Runnable { private Boolean running; private EventBus eventBus; + /** + * Creates a new Session with the given transport and event bus. + * + * @param transport the transport layer for communication + * @param eventBus the event bus for publishing events + * @throws IOException if an I/O error occurs during initialization + */ public Session(TransportLayer transport, EventBus eventBus) throws IOException { this.id = new SessionId(); this.thread = new Thread(this, "session-" + this.id.value()); @@ -28,19 +38,35 @@ public class Session implements Runnable { this.logger.info("Created new session"); } + /** + * Returns the ID of this session. + * + * @return the session ID + */ public SessionId getId() { return this.id; } + /** + * Starts the session thread. + */ public void start() { thread.start(); } + /** + * Closes the session and its transport. + * + * @throws IOException if an I/O error occurs + */ public void close() throws IOException { transport.close(); this.running = false; } + /** + * Runs the session loop, reading from the transport. + */ @Override public void run() { while (running) { diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionId.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionId.java index 117dba3..431ebdc 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionId.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionId.java @@ -2,20 +2,33 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network.sessions; import java.util.UUID; +/** + * Represents a unique identifier for a session. + */ public class SessionId { - /** - * The SessionId is used to identify a unique client connection in the SessionRegistry - */ private final UUID value; + /** + * Creates a new SessionId with a randomly generated UUID. + */ public SessionId() { this.value = UUID.randomUUID(); } + /** + * Creates a new SessionId with the specified UUID. + * + * @param UUID to use for this SessionId + */ public SessionId(UUID value) { this.value = value; } + /** + * Returns the UUID value of this SessionId. + * + * @return the UUID value + */ public UUID value() { return value; } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionManager.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionManager.java index f583be1..42bc4ac 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionManager.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionManager.java @@ -3,27 +3,56 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network.sessions; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +/** + * Manages active sessions in the server. + */ public class SessionManager { private Map<SessionId, Session> sessions; + /** + * Constructs a new SessionManager. + */ public SessionManager() { this.sessions = new ConcurrentHashMap<>(); } + /** + * Adds a session to the manager. + * + * @param session the session to add + */ public void addSession(Session session) { sessions.put(session.getId(), session); System.out.println("Added session " + session.getId().value() + " to session manager"); } + /** + * Removes a session by its ID. + * + * @param id the ID of the session to remove + * @return the removed session, or null if not found + */ public Session removeSession(SessionId id) { System.out.println("Removed session " + id.value() + " from session manager"); return sessions.remove(id); } + /** + * Removes the specified session. + * + * @param session the session to remove + * @return the removed session, or null if not found + */ public Session removeSession(Session session) { return sessions.remove(session.getId()); } + /** + * Retrieves a session by its ID. + * + * @param id the ID of the session to retrieve + * @return the session with the specified ID, or null if not found + */ public Session getSessionById(SessionId id) { return sessions.get(id); } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/transport/TcpTransport.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/transport/TcpTransport.java index 6a761e6..3f80d6c 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/transport/TcpTransport.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/transport/TcpTransport.java @@ -6,17 +6,32 @@ import java.io.IOException; import java.net.Socket; import java.nio.charset.StandardCharsets; +/** + * Implements TCP-based transport layer for network communication. + */ public class TcpTransport implements TransportLayer { private Socket socket; private DataInputStream in; private DataOutputStream out; + /** + * Creates a new TcpTransport with the given socket. + * + * @param socket the socket to use for communication + * @throws IOException if an I/O error occurs + */ public TcpTransport(Socket socket) throws IOException { this.socket = socket; this.in = new DataInputStream(socket.getInputStream()); this.out = new DataOutputStream(socket.getOutputStream()); } + /** + * Reads a string from the socket. + * + * @return the read string + * @throws IOException if an I/O error occurs + */ public String read() throws IOException { int length = in.readInt(); byte[] payload = new byte[length]; @@ -24,6 +39,12 @@ public class TcpTransport implements TransportLayer { return new String(payload, StandardCharsets.UTF_8); } + /** + * Writes a string to the socket. + * + * @param payload the string to write + * @throws IOException if an I/O error occurs + */ public void write(String payload) throws IOException { byte[] rawPayload = payload.getBytes(StandardCharsets.UTF_8); out.writeInt(rawPayload.length); @@ -31,6 +52,11 @@ public class TcpTransport implements TransportLayer { out.flush(); } + /** + * Closes the socket. + * + * @throws IOException if an I/O error occurs + */ public void close() throws IOException { socket.close(); } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/transport/TransportLayer.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/transport/TransportLayer.java index a4453e4..f487a9c 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/transport/TransportLayer.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/transport/TransportLayer.java @@ -2,8 +2,30 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network.transport; import java.io.IOException; +/** + * Interface for transport layer implementations. + */ public interface TransportLayer { + /** + * Reads data from the transport layer. + * + * @return the read data as a string + * @throws IOException if an I/O error occurs + */ String read() throws IOException; + + /** + * Writes data to the transport layer. + * + * @param data the data to write + * @throws IOException if an I/O error occurs + */ void write(String data) throws IOException; + + /** + * Closes the transport layer. + * + * @throws IOException if an I/O error occurs + */ void close() throws IOException; } -- 2.52.0 From 4bcb9a987417a41ad3e845d3f092f430025303e5 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer <lars.winzer@stud.unibas.ch> Date: Fri, 13 Mar 2026 15:46:12 +0100 Subject: [PATCH 25/25] Style: Newline at end of file --- .../dmi/dbis/cs108/casono/server/network/sessions/Session.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/Session.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/Session.java index 9b2f344..d2464f1 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/Session.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/Session.java @@ -82,4 +82,4 @@ public class Session implements Runnable { } } } -} \ No newline at end of file +} -- 2.52.0