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 9327139..2391450 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 @@ -3,6 +3,7 @@ package ch.unibas.dmi.dbis.cs108.casono.server; 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; +import ch.unibas.dmi.dbis.cs108.casono.server.network.command.CommandRouter; 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.parser.CommandParserDispatcher; @@ -28,7 +29,9 @@ public class ServerApp { EventBus eventBus = new EventBus(); CommandParserDispatcher dispatcher = new CommandParserDispatcher(); - SessionManager sessionManager = new SessionManager(eventBus, dispatcher); + CommandRouter router = new CommandRouter(); + + SessionManager sessionManager = new SessionManager(eventBus, dispatcher, router); eventBus.subscribe(DisconnectEvent.class, event -> sessionManager.onDisconnect(event)); NetworkManager networkManager = new NetworkManager(port, sessionManager); diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/command/CommandHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/command/CommandHandler.java new file mode 100644 index 0000000..34228c7 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/command/CommandHandler.java @@ -0,0 +1,7 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.network.command; + +import ch.unibas.dmi.dbis.cs108.casono.server.network.parser.Request; + +public interface CommandHandler { + void execute(T request); +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/command/CommandRouter.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/command/CommandRouter.java new file mode 100644 index 0000000..0badeff --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/command/CommandRouter.java @@ -0,0 +1,28 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.network.command; + +import ch.unibas.dmi.dbis.cs108.casono.server.network.parser.Request; +import java.util.HashMap; +import java.util.Map; + +public class CommandRouter { + private final Map, CommandHandler> handlers = new HashMap<>(); + + public void register(Class request, CommandHandler handler) { + handlers.put(request, handler); + } + + // Safe, because during registration, it's ensured that the provided CommandHandler only + // receives requests it can handle. + @SuppressWarnings("unchecked") + public void execute(Request request) { + CommandHandler handler = + (CommandHandler) handlers.get(request.getClass()); + + if (handler == null) { + String requestName = request.getClass().toString(); + throw new UnknownRequestException( + "Unable to execute request " + requestName + ". Type unknown", requestName); + } + handler.execute(request); + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/command/UnknownRequestException.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/command/UnknownRequestException.java new file mode 100644 index 0000000..60c7fa3 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/command/UnknownRequestException.java @@ -0,0 +1,14 @@ +package ch.unibas.dmi.dbis.cs108.casono.server.network.command; + +public class UnknownRequestException extends RuntimeException { + private final String requestName; + + public UnknownRequestException(String message, String requestName) { + super(message); + this.requestName = requestName; + } + + public String getRequestName() { + return requestName; + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/Session.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/Session.java index 6959ed7..d6e2094 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/Session.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/Session.java @@ -1,5 +1,6 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network.sessions; +import ch.unibas.dmi.dbis.cs108.casono.server.network.command.CommandRouter; import ch.unibas.dmi.dbis.cs108.casono.server.network.events.EventBus; import ch.unibas.dmi.dbis.cs108.casono.server.network.parser.CommandParserDispatcher; import ch.unibas.dmi.dbis.cs108.casono.server.network.response.PrimitiveResponse; @@ -14,6 +15,7 @@ public class Session { private final TransportLayer transport; private final BlockingQueue responseQueue; private final CommandParserDispatcher dispatcher; + private final CommandRouter router; private static final int RESPOND_QUEUE_SIZE = 32; /** @@ -24,10 +26,14 @@ public class Session { * @throws IOException if an I/O error occurs during initialization */ public Session( - TransportLayer transport, EventBus eventBus, CommandParserDispatcher dispatcher) { + TransportLayer transport, + EventBus eventBus, + CommandParserDispatcher dispatcher, + CommandRouter router) { this.id = new SessionId(); this.transport = transport; this.dispatcher = dispatcher; + this.router = router; this.responseQueue = new ArrayBlockingQueue<>(RESPOND_QUEUE_SIZE); } @@ -66,4 +72,8 @@ public class Session { public CommandParserDispatcher getDispatcher() { return dispatcher; } + + public CommandRouter getRouter() { + return router; + } } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionManager.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionManager.java index bbf1a14..b3d52a6 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionManager.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/network/sessions/SessionManager.java @@ -1,5 +1,6 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network.sessions; +import ch.unibas.dmi.dbis.cs108.casono.server.network.command.CommandRouter; 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.parser.CommandParserDispatcher; @@ -16,13 +17,16 @@ public class SessionManager { private final EventBus eventBus; private final Logger logger; private final CommandParserDispatcher dispatcher; + private final CommandRouter router; /** Constructs a new SessionManager. */ - public SessionManager(EventBus eventBus, CommandParserDispatcher dispatcher) { + public SessionManager( + EventBus eventBus, CommandParserDispatcher dispatcher, CommandRouter router) { this.sessions = new ConcurrentHashMap<>(); this.eventBus = eventBus; this.logger = LogManager.getLogger(SessionManager.class); this.dispatcher = dispatcher; + this.router = router; } /** @@ -34,16 +38,18 @@ public class SessionManager { * @return newly created session */ public Session create(TransportLayer transport) { - Session session = new Session(transport, eventBus, dispatcher); + Session session = new Session(transport, eventBus, dispatcher, router); SessionReader reader = new SessionReader(session, eventBus); SessionWriter writer = new SessionWriter(session); - Thread readerThread = Thread.ofVirtual() - .name("session-" + session.getId().value() + "-reader") - .unstarted(reader); - Thread writerThread = Thread.ofVirtual() - .name("session-" + session.getId().value() + "-writer") - .unstarted(writer); + Thread readerThread = + Thread.ofVirtual() + .name("session-" + session.getId().value() + "-reader") + .unstarted(reader); + Thread writerThread = + Thread.ofVirtual() + .name("session-" + session.getId().value() + "-writer") + .unstarted(writer); sessions.put(session.getId(), new SessionHandle(session, readerThread, writerThread)); readerThread.start(); 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 0b21190..cd74de9 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 @@ -1,5 +1,6 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network.sessions; +import ch.unibas.dmi.dbis.cs108.casono.server.network.command.CommandRouter; 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.parser.CommandParserDispatcher; @@ -22,6 +23,7 @@ public class SessionReader implements Runnable { private final TransportLayer transport; private final EventBus eventBus; private final CommandParserDispatcher dispatcher; + private final CommandRouter router; private final Logger logger; public SessionReader(Session session, EventBus eventBus) { @@ -29,6 +31,7 @@ public class SessionReader implements Runnable { this.transport = session.getTransport(); this.eventBus = eventBus; this.dispatcher = session.getDispatcher(); + this.router = session.getRouter(); this.logger = LogManager.getLogger( SessionReader.class.toString() + "-" + session.getId().value()); @@ -50,8 +53,11 @@ public class SessionReader implements Runnable { PrimitiveRequest primitiveRequest = new PrimitiveRequest( requestContext, rawRequest.command(), rawRequest.parameters()); + logger.debug("Converted to {}", primitiveRequest); Request request = dispatcher.parse(primitiveRequest); + + router.execute(request); } catch (EOFException e) { logger.info("Client disconnected"); eventBus.publish(new DisconnectEvent(session.getId()));