diff --git a/documents/docs/networking/commands/commands-deep-dive.md b/documents/docs/networking/commands/commands-deep-dive.md index 5a0178c..0540dcb 100644 --- a/documents/docs/networking/commands/commands-deep-dive.md +++ b/documents/docs/networking/commands/commands-deep-dive.md @@ -64,11 +64,31 @@ Concrete subclasses add command-specific fields, all set via constructor. Reques ### `CommandHandler` 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`. -Handlers receive their dependencies (the `ResponseDispatcher`, registries and managers etc.) through constructor injection. -This keeps them fully testable without the network layer. +Handlers receive their dependencies (the `ResponseDispatcher`, registries and managers etc.) through constructor injection. +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` +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` +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` Class diagram of the CommandRouter diff --git a/documents/images/docs/networking/commands/handler_check.png b/documents/images/docs/networking/commands/handler_check.png new file mode 100644 index 0000000..4824d15 Binary files /dev/null and b/documents/images/docs/networking/commands/handler_check.png differ diff --git a/documents/images/docs/networking/commands/handler_check.puml b/documents/images/docs/networking/commands/handler_check.puml new file mode 100644 index 0000000..8343c1b --- /dev/null +++ b/documents/images/docs/networking/commands/handler_check.puml @@ -0,0 +1,8 @@ +@startuml +skinparam backgroundColor transparent + +interface HandlerCheck { + + check(request: Request): Optional +} + +@enduml \ No newline at end of file diff --git a/documents/images/docs/networking/commands/handler_check_executor.png b/documents/images/docs/networking/commands/handler_check_executor.png new file mode 100644 index 0000000..aa3a444 Binary files /dev/null and b/documents/images/docs/networking/commands/handler_check_executor.png differ diff --git a/documents/images/docs/networking/commands/handler_check_executor.puml b/documents/images/docs/networking/commands/handler_check_executor.puml new file mode 100644 index 0000000..07dc033 --- /dev/null +++ b/documents/images/docs/networking/commands/handler_check_executor.puml @@ -0,0 +1,31 @@ +@startuml +skinparam backgroundColor transparent + +class CommandHandlerExecutor { + - responseDispatcher: ResponseDispatcher + + CommandHandlerExecutor(responseDispatcher: ResponseDispatcher) + + execute(handler: CommandHandler, request: Request): void +} + +interface HandlerCheck { + + check(request: Request): Optional +} + +abstract class CommandHandler { + - checks: List + # addCheck(check: HandlerCheck): void + + getChecks(): List + + 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 \ No newline at end of file