Feat/gameui #244
+28
-1
@@ -48,6 +48,9 @@ gradle-app.setting
|
|||||||
# JDT-specific (Eclipse Java Development Tools)
|
# JDT-specific (Eclipse Java Development Tools)
|
||||||
.classpath
|
.classpath
|
||||||
|
|
||||||
|
# Gradle properties
|
||||||
|
gradle.properties
|
||||||
|
|
||||||
## MacOS
|
## MacOS
|
||||||
# General
|
# General
|
||||||
.DS_Store
|
.DS_Store
|
||||||
@@ -122,4 +125,28 @@ $RECYCLE.BIN/
|
|||||||
|
|
||||||
## bin
|
## 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
|
||||||
|
|||||||
@@ -64,11 +64,31 @@ Concrete subclasses add command-specific fields, all set via constructor. Reques
|
|||||||
### `CommandHandler<T extends Request>`
|
### `CommandHandler<T extends Request>`
|
||||||
<img src="../../../images/docs/networking/commands/command_handler.png" alt="Class diagram of the CommandHandler" />
|
<img src="../../../images/docs/networking/commands/command_handler.png" alt="Class diagram of the CommandHandler" />
|
||||||
|
|
||||||
The `CommandHandler` is a single-method interface responsible for executing a typed request.
|
The `CommandHandler` is an abstract base class responsible for executing a typed request.
|
||||||
The handler contains the domain logic: reading from registries and managers, modifying state, and dispatching a response via the `ResponseDispatcher`.
|
The handler contains the domain logic: reading from registries and managers, modifying state, and dispatching a response via the `ResponseDispatcher`.
|
||||||
|
|
||||||
Handlers receive their dependencies (the `ResponseDispatcher`, registries and managers etc.) through constructor injection.
|
Handlers receive their dependencies (the `ResponseDispatcher`, registries and managers etc.) through constructor injection.
|
||||||
This keeps them fully testable without the network layer.
|
They can also register reusable pre-execution checks via `addCheck(...)`. These checks are stored on the handler and are evaluated before `execute(...)` runs.
|
||||||
|
|
||||||
|
When a piece of trivial validation is shared by multiple handlers, it should be extracted into a dedicated `HandlerCheck` instead of being duplicated in each handler.
|
||||||
|
|
||||||
|
### `HandlerCheck`
|
||||||
|
<img src="../../../images/docs/networking/commands/handler_check.png" alt="Class diagram of HandlerCheck and CommandHandlerExecutor" />
|
||||||
|
|
||||||
|
The `HandlerCheck` is a functional interface for reusable pre-execution validation.
|
||||||
|
Its `check(...)` method receives the incoming `Request` and returns an empty `Optional` if the request may continue.
|
||||||
|
If the check fails, it returns an `ErrorResponse` wrapped in the `Optional`, which will be dispatched to the client instead of calling the handler.
|
||||||
|
|
||||||
|
This is the right place for small shared checks such as "is the user logged in?" or other simple preconditions that multiple handlers need.
|
||||||
|
|
||||||
|
### `CommandHandlerExecutor`
|
||||||
|
<img src="../../../images/docs/networking/commands/handler_check_executor.png" alt="Class diagram of HandlerCheck and CommandHandlerExecutor" />
|
||||||
|
|
||||||
|
The `CommandHandlerExecutor` runs all checks registered on a handler before invoking `execute(...)`.
|
||||||
|
If any `HandlerCheck` returns a response, the executor dispatches it immediately and aborts execution.
|
||||||
|
Otherwise, the handler is executed normally.
|
||||||
|
|
||||||
|
This keeps precondition handling separate from the actual domain logic inside the handler.
|
||||||
|
|
||||||
### `CommandRouter`
|
### `CommandRouter`
|
||||||
<img src="../../../images/docs/networking/commands/command_router.png" alt="Class diagram of the CommandRouter" />
|
<img src="../../../images/docs/networking/commands/command_router.png" alt="Class diagram of the CommandRouter" />
|
||||||
|
|||||||
@@ -159,6 +159,9 @@ public class GreetHandler implements CommandHandler<GreetRequest> {
|
|||||||
**Rules for the Handler class:**
|
**Rules for the Handler class:**
|
||||||
|
|
||||||
- Declare all dependencies as `private final` fields, injected through the constructor.
|
- Declare all dependencies as `private final` fields, injected through the constructor.
|
||||||
|
- Use `addCheck(...)` to attach pre-execution checks that should run before `execute(...)`.
|
||||||
|
- If several handlers share the same trivial logic, such as verifying that the user is logged in,
|
||||||
|
extract that logic into a separate `HandlerCheck` and reuse it instead of duplicating the code.
|
||||||
- Always dispatch exactly one response per execution path. Every branch must end with a
|
- Always dispatch exactly one response per execution path. Every branch must end with a
|
||||||
`responseDispatcher.dispatch(...)` call.
|
`responseDispatcher.dispatch(...)` call.
|
||||||
- Use `ErrorResponse` for domain-level failures (e.g. entity not found, precondition not met).
|
- Use `ErrorResponse` for domain-level failures (e.g. entity not found, precondition not met).
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
@@ -0,0 +1,8 @@
|
|||||||
|
@startuml
|
||||||
|
skinparam backgroundColor transparent
|
||||||
|
|
||||||
|
interface HandlerCheck {
|
||||||
|
+ check(request: Request): Optional<Response>
|
||||||
|
}
|
||||||
|
|
||||||
|
@enduml
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
@@ -0,0 +1,31 @@
|
|||||||
|
@startuml
|
||||||
|
skinparam backgroundColor transparent
|
||||||
|
|
||||||
|
class CommandHandlerExecutor {
|
||||||
|
- responseDispatcher: ResponseDispatcher
|
||||||
|
+ CommandHandlerExecutor(responseDispatcher: ResponseDispatcher)
|
||||||
|
+ execute(handler: CommandHandler<Request>, request: Request): void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HandlerCheck {
|
||||||
|
+ check(request: Request): Optional<Response>
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class CommandHandler<T extends Request> {
|
||||||
|
- checks: List<HandlerCheck>
|
||||||
|
# addCheck(check: HandlerCheck): void
|
||||||
|
+ getChecks(): List<HandlerCheck>
|
||||||
|
+ execute(request: T): void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ResponseDispatcher
|
||||||
|
class Request
|
||||||
|
class Response
|
||||||
|
|
||||||
|
CommandHandlerExecutor --> CommandHandler : executes
|
||||||
|
CommandHandler "1" o-- "0..*" HandlerCheck : registered checks
|
||||||
|
CommandHandlerExecutor --> HandlerCheck : evaluates
|
||||||
|
HandlerCheck ..> Request : inspects
|
||||||
|
HandlerCheck ..> Response : returns failure response
|
||||||
|
CommandHandlerExecutor --> ResponseDispatcher : dispatches failures
|
||||||
|
@enduml
|
||||||
@@ -3,12 +3,19 @@ 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.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.CheckUsernameParser;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.check_nick.CheckUsernameRequest;
|
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.PingHandler;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.app.commands.ping.PingParser;
|
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.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.UserCleanupJob;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry;
|
import ch.unibas.dmi.dbis.cs108.casono.server.domain.user.UserRegistry;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.NetworkManager;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.NetworkManager;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandlerExecutor;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandRouter;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandRouter;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.CommandParserDispatcher;
|
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.DisconnectEvent;
|
||||||
@@ -40,11 +47,12 @@ public class ServerApp {
|
|||||||
|
|
||||||
EventBus eventBus = new EventBus();
|
EventBus eventBus = new EventBus();
|
||||||
CommandParserDispatcher dispatcher = new CommandParserDispatcher();
|
CommandParserDispatcher dispatcher = new CommandParserDispatcher();
|
||||||
CommandRouter router = new CommandRouter();
|
SessionManager sessionManager = new SessionManager(eventBus, dispatcher);
|
||||||
|
ResponseDispatcher responseDispatcher = new ResponseDispatcher(sessionManager);
|
||||||
|
CommandHandlerExecutor handlerExecutor = new CommandHandlerExecutor(responseDispatcher);
|
||||||
|
CommandRouter router = new CommandRouter(handlerExecutor);
|
||||||
|
|
||||||
SessionManager sessionManager = new SessionManager(eventBus, dispatcher, router);
|
|
||||||
eventBus.subscribe(DisconnectEvent.class, event -> sessionManager.onDisconnect(event));
|
eventBus.subscribe(DisconnectEvent.class, event -> sessionManager.onDisconnect(event));
|
||||||
NetworkManager networkManager = new NetworkManager(port, sessionManager);
|
|
||||||
|
|
||||||
UserRegistry userRegistry = new UserRegistry();
|
UserRegistry userRegistry = new UserRegistry();
|
||||||
eventBus.subscribe(
|
eventBus.subscribe(
|
||||||
@@ -65,10 +73,9 @@ public class ServerApp {
|
|||||||
SESSION_DISCONNECT_JOB_PERIOD,
|
SESSION_DISCONNECT_JOB_PERIOD,
|
||||||
TimeUnit.SECONDS);
|
TimeUnit.SECONDS);
|
||||||
|
|
||||||
ResponseDispatcher responseDispatcher = new ResponseDispatcher(sessionManager);
|
|
||||||
|
|
||||||
registerCommands(dispatcher, router, responseDispatcher, userRegistry);
|
registerCommands(dispatcher, router, responseDispatcher, userRegistry);
|
||||||
|
|
||||||
|
NetworkManager networkManager = new NetworkManager(port, sessionManager, router);
|
||||||
networkManager.start();
|
networkManager.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,5 +98,13 @@ public class ServerApp {
|
|||||||
commandRouter.register(
|
commandRouter.register(
|
||||||
CheckUsernameRequest.class,
|
CheckUsernameRequest.class,
|
||||||
new CheckUsernameHandler(responseDispatcher, userRegistry));
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.casono.server.app.checks;
|
||||||
|
|
||||||
|
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.checks.HandlerCheck;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.ErrorResponse;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.Response;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class UserLoggedInCheck implements HandlerCheck {
|
||||||
|
private final UserRegistry userRegistry;
|
||||||
|
|
||||||
|
public UserLoggedInCheck(UserRegistry userRegistry) {
|
||||||
|
this.userRegistry = userRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Response> check(Request request) {
|
||||||
|
Optional<User> user = userRegistry.getBySessionId(request.getSessionId());
|
||||||
|
if (user.isPresent()) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
return Optional.of(
|
||||||
|
new ErrorResponse(
|
||||||
|
request.getContext(),
|
||||||
|
"USER_NOT_LOGGED_IN",
|
||||||
|
"The execution of this command requires the user to be logged in"));
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-3
@@ -7,8 +7,7 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatch
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/** Handles {@link CheckUsernameRequest}s to check whether a username is available. */
|
/** Handles {@link CheckUsernameRequest}s to check whether a username is available. */
|
||||||
public class CheckUsernameHandler implements CommandHandler<CheckUsernameRequest> {
|
public class CheckUsernameHandler extends CommandHandler<CheckUsernameRequest> {
|
||||||
private final ResponseDispatcher responseDispatcher;
|
|
||||||
private final UserRegistry userRegistry;
|
private final UserRegistry userRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,7 +17,7 @@ public class CheckUsernameHandler implements CommandHandler<CheckUsernameRequest
|
|||||||
* @param userRegistry the registry used to look up existing users
|
* @param userRegistry the registry used to look up existing users
|
||||||
*/
|
*/
|
||||||
public CheckUsernameHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) {
|
public CheckUsernameHandler(ResponseDispatcher responseDispatcher, UserRegistry userRegistry) {
|
||||||
this.responseDispatcher = responseDispatcher;
|
super(responseDispatcher);
|
||||||
this.userRegistry = userRegistry;
|
this.userRegistry = userRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
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 extends CommandHandler<LoginRequest> {
|
||||||
|
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) {
|
||||||
|
super(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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
+30
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+23
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
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 extends CommandHandler<LogoutRequest> {
|
||||||
|
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) {
|
||||||
|
super(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?"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-3
@@ -5,8 +5,7 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.OkRespon
|
|||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
|
||||||
|
|
||||||
/** Handler for {@link PingRequest}. */
|
/** Handler for {@link PingRequest}. */
|
||||||
public class PingHandler implements CommandHandler<PingRequest> {
|
public class PingHandler extends CommandHandler<PingRequest> {
|
||||||
private final ResponseDispatcher responseDispatcher;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new PingHandler to execute {@link PingRequest}s
|
* Create a new PingHandler to execute {@link PingRequest}s
|
||||||
@@ -14,7 +13,7 @@ public class PingHandler implements CommandHandler<PingRequest> {
|
|||||||
* @param responseDispatcher dispatcher used to send responses back to clients
|
* @param responseDispatcher dispatcher used to send responses back to clients
|
||||||
*/
|
*/
|
||||||
public PingHandler(ResponseDispatcher responseDispatcher) {
|
public PingHandler(ResponseDispatcher responseDispatcher) {
|
||||||
this.responseDispatcher = responseDispatcher;
|
super(responseDispatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -31,6 +31,66 @@ public class UserRegistry {
|
|||||||
return Optional.of(user);
|
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
|
* 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.
|
* 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
byId.remove(user.getId());
|
remove(user);
|
||||||
byName.remove(user.getName());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.casono.server.network;
|
package ch.unibas.dmi.dbis.cs108.casono.server.network;
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandRouter;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionManager;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionManager;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.TcpTransport;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.TcpTransport;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -15,6 +16,7 @@ public class NetworkManager implements Runnable {
|
|||||||
private Thread thread;
|
private Thread thread;
|
||||||
private Boolean running;
|
private Boolean running;
|
||||||
private SessionManager sessionManager;
|
private SessionManager sessionManager;
|
||||||
|
private CommandRouter router;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new NetworkManager with the given port, session manager, and event bus.
|
* Creates a new NetworkManager with the given port, session manager, and event bus.
|
||||||
@@ -22,12 +24,13 @@ public class NetworkManager implements Runnable {
|
|||||||
* @param port the port to listen on
|
* @param port the port to listen on
|
||||||
* @param sessionManager the session manager to use
|
* @param sessionManager the session manager to use
|
||||||
*/
|
*/
|
||||||
public NetworkManager(Integer port, SessionManager sessionManager) {
|
public NetworkManager(Integer port, SessionManager sessionManager, CommandRouter router) {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.logger = LogManager.getLogger(NetworkManager.class);
|
this.logger = LogManager.getLogger(NetworkManager.class);
|
||||||
this.thread = new Thread(this, "networkManager");
|
this.thread = new Thread(this, "networkManager");
|
||||||
this.running = true;
|
this.running = true;
|
||||||
this.sessionManager = sessionManager;
|
this.sessionManager = sessionManager;
|
||||||
|
this.router = router;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Starts the internal thread to accept new connections. */
|
/** Starts the internal thread to accept new connections. */
|
||||||
@@ -45,7 +48,7 @@ public class NetworkManager implements Runnable {
|
|||||||
|
|
||||||
logger.debug("Accepted connection from {}", clientSocket.getRemoteSocketAddress());
|
logger.debug("Accepted connection from {}", clientSocket.getRemoteSocketAddress());
|
||||||
|
|
||||||
sessionManager.create(new TcpTransport(clientSocket));
|
sessionManager.create(new TcpTransport(clientSocket), router);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|||||||
+51
-2
@@ -1,7 +1,56 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution;
|
package ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution;
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.checks.HandlerCheck;
|
||||||
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request;
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface CommandHandler<T extends Request> {
|
/**
|
||||||
void execute(T request);
|
* Abstract base class for handling requests of a specific type.
|
||||||
|
*
|
||||||
|
* @param <T> the type of request this handler processes, must extend {@link Request}
|
||||||
|
*/
|
||||||
|
public abstract class CommandHandler<T extends Request> {
|
||||||
|
private final List<HandlerCheck> checks = new ArrayList<>();
|
||||||
|
protected final ResponseDispatcher responseDispatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a CommandHandler with the specified ResponseDispatcher.
|
||||||
|
*
|
||||||
|
* @param responseDispatcher the ResponseDispatcher instance used to send responses to clients.
|
||||||
|
*/
|
||||||
|
public CommandHandler(ResponseDispatcher responseDispatcher) {
|
||||||
|
this.responseDispatcher = responseDispatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a handler check to be performed before request execution.
|
||||||
|
*
|
||||||
|
* <p>The {@code execute} Method is only invoked, if all specified checks passed.
|
||||||
|
*
|
||||||
|
* @param check the {@link HandlerCheck} to add
|
||||||
|
*/
|
||||||
|
protected final void addCheck(HandlerCheck check) {
|
||||||
|
checks.add(check);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an unmodifiable list of all registered handler checks.
|
||||||
|
*
|
||||||
|
* @return an unmodifiable list of {@link HandlerCheck} objects
|
||||||
|
*/
|
||||||
|
public final List<HandlerCheck> getChecks() {
|
||||||
|
return Collections.unmodifiableList(checks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the request.
|
||||||
|
*
|
||||||
|
* <p>Subclasses should override this method to implement their specific request handling logic.
|
||||||
|
*
|
||||||
|
* @param request the request to execute, of type T
|
||||||
|
*/
|
||||||
|
public void execute(T request) {}
|
||||||
}
|
}
|
||||||
|
|||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution;
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.checks.HandlerCheck;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.Response;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.dispatcher.ResponseDispatcher;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes execution of the {@link CommandHandler} if all defined pre-execution checks pass.
|
||||||
|
*
|
||||||
|
* <p>If any check fails, the response returned by the check is dispatched immediately and execution
|
||||||
|
* is aborted. Otherwise, the handler will invoke execution normally.
|
||||||
|
*/
|
||||||
|
public class CommandHandlerExecutor {
|
||||||
|
private final ResponseDispatcher responseDispatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new CommandHandlerExecutor to execute pre-execution checks and invoke the {@link
|
||||||
|
* CommandHandler} if all checks pass.
|
||||||
|
*
|
||||||
|
* @param responseDispatcher to dispatch the response with if an check fails
|
||||||
|
*/
|
||||||
|
public CommandHandlerExecutor(ResponseDispatcher responseDispatcher) {
|
||||||
|
this.responseDispatcher = responseDispatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a command handler if all defined pre-execution checks pass.
|
||||||
|
*
|
||||||
|
* @param handler the command handler containing checks and execution logic
|
||||||
|
* @param request the incoming request to validate and process
|
||||||
|
* @throws NullPointerException if handler or request is null
|
||||||
|
*/
|
||||||
|
public void execute(CommandHandler<Request> handler, Request request) {
|
||||||
|
for (HandlerCheck check : handler.getChecks()) {
|
||||||
|
Optional<Response> result = check.check(request);
|
||||||
|
if (result.isPresent()) {
|
||||||
|
responseDispatcher.dispatch(result.get());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.execute(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
-1
@@ -4,13 +4,46 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
/** Routes incoming requests to their corresponding {@link CommandHandler} implementations. */
|
||||||
public class CommandRouter {
|
public class CommandRouter {
|
||||||
private final Map<Class<? extends Request>, CommandHandler<?>> handlers = new HashMap<>();
|
private final Map<Class<? extends Request>, CommandHandler<?>> handlers = new HashMap<>();
|
||||||
|
private final CommandHandlerExecutor handlerExecutor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new CommandRouter with the specified handler executor.
|
||||||
|
*
|
||||||
|
* @param commandHandlerExecutor to delegate execution of checks and invocation of {@link
|
||||||
|
* CommandHandler} to
|
||||||
|
*/
|
||||||
|
public CommandRouter(CommandHandlerExecutor commandHandlerExecutor) {
|
||||||
|
this.handlerExecutor = commandHandlerExecutor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a {@link CommandHandler} for a specific request type.
|
||||||
|
*
|
||||||
|
* <p>This method establishes a type-safe mapping between a request class and its handler.
|
||||||
|
*
|
||||||
|
* <p>Only one handler can be registered per request type; subsequent registrations will
|
||||||
|
* overwrite previous ones.
|
||||||
|
*
|
||||||
|
* @param <T> the type of request handled by the provided handler
|
||||||
|
* @param request the request class to associate with the given command handler
|
||||||
|
* @param handler the command handler for the given request type
|
||||||
|
*/
|
||||||
public <T extends Request> void register(Class<T> request, CommandHandler<T> handler) {
|
public <T extends Request> void register(Class<T> request, CommandHandler<T> handler) {
|
||||||
handlers.put(request, handler);
|
handlers.put(request, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the appropriate handler for the given request.
|
||||||
|
*
|
||||||
|
* <p>Looks up the handler registered for the request's class and executes it through the
|
||||||
|
* configured {@link CommandHandlerExecutor}.
|
||||||
|
*
|
||||||
|
* @param request the request to be executed
|
||||||
|
* @throws UnknownRequestException if no handler is registered for the request type
|
||||||
|
*/
|
||||||
// Safe, because during registration, it's ensured that the provided CommandHandler only
|
// Safe, because during registration, it's ensured that the provided CommandHandler only
|
||||||
// receives requests it can handle.
|
// receives requests it can handle.
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@@ -23,6 +56,7 @@ public class CommandRouter {
|
|||||||
throw new UnknownRequestException(
|
throw new UnknownRequestException(
|
||||||
"Unable to execute request " + requestName + ". Type unknown", requestName);
|
"Unable to execute request " + requestName + ". Type unknown", requestName);
|
||||||
}
|
}
|
||||||
handler.execute(request);
|
|
||||||
|
handlerExecutor.execute(handler, request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.checks;
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.execution.CommandHandler;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Request;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.ErrorResponse;
|
||||||
|
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.Response;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functional interface used by pre-execution checks. Executed before the execute method of the
|
||||||
|
* {@link CommandHandler} is called
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface HandlerCheck {
|
||||||
|
/**
|
||||||
|
* Checks that the requirements outlined by this HandlerCheck are fulfilled.
|
||||||
|
*
|
||||||
|
* @param request to execute the check with
|
||||||
|
* @return Optional containing no value if the check was successful. And a {@link ErrorResponse}
|
||||||
|
* if the check failed, the response will be dispatched to the client.
|
||||||
|
*/
|
||||||
|
Optional<Response> check(Request request);
|
||||||
|
}
|
||||||
+3
-5
@@ -19,16 +19,13 @@ public class SessionManager {
|
|||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
private final CommandParserDispatcher dispatcher;
|
private final CommandParserDispatcher dispatcher;
|
||||||
private final CommandRouter router;
|
|
||||||
|
|
||||||
/** Constructs a new SessionManager. */
|
/** Constructs a new SessionManager. */
|
||||||
public SessionManager(
|
public SessionManager(EventBus eventBus, CommandParserDispatcher dispatcher) {
|
||||||
EventBus eventBus, CommandParserDispatcher dispatcher, CommandRouter router) {
|
|
||||||
this.sessions = new ConcurrentHashMap<>();
|
this.sessions = new ConcurrentHashMap<>();
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.logger = LogManager.getLogger(SessionManager.class);
|
this.logger = LogManager.getLogger(SessionManager.class);
|
||||||
this.dispatcher = dispatcher;
|
this.dispatcher = dispatcher;
|
||||||
this.router = router;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,9 +34,10 @@ public class SessionManager {
|
|||||||
* <p>Will create both worker threads and start them.
|
* <p>Will create both worker threads and start them.
|
||||||
*
|
*
|
||||||
* @param transport to create session from
|
* @param transport to create session from
|
||||||
|
* @param router the command router used by the created session
|
||||||
* @return newly created session
|
* @return newly created session
|
||||||
*/
|
*/
|
||||||
public Session create(TransportLayer transport) {
|
public Session create(TransportLayer transport, CommandRouter router) {
|
||||||
Session session = new Session(transport, eventBus, dispatcher, router);
|
Session session = new Session(transport, eventBus, dispatcher, router);
|
||||||
SessionReader reader = new SessionReader(session, eventBus);
|
SessionReader reader = new SessionReader(session, eventBus);
|
||||||
SessionWriter writer = new SessionWriter(session);
|
SessionWriter writer = new SessionWriter(session);
|
||||||
|
|||||||
Reference in New Issue
Block a user