From 4ff28932b446731261dc01569acad66c0a79a6d5 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Tue, 7 Apr 2026 12:30:40 +0200 Subject: [PATCH 1/8] Add: LogoutRequest for handling logout commands --- .../server/app/commands/logout/LogoutRequest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutRequest.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutRequest.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutRequest.java new file mode 100644 index 0000000..ee58c0b --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutRequest.java @@ -0,0 +1,10 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout; + +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 LogoutRequest extends Request { + public LogoutRequest(RequestContext context) { + super(context); + } +} From fa0ac684f17961bc544c27ac61b6770310525a86 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Tue, 7 Apr 2026 12:31:48 +0200 Subject: [PATCH 2/8] Add: LogoutParser for parsing logout requests --- .../server/app/commands/logout/LogoutParser.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutParser.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutParser.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutParser.java new file mode 100644 index 0000000..de8fcfe --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutParser.java @@ -0,0 +1,11 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout; + +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 LogoutParser implements CommandParser { + @Override + public LogoutRequest parse(PrimitiveRequest primitiveRequest) { + return new LogoutRequest(primitiveRequest.context()); + } +} From 8376f681b12074f3b73726f8cbbbdad1a0677cd1 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Tue, 7 Apr 2026 12:40:51 +0200 Subject: [PATCH 3/8] Add: LogoutHandler for processing logout commands --- .../app/commands/logout/LogoutHandler.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java new file mode 100644 index 0000000..7c21229 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java @@ -0,0 +1,22 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout; + +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.OkResponse; +import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher; + +public class LogoutHandler implements CommandHandler { + private final ResponseDispatcher responseDispatcher; + private final UserRegistry userRegistry; + + public LogoutHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) { + this.responseDispatcher = responseDispatcher; + this.userRegistry = userRegistry; + } + + @Override + public void execute(LogoutRequest request) { + userRegistry.onDisconnect(request.getSessionId()); + responseDispatcher.dispatch(new OkResponse(request.getContext())); + } +} From 9a7b1c4deaec1100630e96fd6b87e2e1814a8c26 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Tue, 7 Apr 2026 12:45:52 +0200 Subject: [PATCH 4/8] Add: LOGOUT command in composition root --- .../ch/unibas/dmi/dbis/cs108/casono/server/ServerApp.java | 7 +++++++ 1 file changed, 7 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 4f22358..1b5f62a 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 @@ -6,6 +6,9 @@ import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick.CheckUsern import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.login.LoginHandler; import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.login.LoginParser; import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.login.LoginRequest; +import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout.LogoutHandler; +import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout.LogoutParser; +import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout.LogoutRequest; 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; @@ -98,5 +101,9 @@ public class ServerApp { parserDispatcher.register("LOGIN", new LoginParser()); commandRouter.register( LoginRequest.class, new LoginHandler(responseDispatcher, userRegistry)); + + parserDispatcher.register("LOGOUT", new LogoutParser()); + commandRouter.register( + LogoutRequest.class, new LogoutHandler(responseDispatcher, userRegistry)); } } From 4c10bc7ab03428b07cd5c5b38c25f505db05db1b Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Tue, 7 Apr 2026 13:39:44 +0200 Subject: [PATCH 5/8] Refactor: Use removeBySessionId method instead of onDisconnect handler --- .../cs108/casono/server/app/commands/logout/LogoutHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java index 7c21229..af08e0c 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java @@ -16,7 +16,7 @@ public class LogoutHandler implements CommandHandler { @Override public void execute(LogoutRequest request) { - userRegistry.onDisconnect(request.getSessionId()); + userRegistry.removeBySessionId(request.getSessionId()); responseDispatcher.dispatch(new OkResponse(request.getContext())); } } From 4789273d8ff86c77ed3f1f7c079c3112a86f34d2 Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Tue, 7 Apr 2026 14:02:18 +0200 Subject: [PATCH 6/8] Add: Send ErrorResponse with 'NO_USER_ASSOCIATED' code when no user is associated with the session --- .../server/app/commands/logout/LogoutHandler.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java index af08e0c..c8e00b6 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java @@ -16,7 +16,15 @@ public class LogoutHandler implements CommandHandler { @Override public void execute(LogoutRequest request) { - userRegistry.removeBySessionId(request.getSessionId()); - responseDispatcher.dispatch(new OkResponse(request.getContext())); + boolean was_removed = userRegistry.removeBySessionId(request.getSessionId()); + if (was_removed) { + responseDispatcher.dispatch(new OkResponse(request.getContext())); + } else { + responseDispatcher.dispatch( + new ErrorResponse( + request.getContext(), + "NO_USER_ASSOCIATED", + "No user is associated with your session. Did you login before?")); + } } } From 5ab29a3337074dbba79f2f49dc58d4e841448eec Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Tue, 7 Apr 2026 14:02:44 +0200 Subject: [PATCH 7/8] Docs: Write JavaDoc for added components --- .../server/app/commands/logout/LogoutHandler.java | 15 +++++++++++++++ .../server/app/commands/logout/LogoutParser.java | 8 ++++++++ .../server/app/commands/logout/LogoutRequest.java | 8 ++++++++ 3 files changed, 31 insertions(+) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java index c8e00b6..5876fde 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java @@ -2,18 +2,33 @@ package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout; 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.ErrorResponse; 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; +/** Handles {@link LogoutRequest} to logout connected user. */ public class LogoutHandler implements CommandHandler { private final ResponseDispatcher responseDispatcher; private final UserRegistry userRegistry; + /** + * Creates a new logout handler to logout user. + * + * @param responseDispatcher dispatcher used to send the logout result back to the client + * @param userRegistry registry responsible for tracking connected user sessions + */ public LogoutHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) { this.responseDispatcher = responseDispatcher; this.userRegistry = userRegistry; } + /** + * Executes the logout request for the given request. + * + *

The user is removed from the {@link UserRegistry}. + * + * @param request the request to execute + */ @Override public void execute(LogoutRequest request) { boolean was_removed = userRegistry.removeBySessionId(request.getSessionId()); diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutParser.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutParser.java index de8fcfe..72cdf1c 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutParser.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutParser.java @@ -3,7 +3,15 @@ package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout; import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.CommandParser; import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.PrimitiveRequest; +/** Parses a primitive request into a {@link LogoutRequest}. */ public class LogoutParser implements CommandParser { + + /** + * Parses a primitive request into a LogoutRequest. + * + * @param primitiveRequest the request to parse + * @return the created {@link LogoutRequest} + */ @Override public LogoutRequest parse(PrimitiveRequest primitiveRequest) { return new LogoutRequest(primitiveRequest.context()); diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutRequest.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutRequest.java index ee58c0b..77be0b4 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutRequest.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutRequest.java @@ -3,7 +3,15 @@ package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.logout; 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 logout a currently logged in user */ public class LogoutRequest extends Request { + + /** + * Constructs a new LogoutRequest with the given context. + * + * @param context the {@link RequestContext} containing information for responding to the + * request + */ public LogoutRequest(RequestContext context) { super(context); } From 7c9cf3e00d6158f94a16a55310ac2298bccf1dfc Mon Sep 17 00:00:00 2001 From: Lars Simon Winzer Date: Tue, 7 Apr 2026 14:09:35 +0200 Subject: [PATCH 8/8] Style: Variable naming --- .../casono/server/app/commands/logout/LogoutHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java index 5876fde..c5ca9fd 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/logout/LogoutHandler.java @@ -31,8 +31,8 @@ public class LogoutHandler implements CommandHandler { */ @Override public void execute(LogoutRequest request) { - boolean was_removed = userRegistry.removeBySessionId(request.getSessionId()); - if (was_removed) { + boolean wasRemoved = userRegistry.removeBySessionId(request.getSessionId()); + if (wasRemoved) { responseDispatcher.dispatch(new OkResponse(request.getContext())); } else { responseDispatcher.dispatch(