Fix: Resolving Git Merge Conflicts #253

Merged
j.kropff merged 69 commits from chore/ui-checkstyle-fixes into main 2026-04-11 15:10:58 +02:00
10 changed files with 317 additions and 3 deletions
Showing only changes of commit 8fb2657cdd - Show all commits
+28 -1
View File
@@ -48,6 +48,9 @@ gradle-app.setting
# JDT-specific (Eclipse Java Development Tools)
.classpath
# Gradle properties
gradle.properties
## MacOS
# General
.DS_Store
@@ -122,4 +125,28 @@ $RECYCLE.BIN/
## bin
bin/
gradle.properties
# LaTeX (TeX)
## Core latex/pdflatex auxiliary files:
*.aux
*.lof
*.log
*.lot
*.fls
*.out
*.toc
*.fmt
*.fot
*.cb
*.cb2
.*.lb
## Build tool auxiliary files:
*.fdb_latexmk
*.synctex
*.synctex(busy)
*.synctex.gz
*.synctex.gz(busy)
*.pdfsync
*.rubbercache
rubber.cache
@@ -3,6 +3,12 @@ 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.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;
@@ -91,5 +97,13 @@ public class ServerApp {
commandRouter.register(
CheckUsernameRequest.class,
new CheckUsernameHandler(responseDispatcher, userRegistry));
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));
}
}
@@ -0,0 +1,58 @@
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.login;
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.User;
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserFactory;
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserId;
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.dispatcher.ResponseDispatcher;
import java.util.Optional;
/**
* Handles {@link LoginRequest}s to create a user for a session, if the session has not assigned one
* already
*/
public class LoginHandler implements CommandHandler<LoginRequest> {
private final ResponseDispatcher responseDispatcher;
private final UserRegistry userRegistry;
private final UserFactory userFactory;
/**
* Creates a new handler for checking for existing user and creating a new one
*
* @param responseDispatcher the dispatcher used to send the response
* @param userRegistry the registry used to look up existing users and create the new one
*/
public LoginHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) {
this.responseDispatcher = responseDispatcher;
this.userRegistry = userRegistry;
this.userFactory = new UserFactory(userRegistry);
}
/**
* Executes the login request
*
* <p>If no user is already assigned to the session, a new user is created and its name and
* {@link UserId} returned in the response. If the session has already a user assigned, a {@code
* ALREADY_LOGGED_IN} error is responded with.
*
* @param request the request to execute
*/
@Override
public void execute(LoginRequest request) {
Optional<User> existingUser = userRegistry.getBySessionId(request.getSessionId());
if (existingUser.isPresent()) {
responseDispatcher.dispatch(
new ErrorResponse(
request.getContext(),
"ALREADY_LOGGED_IN",
"This session is already associated with an active user."));
return;
}
User user = userFactory.create(request.getUsername(), request.getSessionId());
responseDispatcher.dispatch(
new LoginResponse(request.getContext(), user.getName(), user.getId()));
}
}
@@ -0,0 +1,21 @@
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.login;
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;
/** Parses a primitive request into a {@link LoginRequest}. */
public class LoginParser implements CommandParser<LoginRequest> {
/**
* Extracts the required {@code USERNAME} parameter from the incoming request.
*
* @param primitiveRequest the request to parse
* @return {@link LoginRequest} containing the username
*/
@Override
public LoginRequest parse(PrimitiveRequest primitiveRequest) {
RequestParameterAccessor accessor =
new RequestParameterAccessor(primitiveRequest.parameters());
return new LoginRequest(primitiveRequest.context(), accessor.require("USERNAME"));
}
}
@@ -0,0 +1,30 @@
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.login;
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 create server-side user instance based on provided username */
public class LoginRequest extends Request {
private final String username;
/**
* Constructs a new LoginRequest with the given context and desired username
*
* @param context the {@link RequestContext} containing information for responding to the
* request
* @param username the desired username when creating the user
*/
public LoginRequest(RequestContext context, String username) {
super(context);
this.username = username;
}
/**
* Returns the desired username requested for login
*
* @return the desired username
*/
public String getUsername() {
return username;
}
}
@@ -0,0 +1,23 @@
package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.login;
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserId;
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;
/** Response containing the assigned username and id of said user */
public class LoginResponse extends SuccessResponse {
/**
* @param context the {@link RequestContext} associated with the request
* @param assignedUsername the assigned username to this user
* @param id of the created user
*/
public LoginResponse(RequestContext context, String assignedUsername, UserId id) {
super(
context,
new ResponseBodyBuilder()
.param("USERNAME", assignedUsername)
.param("ID", id.value())
.build());
}
}
@@ -0,0 +1,45 @@
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<LogoutRequest> {
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.
*
* <p>The user is removed from the {@link UserRegistry}.
*
* @param request the request to execute
*/
@Override
public void execute(LogoutRequest request) {
boolean wasRemoved = userRegistry.removeBySessionId(request.getSessionId());
if (wasRemoved) {
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?"));
}
}
}
@@ -0,0 +1,19 @@
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<LogoutRequest> {
/**
* 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());
}
}
@@ -0,0 +1,18 @@
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);
}
}
@@ -31,6 +31,66 @@ public class UserRegistry {
return Optional.of(user);
}
/**
* Removes a user from the registry by user ID.
*
* @param userId the ID of the user to remove
* @return true if a user was removed, false if no user with that ID exists
*/
public synchronized boolean removeByUserId(UserId userId) {
User user = byId.get(userId);
if (user == null) {
return false;
}
byName.remove(user.getName());
user.getSessionId().ifPresent(bySessionId::remove);
return true;
}
/**
* Removes a user from the registry by session ID.
*
* @param sessionId the session ID associated with the user to remove
* @return true if a user was removed, false if no user with that session exists
*/
public synchronized boolean removeBySessionId(SessionId sessionId) {
User user = bySessionId.get(sessionId);
if (user == null) {
return false;
}
remove(user);
return true;
}
/**
* Removes a user from the registry by username.
*
* @param username the username associated with the user to remove
* @return true if a user was removed, false if no user with that session exists
*/
public synchronized boolean removeByUsername(String username) {
User user = byName.get(username);
if (user == null) {
return false;
}
remove(user);
return true;
}
/**
* Removes a user from the internals of the registry.
*
* @param user the user to remove
*/
private synchronized void remove(User user) {
byId.remove(user.getId());
byName.remove(user.getName());
user.getSessionId().ifPresent(bySessionId::remove);
}
/**
* Removes the user with the given ID, but only if they are still disconnected. This prevents
* removing a user who has reconnected between the cleanup job's check and its removal call.
@@ -47,8 +107,7 @@ public class UserRegistry {
return false;
}
byId.remove(user.getId());
byName.remove(user.getName());
remove(user);
return true;
}