From 92a2ffe054d9bc0b00916e385cbdc5d72436493a Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 12:08:40 +0200 Subject: [PATCH 01/22] Add: PingRequest for ping request --- .../casono/server/app/commands/ping/PingRequest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingRequest.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingRequest.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingRequest.java new file mode 100644 index 0000000..a840408 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingRequest.java @@ -0,0 +1,10 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping; + +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext; + +public class PingRequest extends Request { + public PingRequest(RequestContext context) { + super(context); + } +} From b445b019a163c2d78991251f0deabbf0b116580f Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 12:09:01 +0200 Subject: [PATCH 02/22] Add: PingParser to parse PrimitiveRequest into PingRequest --- .../casono/server/app/commands/ping/PingParser.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingParser.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingParser.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingParser.java new file mode 100644 index 0000000..1e4fb51 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingParser.java @@ -0,0 +1,11 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping; + +import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.CommandParser; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.PrimitiveRequest; + +public class PingParser implements CommandParser { + @Override + public PingRequest parse(PrimitiveRequest primitiveRequest) { + return new PingRequest(primitiveRequest.context()); + } +} From dafa95af4108bc8f56768ceed070100a01edd784 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 12:09:29 +0200 Subject: [PATCH 03/22] Add: PingHandler to execute PingRequest and dispatch Response --- .../server/app/commands/ping/PingHandler.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingHandler.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingHandler.java new file mode 100644 index 0000000..74f2a21 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingHandler.java @@ -0,0 +1,18 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping; + +import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandler; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.OkResponse; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher; + +public class PingHandler implements CommandHandler { + private final ResponseDispatcher responseDispatcher; + + public PingHandler(ResponseDispatcher responseDispatcher) { + this.responseDispatcher = responseDispatcher; + } + + @Override + public void execute(PingRequest request) { + responseDispatcher.dispatch(new OkResponse(request.getContext())); + } +} From 707477bd73c106e1077e7e65338106450a39b955 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 12:15:01 +0200 Subject: [PATCH 04/22] Add: Integrate PingParser and PingHandler into helper function in composition root --- .../dmi/dbis/cs108/casono/server/ServerApp.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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 5687b5b..798c901 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,8 @@ package ch.unibas.dmi.dbis.cs108.casono.server; +import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingHandler; +import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingParser; +import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingRequest; import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserCleanupJob; import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry; import ch.unibas.dmi.dbis.cs108.casono.server.network.NetworkManager; @@ -7,6 +10,7 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandR import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.CommandParserDispatcher; 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.protocol.response.dispatcher.ResponseDispatcher; import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionDisconnectJob; import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionManager; import java.time.Duration; @@ -58,6 +62,18 @@ public class ServerApp { SESSION_DISCONNECT_JOB_PERIOD, TimeUnit.SECONDS); + ResponseDispatcher responseDispatcher = new ResponseDispatcher(sessionManager); + + register_commands(dispatcher, router, responseDispatcher); + networkManager.start(); } + + private static void register_commands( + CommandParserDispatcher parserDispatcher, + CommandRouter commandRouter, + ResponseDispatcher responseDispatcher) { + parserDispatcher.register("PING", new PingParser()); + commandRouter.register(PingRequest.class, new PingHandler(responseDispatcher)); + } } From 87b2dcfc2cd81d72b9749406f4ef06f86cfa4cc9 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 12:27:11 +0200 Subject: [PATCH 05/22] Docs: Add JavaDoc to newly added components --- .../dmi/dbis/cs108/casono/server/ServerApp.java | 7 +++++++ .../casono/server/app/commands/ping/PingHandler.java | 11 +++++++++++ .../casono/server/app/commands/ping/PingParser.java | 11 +++++++++++ .../casono/server/app/commands/ping/PingRequest.java | 9 +++++++++ 4 files changed, 38 insertions(+) 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 798c901..b100628 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 @@ -69,6 +69,13 @@ public class ServerApp { networkManager.start(); } + /** + * Registers command parsers and handlers. + * + * @param parserDispatcher the dispatcher responsible for parsing incoming commands + * @param commandRouter the router that dispatches parsed commands to appropriate handlers + * @param responseDispatcher the dispatcher responsible for sending responses back to clients + */ private static void register_commands( CommandParserDispatcher parserDispatcher, CommandRouter commandRouter, diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingHandler.java index 74f2a21..1669cd8 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingHandler.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingHandler.java @@ -4,13 +4,24 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandH import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.OkResponse; import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher; +/** Handler for {@link PingRequest}. */ public class PingHandler implements CommandHandler { private final ResponseDispatcher responseDispatcher; + /** + * Create a new PingHandler to execute {@link PingRequest}s + * + * @param responseDispatcher dispatcher used to send responses back to clients + */ public PingHandler(ResponseDispatcher responseDispatcher) { this.responseDispatcher = responseDispatcher; } + /** + * Execute the ping request. + * + * @param request the ping request to handle + */ @Override public void execute(PingRequest request) { responseDispatcher.dispatch(new OkResponse(request.getContext())); diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingParser.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingParser.java index 1e4fb51..69ab980 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingParser.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingParser.java @@ -3,7 +3,18 @@ package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping; import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.CommandParser; import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.PrimitiveRequest; +/** + * Parser for the Ping command. + * + *

Converts a low-level {@link PrimitiveRequest} into a {@link PingRequest}. + */ public class PingParser implements CommandParser { + /** + * Parse the given primitive request into a {@link PingRequest}. + * + * @param primitiveRequest the raw request to parse + * @return {@link PingRequest} + */ @Override public PingRequest parse(PrimitiveRequest primitiveRequest) { return new PingRequest(primitiveRequest.context()); diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingRequest.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingRequest.java index a840408..25ab93f 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingRequest.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/ping/PingRequest.java @@ -3,7 +3,16 @@ package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping; import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request; import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext; +/** + * Represents a "PING" request sent by a client to check server availability and keep the connection + * alive. + */ public class PingRequest extends Request { + /** + * Constructs a new PingRequest with the given context. + * + * @param context the request context associated with this request + */ public PingRequest(RequestContext context) { super(context); } From 10347b3ed47bc4b522ac7161b81efa9539c9e499 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 12:43:05 +0200 Subject: [PATCH 06/22] Style: Correct method naming --- .../ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java | 4 ++-- 1 file changed, 2 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 b100628..4d4f1ec 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 @@ -64,7 +64,7 @@ public class ServerApp { ResponseDispatcher responseDispatcher = new ResponseDispatcher(sessionManager); - register_commands(dispatcher, router, responseDispatcher); + registerCommands(dispatcher, router, responseDispatcher); networkManager.start(); } @@ -76,7 +76,7 @@ public class ServerApp { * @param commandRouter the router that dispatches parsed commands to appropriate handlers * @param responseDispatcher the dispatcher responsible for sending responses back to clients */ - private static void register_commands( + private static void registerCommands( CommandParserDispatcher parserDispatcher, CommandRouter commandRouter, ResponseDispatcher responseDispatcher) { From 35c8590c57ea364c91128a0c4e603ef310d54004 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 13:10:01 +0200 Subject: [PATCH 07/22] Add: CheckUsernameRequest containing username to check for availability --- .../check_nick/CheckUsernameRequest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameRequest.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameRequest.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameRequest.java new file mode 100644 index 0000000..0b5bda6 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameRequest.java @@ -0,0 +1,17 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick; + +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext; + +public class CheckUsernameRequest extends Request { + private final String username; + + public CheckUsernameRequest(RequestContext context, String username) { + super(context); + this.username = username; + } + + public String getUsername() { + return username; + } +} From 3b44e58505fa521f97abe68e278d48eb024228c6 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 13:26:27 +0200 Subject: [PATCH 08/22] Add: CheckUsernameParser to check for required parameter --- .../commands/check_nick/CheckUsernameParser.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameParser.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameParser.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameParser.java new file mode 100644 index 0000000..24b5263 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameParser.java @@ -0,0 +1,13 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick; + +import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.CommandParser; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.PrimitiveRequest; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.accessor.RequestParameterAccessor; + +public class CheckUsernameParser implements CommandParser { + @Override + public CheckUsernameRequest parse(PrimitiveRequest primitiveRequest) { + RequestParameterAccessor accessor = new RequestParameterAccessor(primitiveRequest.parameters()); + return new CheckUsernameRequest(primitiveRequest.context(), accessor.require("USERNAME")); + } +} From 07587340d411c2f59a2c91d98400e837079dffcb Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 13:30:22 +0200 Subject: [PATCH 09/22] Add: Register CheckUsernameParser in composition root --- .../ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java | 8 ++++++-- 1 file changed, 6 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 4d4f1ec..a182f80 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.app.commands.check_nick.CheckUsernameParser; import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingHandler; import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingParser; import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingRequest; @@ -64,7 +65,7 @@ public class ServerApp { ResponseDispatcher responseDispatcher = new ResponseDispatcher(sessionManager); - registerCommands(dispatcher, router, responseDispatcher); + registerCommands(dispatcher, router, responseDispatcher, userRegistry); networkManager.start(); } @@ -79,8 +80,11 @@ public class ServerApp { private static void registerCommands( CommandParserDispatcher parserDispatcher, CommandRouter commandRouter, - ResponseDispatcher responseDispatcher) { + ResponseDispatcher responseDispatcher, + UserRegistry userRegistry) { parserDispatcher.register("PING", new PingParser()); commandRouter.register(PingRequest.class, new PingHandler(responseDispatcher)); + + parserDispatcher.register("CHECK_USERNAME", new CheckUsernameParser()); } } From f95d9174f1d1df665aa4d89932c906e76b93f8a2 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 13:44:51 +0200 Subject: [PATCH 10/22] Add: Handle MissingParameterException in SessionReader and respond to request --- .../cs108/casono/server/network/sessions/SessionReader.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionReader.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionReader.java index 6fb4378..e199e0e 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionReader.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionReader.java @@ -12,6 +12,7 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Primitive import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RawRequest; import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request; import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.accessor.MissingParameterException; import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.ErrorResponse; import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.PrimitiveResponse; import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatchException; @@ -94,6 +95,10 @@ public class SessionReader implements Runnable { "Unexpected ResponseDispatchException exception while dispatching request", e); + } catch (MissingParameterException e) { + logger.error("Recieved request for command '{}' was missing the '{}' parameter", rawRequest.command(), e.getParameterKey()); + sendErrorResponse(new ErrorResponse(requestContext, "MISSING_PARAMETER", e.getMessage())); + } catch (IOException e) { logger.error("Unexpected IO exception while reading from transport", e); From 528a40b39433c1324a1b5bb6dd9c4a2b9cb722b8 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 13:45:14 +0200 Subject: [PATCH 11/22] Style: Apply Spotless --- .../casono/server/network/sessions/SessionReader.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionReader.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionReader.java index e199e0e..78ffbfd 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionReader.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionReader.java @@ -96,8 +96,12 @@ public class SessionReader implements Runnable { e); } catch (MissingParameterException e) { - logger.error("Recieved request for command '{}' was missing the '{}' parameter", rawRequest.command(), e.getParameterKey()); - sendErrorResponse(new ErrorResponse(requestContext, "MISSING_PARAMETER", e.getMessage())); + logger.error( + "Recieved request for command '{}' was missing the '{}' parameter", + rawRequest.command(), + e.getParameterKey()); + sendErrorResponse( + new ErrorResponse(requestContext, "MISSING_PARAMETER", e.getMessage())); } catch (IOException e) { logger.error("Unexpected IO exception while reading from transport", e); From 5b70fb89effb93db68ab78298fdb4064a7795da3 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 14:11:14 +0200 Subject: [PATCH 12/22] Add: Implement methods to find users by UserId and username --- .../cs108/casono/server/domain/user/UserRegistry.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/user/UserRegistry.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/user/UserRegistry.java index adb1abe..6959c22 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/user/UserRegistry.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/user/UserRegistry.java @@ -1,6 +1,8 @@ package ch.unibas.dmi.dbis.cs108.casono.server.domain.user; import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionId; + +import java.lang.classfile.attribute.UnknownAttribute; import java.util.Collection; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; @@ -95,6 +97,14 @@ public class UserRegistry { return Optional.ofNullable(bySessionId.get(sessionId)); } + public Optional findByUserId(UserId userId) { + return Optional.ofNullable(byId.get(userId)); + } + + public Optional findByUsername(String username) { + return Optional.ofNullable(byName.get(username)); + } + /** * Returns all currently registered users. * From f91fa698f3ec0e9ccf326e23e531a74e1a307a47 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 14:12:13 +0200 Subject: [PATCH 13/22] Refactor: Rename user lookup methods from 'find' to 'get' prefix --- .../dbis/cs108/casono/server/domain/user/UserRegistry.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/user/UserRegistry.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/user/UserRegistry.java index 6959c22..9220afe 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/user/UserRegistry.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/user/UserRegistry.java @@ -93,15 +93,15 @@ public class UserRegistry { * @param sessionId the session ID to look up * @return an Optional containing the user, or empty if no user is associated with this session */ - public Optional findBySessionId(SessionId sessionId) { + public Optional getBySessionId(SessionId sessionId) { return Optional.ofNullable(bySessionId.get(sessionId)); } - public Optional findByUserId(UserId userId) { + public Optional getByUserId(UserId userId) { return Optional.ofNullable(byId.get(userId)); } - public Optional findByUsername(String username) { + public Optional getByUsername(String username) { return Optional.ofNullable(byName.get(username)); } From a9878da3f2938177de19e1c70272ed0a709c194e Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 14:17:45 +0200 Subject: [PATCH 14/22] Docs: Write JavaDoc for changed components --- .../server/domain/user/UserRegistry.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/user/UserRegistry.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/user/UserRegistry.java index 9220afe..51b6894 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/user/UserRegistry.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/user/UserRegistry.java @@ -88,19 +88,31 @@ public class UserRegistry { } /** - * Looks up a user by their session ID. + * Looks up a user by their {@link SessionId}. * - * @param sessionId the session ID to look up - * @return an Optional containing the user, or empty if no user is associated with this session + * @param sessionId the SessionId to look up + * @return an Optional containing the {@link User}, or empty if no user is associated with this SessionId */ public Optional getBySessionId(SessionId sessionId) { return Optional.ofNullable(bySessionId.get(sessionId)); } + /** + * Looks up a user by their {@link UserId}. + * + * @param userId the UserId to look up + * @return an Optional containing the {@link User}, or empty if no user is associated with this UserId + */ public Optional getByUserId(UserId userId) { return Optional.ofNullable(byId.get(userId)); } + /** + * Looks up a user by their username. + * + * @param username the username to look up + * @return an Optional containing the {@link User}, or empty if no user is associated with this username + */ public Optional getByUsername(String username) { return Optional.ofNullable(byName.get(username)); } From 415ad754df617e169d64d26a9f047e69ec08f0de Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 14:18:09 +0200 Subject: [PATCH 15/22] Style: Apply Spotless --- .../cs108/casono/server/domain/user/UserRegistry.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/user/UserRegistry.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/user/UserRegistry.java index 51b6894..bc0cd36 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/user/UserRegistry.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/user/UserRegistry.java @@ -1,8 +1,6 @@ package ch.unibas.dmi.dbis.cs108.casono.server.domain.user; import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionId; - -import java.lang.classfile.attribute.UnknownAttribute; import java.util.Collection; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; @@ -91,7 +89,8 @@ public class UserRegistry { * Looks up a user by their {@link SessionId}. * * @param sessionId the SessionId to look up - * @return an Optional containing the {@link User}, or empty if no user is associated with this SessionId + * @return an Optional containing the {@link User}, or empty if no user is associated with this + * SessionId */ public Optional getBySessionId(SessionId sessionId) { return Optional.ofNullable(bySessionId.get(sessionId)); @@ -101,7 +100,8 @@ public class UserRegistry { * Looks up a user by their {@link UserId}. * * @param userId the UserId to look up - * @return an Optional containing the {@link User}, or empty if no user is associated with this UserId + * @return an Optional containing the {@link User}, or empty if no user is associated with this + * UserId */ public Optional getByUserId(UserId userId) { return Optional.ofNullable(byId.get(userId)); @@ -111,7 +111,8 @@ public class UserRegistry { * Looks up a user by their username. * * @param username the username to look up - * @return an Optional containing the {@link User}, or empty if no user is associated with this username + * @return an Optional containing the {@link User}, or empty if no user is associated with this + * username */ public Optional getByUsername(String username) { return Optional.ofNullable(byName.get(username)); From bfbf4b20152b7aa90b71ad79ec0c1fa0a22b8c3a Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 14:28:56 +0200 Subject: [PATCH 16/22] Add: UsernameAvailability enum with availability states --- .../app/commands/check_nick/UsernameAvailability.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/UsernameAvailability.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/UsernameAvailability.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/UsernameAvailability.java new file mode 100644 index 0000000..1f176d1 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/UsernameAvailability.java @@ -0,0 +1,6 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick; + +public enum UsernameAvailability { + FREE, + TAKEN +} From 9087f009d3d38f2d3ac64dc98c0b989a99dbfd5e Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 14:33:26 +0200 Subject: [PATCH 17/22] Add: CheckUsernameResponse containing username availability field --- .../commands/check_nick/CheckUsernameResponse.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameResponse.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameResponse.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameResponse.java new file mode 100644 index 0000000..70fcb60 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameResponse.java @@ -0,0 +1,11 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick; + +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.SuccessResponse; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.ResponseBodyBuilder; + +public class CheckUsernameResponse extends SuccessResponse { + public CheckUsernameResponse(RequestContext context, UsernameAvailability availability) { + super(context, new ResponseBodyBuilder().param("STATUS", availability).build()); + } +} From 5fa478c4406c4a5133d72686fd6af356deb5729f Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 14:33:59 +0200 Subject: [PATCH 18/22] Add: CheckUsernameHandler getting User from UserRegistry and determining availablity --- .../check_nick/CheckUsernameHandler.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameHandler.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameHandler.java new file mode 100644 index 0000000..d2c1d28 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameHandler.java @@ -0,0 +1,29 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick; + +import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.User; +import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry; +import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandler; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher; +import java.util.Optional; + +public class CheckUsernameHandler implements CommandHandler { + private final ResponseDispatcher responseDispatcher; + private final UserRegistry userRegistry; + + public CheckUsernameHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) { + this.responseDispatcher = responseDispatcher; + this.userRegistry = userRegistry; + } + + @Override + public void execute(CheckUsernameRequest request) { + Optional user = userRegistry.getByUsername(request.getUsername()); + UsernameAvailability availability; + if (user.isEmpty()) { + availability = UsernameAvailability.FREE; + } else { + availability = UsernameAvailability.TAKEN; + } + responseDispatcher.dispatch(new CheckUsernameResponse(request.getContext(), availability)); + } +} From 5ef2fa5df1a6a314036f8e0b36a45e4fe3c2b3fd Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 14:34:24 +0200 Subject: [PATCH 19/22] Refactor: Change UsernameAvailability from public to package-private access --- .../server/app/commands/check_nick/UsernameAvailability.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/UsernameAvailability.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/UsernameAvailability.java index 1f176d1..4cf42eb 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/UsernameAvailability.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/UsernameAvailability.java @@ -1,6 +1,6 @@ package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick; -public enum UsernameAvailability { +enum UsernameAvailability { FREE, TAKEN } From 72e3d257ffc8aa1b2fc4467fa522410c123fb3bd Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 14:35:56 +0200 Subject: [PATCH 20/22] Add: Register CheckUsernameHandler in composition root --- .../ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java | 5 +++++ 1 file changed, 5 insertions(+) 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 a182f80..48ac98f 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,6 +1,8 @@ package ch.unibas.dmi.dbis.cs108.casono.server; +import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick.CheckUsernameHandler; import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick.CheckUsernameParser; +import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick.CheckUsernameRequest; import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingHandler; import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingParser; import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingRequest; @@ -86,5 +88,8 @@ public class ServerApp { commandRouter.register(PingRequest.class, new PingHandler(responseDispatcher)); parserDispatcher.register("CHECK_USERNAME", new CheckUsernameParser()); + commandRouter.register( + CheckUsernameRequest.class, + new CheckUsernameHandler(responseDispatcher, userRegistry)); } } From de11d673dc0f18949b163520f14f226688dc0a69 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 15:02:00 +0200 Subject: [PATCH 21/22] Docs: Write JavaDoc for added components --- .../commands/check_nick/CheckUsernameHandler.java | 15 +++++++++++++++ .../commands/check_nick/CheckUsernameParser.java | 7 +++++++ .../commands/check_nick/CheckUsernameRequest.java | 13 +++++++++++++ .../check_nick/CheckUsernameResponse.java | 7 +++++++ .../commands/check_nick/UsernameAvailability.java | 4 ++++ 5 files changed, 46 insertions(+) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameHandler.java index d2c1d28..c238ba1 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameHandler.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameHandler.java @@ -6,15 +6,30 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandH import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher; import java.util.Optional; +/** Handles {@link CheckUsernameRequest}s to check whether a username is available. */ public class CheckUsernameHandler implements CommandHandler { private final ResponseDispatcher responseDispatcher; private final UserRegistry userRegistry; + /** + * Creates a new handler for checking username availability. + * + * @param responseDispatcher the dispatcher used to send the response + * @param userRegistry the registry used to look up existing users + */ public CheckUsernameHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) { this.responseDispatcher = responseDispatcher; this.userRegistry = userRegistry; } + /** + * Executes the username availability check for the given request. + * + *

If no user exists for the requested username, the username is reported as {@link + * UsernameAvailability#FREE}; otherwise, it is reported as {@link UsernameAvailability#TAKEN}. + * + * @param request the request to execute + */ @Override public void execute(CheckUsernameRequest request) { Optional user = userRegistry.getByUsername(request.getUsername()); diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameParser.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameParser.java index 24b5263..07df259 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameParser.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameParser.java @@ -4,7 +4,14 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.CommandPar import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.PrimitiveRequest; import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.accessor.RequestParameterAccessor; +/** Parses a primitive request into a {@link CheckUsernameRequest}. */ public class CheckUsernameParser implements CommandParser { + /** + * Extracts the required {@code USERNAME} parameter from the incoming request. + * + * @param primitiveRequest the request to parse + * @return {@link CheckUsernameRequest} containing the username + */ @Override public CheckUsernameRequest parse(PrimitiveRequest primitiveRequest) { RequestParameterAccessor accessor = new RequestParameterAccessor(primitiveRequest.parameters()); diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameRequest.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameRequest.java index 0b5bda6..e5c34fa 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameRequest.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameRequest.java @@ -3,14 +3,27 @@ package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick; import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request; import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestContext; +/** Request implementation used to check whether a username is available or already taken */ public class CheckUsernameRequest extends Request { private final String username; + /** + * Constructs a new CheckUsernameRequest with the given context and username to check + * + * @param context the {@link RequestContext} containing information for responding to the + * request + * @param username the username to check for availability + */ public CheckUsernameRequest(RequestContext context, String username) { super(context); this.username = username; } + /** + * Returns the provided username in the request + * + * @return username to check + */ public String getUsername() { return username; } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameResponse.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameResponse.java index 70fcb60..5018323 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameResponse.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameResponse.java @@ -4,7 +4,14 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.RequestCo import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.SuccessResponse; import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.ResponseBodyBuilder; +/** Response indicating the availability status of a username check. */ public class CheckUsernameResponse extends SuccessResponse { + /** + * Creates a new response to respond to the username availability check to + * + * @param context the {@link RequestContext} associated with the request + * @param availability the availability status of the requested username + */ public CheckUsernameResponse(RequestContext context, UsernameAvailability availability) { super(context, new ResponseBodyBuilder().param("STATUS", availability).build()); } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/UsernameAvailability.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/UsernameAvailability.java index 4cf42eb..df3d358 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/UsernameAvailability.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/UsernameAvailability.java @@ -1,6 +1,10 @@ package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick; +/** Represents the availability status of a username */ enum UsernameAvailability { + /** Username is available */ FREE, + + /** Username is already in use */ TAKEN } From 93dba00a4d961a497e36fc873a3adc59b0f58a52 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Thu, 2 Apr 2026 15:02:58 +0200 Subject: [PATCH 22/22] Style: Apply Spotless --- .../server/app/commands/check_nick/CheckUsernameParser.java | 3 ++- .../server/app/commands/check_nick/CheckUsernameRequest.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameParser.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameParser.java index 07df259..20624c0 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameParser.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameParser.java @@ -14,7 +14,8 @@ public class CheckUsernameParser implements CommandParser */ @Override public CheckUsernameRequest parse(PrimitiveRequest primitiveRequest) { - RequestParameterAccessor accessor = new RequestParameterAccessor(primitiveRequest.parameters()); + RequestParameterAccessor accessor = + new RequestParameterAccessor(primitiveRequest.parameters()); return new CheckUsernameRequest(primitiveRequest.context(), accessor.require("USERNAME")); } } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameRequest.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameRequest.java index e5c34fa..7247b0e 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameRequest.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/check_nick/CheckUsernameRequest.java @@ -9,7 +9,7 @@ public class CheckUsernameRequest extends Request { /** * Constructs a new CheckUsernameRequest with the given context and username to check - * + * * @param context the {@link RequestContext} containing information for responding to the * request * @param username the username to check for availability