Create interfaces and classes required for responding to a request #8

Closed
opened 2026-03-19 16:10:13 +01:00 by lars.winzer · 28 comments
lars.winzer commented 2026-03-19 16:10:13 +01:00 (Migrated from git.scicore.unibas.ch)

Task

Summary

After a request has been processed, the server needs to respond to it.

Context

Domain and Transport

Affected Components

Session, CommandRouter

Definition of Done

  • Created outlined interfaces
  • Created class for ResponseDispatcher, ResponseEncoder

Notes

PlantUML Diagramm code

Note

The diagramm has been enhanced by Claude. But the base with all components outlined came from me.

@startuml

' Encodable / Response Hierarchy

interface Encodable {
  + encode(): String
}

abstract class Response {
  - sessionId: SessionId
  - requestId: int
  + sessionId(): SessionId
  + requestId(): int
}

class SuccessResponse {
  + encode(): String
}

class ErrorResponse {
  + encode(): String
}

class OkResponse {
  + encode(): String
}

Response ..|> Encodable
SuccessResponse --|> Response
ErrorResponse --|> Response
OkResponse --|> SuccessResponse

' Transport boundary types

class PrimitiveResponse <<record>> {
  + sessionId: SessionId
  + requestId: int
  + payload: String
}

class RawPacket <<record>> {
  + requestId: int
  + payload: String
}

note right of RawPacket
  Only known for
  SessionReader and SessionWriter
end note

' Encoding & Dispatch

class ResponseEncoder {
  + encode(response: Response): PrimitiveResponse
}

class ResponseDispatcher {
  - sessionManager: SessionManager
  - encoder: ResponseEncoder
  + dispatch(response: Response): void
}

ResponseEncoder ..> Response        : uses
ResponseEncoder ..> PrimitiveResponse : creates

ResponseDispatcher --> ResponseEncoder  : 1. encode()
ResponseDispatcher --> SessionManager   : 2. getSession(sessionId)
ResponseDispatcher ..> PrimitiveResponse : 3. queue.put()

' Session / Transport Layer

class SessionManager {
  + getSessionById(sessionId: SessionId): Session
}

class Session {
  - outgoingQueue: BlockingQueue<PrimitiveResponse>
  + outgoingQueue(): BlockingQueue<PrimitiveResponse>
}

class SessionWriter <<Runnable>> {
  - session: Session
  + run(): void
}

SessionManager --> Session     : manages
SessionWriter  --> Session     : reads queue from
SessionWriter  ..> RawPacket   : creates
SessionWriter  ..> PrimitiveResponse : consumes

' CommandHandler

class CommandHandler {
  + handle(request: Request): void
}

CommandHandler ..> Response         : creates
CommandHandler --> ResponseDispatcher : calls

@enduml

VERT_serverside-response.png{width=900 height=419}

Checklist

  • Linked to other issues or branches that must be completed first?
## Task ### Summary After a request has been processed, the server needs to respond to it. ### Context Domain and Transport ### Affected Components Session, CommandRouter ### Definition of Done - [x] Created outlined interfaces - [x] Created class for ResponseDispatcher, ResponseEncoder ### Notes <details> <summary>PlantUML Diagramm code</summary> > [!NOTE] > The diagramm has been enhanced by Claude. But the base with all components outlined came from me. ```plantuml @startuml ' Encodable / Response Hierarchy interface Encodable { + encode(): String } abstract class Response { - sessionId: SessionId - requestId: int + sessionId(): SessionId + requestId(): int } class SuccessResponse { + encode(): String } class ErrorResponse { + encode(): String } class OkResponse { + encode(): String } Response ..|> Encodable SuccessResponse --|> Response ErrorResponse --|> Response OkResponse --|> SuccessResponse ' Transport boundary types class PrimitiveResponse <<record>> { + sessionId: SessionId + requestId: int + payload: String } class RawPacket <<record>> { + requestId: int + payload: String } note right of RawPacket Only known for SessionReader and SessionWriter end note ' Encoding & Dispatch class ResponseEncoder { + encode(response: Response): PrimitiveResponse } class ResponseDispatcher { - sessionManager: SessionManager - encoder: ResponseEncoder + dispatch(response: Response): void } ResponseEncoder ..> Response : uses ResponseEncoder ..> PrimitiveResponse : creates ResponseDispatcher --> ResponseEncoder : 1. encode() ResponseDispatcher --> SessionManager : 2. getSession(sessionId) ResponseDispatcher ..> PrimitiveResponse : 3. queue.put() ' Session / Transport Layer class SessionManager { + getSessionById(sessionId: SessionId): Session } class Session { - outgoingQueue: BlockingQueue<PrimitiveResponse> + outgoingQueue(): BlockingQueue<PrimitiveResponse> } class SessionWriter <<Runnable>> { - session: Session + run(): void } SessionManager --> Session : manages SessionWriter --> Session : reads queue from SessionWriter ..> RawPacket : creates SessionWriter ..> PrimitiveResponse : consumes ' CommandHandler class CommandHandler { + handle(request: Request): void } CommandHandler ..> Response : creates CommandHandler --> ResponseDispatcher : calls @enduml ``` </details> ![VERT_serverside-response.png](/uploads/7391f9688d4fc48b7aed31bb7a82b885/VERT_serverside-response.png){width=900 height=419} ### Checklist - [x] Linked to other issues or branches that must be completed first?
lars.winzer commented 2026-03-19 16:10:42 +01:00 (Migrated from git.scicore.unibas.ch)

assigned to @lars.winzer

assigned to @lars.winzer
lars.winzer commented 2026-03-19 16:20:46 +01:00 (Migrated from git.scicore.unibas.ch)

changed the description

changed the description
lars.winzer commented 2026-03-19 16:22:59 +01:00 (Migrated from git.scicore.unibas.ch)

created branch feat/serverside-response to address this issue

created branch [`feat/serverside-response`](/cs108-fs26/Gruppe-13/-/compare/main...feat%2Fserverside-response) to address this issue
lars.winzer commented 2026-03-19 16:23:06 +01:00 (Migrated from git.scicore.unibas.ch)

changed title from Create interfaces required for responding to a request to Create interfaces and classes required for responding to a request

<p>changed title from <code class="idiff">Create interfaces required for responding to a request</code> to <code class="idiff">Create interfaces <span class="idiff left right addition">and classes </span>required for responding to a request</code></p>
lars.winzer commented 2026-03-19 16:23:32 +01:00 (Migrated from git.scicore.unibas.ch)

changed the description

changed the description
lars.winzer commented 2026-03-19 16:57:10 +01:00 (Migrated from git.scicore.unibas.ch)

changed the description

changed the description
lars.winzer commented 2026-03-19 16:59:08 +01:00 (Migrated from git.scicore.unibas.ch)

marked this task as related to #9

marked this task as related to #9
lars.winzer commented 2026-03-19 16:59:14 +01:00 (Migrated from git.scicore.unibas.ch)

removed the relation with #9

removed the relation with #9
lars.winzer commented 2026-03-19 16:59:25 +01:00 (Migrated from git.scicore.unibas.ch)

marked this task as related to #9

marked this task as related to #9
lars.winzer commented 2026-03-19 17:01:06 +01:00 (Migrated from git.scicore.unibas.ch)

added 30m of time spent at 2026-03-19 12:00:00 +0100

added 30m of time spent at 2026-03-19 12:00:00 +0100
lars.winzer commented 2026-03-23 10:43:29 +01:00 (Migrated from git.scicore.unibas.ch)

Now that the weekend is over, I'm ready to get back to work here.

Now that the weekend is over, I'm ready to get back to work here.
lars.winzer commented 2026-03-23 10:55:24 +01:00 (Migrated from git.scicore.unibas.ch)

changed the description

changed the description
lars.winzer commented 2026-03-23 10:58:59 +01:00 (Migrated from git.scicore.unibas.ch)

changed the description

changed the description
lars.winzer commented 2026-03-23 11:03:37 +01:00 (Migrated from git.scicore.unibas.ch)

added 10m of time spent at 2026-03-23 12:00:00 +0100

added 10m of time spent at 2026-03-23 12:00:00 +0100
lars.winzer commented 2026-03-23 15:22:21 +01:00 (Migrated from git.scicore.unibas.ch)

As I began implementing the base classes ever response needs to implement, I came across the following issue: How do you encode complex responses like for the game state?

It holds many values, like the value of the pot and cards, whereas each card has its own value and color. Same goes for the played with its name, value and cards on its hand.

As a possible solution, I looked into how Indent-Stack-Parser work and came up with this format.

With END after each block

+OK
  PHASE=FLO P
  POT=150
  CURRENT_BET=50
  DEALER=0
  ACTIVE_PLAYER=1
  CARDS
    CARD 
      VALUE=10
      SUIT=H
    END
    CARD 
      VALUE=7
      SUIT=S
    END
    CARD 
      VALUE=A
      SUIT=D
    END
  END
  PLAYERS
    PLAYER
      NAME=Max
      CHIPS=1200
      BET=50
      STATE=ACTIVE
      CARDS
        CARD 
          VALUE=K
          SUIT=H
        END
        CARD 
          VALUE=3
          SUIT=C
        END
      END
    PLAYER
      NAME=Anna
      CHIPS=800
      BET=0
      STATE=FOLDED
      CARDS
    END
  END
END

Without END after each block

+OK
  PHASE=FLO P
  POT=150
  CURRENT_BET=50
  DEALER=0
  ACTIVE_PLAYER=1
  CARDS
    CARD 
      VALUE=10
      SUIT=H
    CARD 
      VALUE=7
      SUIT=S
    CARD 
      VALUE=A
      SUIT=D
  PLAYERS
    PLAYER
      NAME=Max
      CHIPS=1200
      BET=50
      STATE=ACTIVE
      CARDS
        CARD 
          VALUE=K
          SUIT=H
        CARD 
          VALUE=3
          SUIT=C
    PLAYER
      NAME=Anna
      CHIPS=800
      BET=0
      STATE=FOLDED
      CARDS
END

The one with closing END after each block is much easier to parse and check for syntax errors.

As I began implementing the base classes ever response needs to implement, I came across the following issue: How do you encode complex responses like for the game state? It holds many values, like the value of the pot and cards, whereas each card has its own value and color. Same goes for the played with its name, value and cards on its hand. As a possible solution, I looked into how Indent-Stack-Parser work and came up with this format. ### With END after each block ``` +OK PHASE=FLO P POT=150 CURRENT_BET=50 DEALER=0 ACTIVE_PLAYER=1 CARDS CARD VALUE=10 SUIT=H END CARD VALUE=7 SUIT=S END CARD VALUE=A SUIT=D END END PLAYERS PLAYER NAME=Max CHIPS=1200 BET=50 STATE=ACTIVE CARDS CARD VALUE=K SUIT=H END CARD VALUE=3 SUIT=C END END PLAYER NAME=Anna CHIPS=800 BET=0 STATE=FOLDED CARDS END END END ``` ### Without END after each block ``` +OK PHASE=FLO P POT=150 CURRENT_BET=50 DEALER=0 ACTIVE_PLAYER=1 CARDS CARD VALUE=10 SUIT=H CARD VALUE=7 SUIT=S CARD VALUE=A SUIT=D PLAYERS PLAYER NAME=Max CHIPS=1200 BET=50 STATE=ACTIVE CARDS CARD VALUE=K SUIT=H CARD VALUE=3 SUIT=C PLAYER NAME=Anna CHIPS=800 BET=0 STATE=FOLDED CARDS END ``` The one with closing `END` after each block is much easier to parse and check for syntax errors.
lars.winzer commented 2026-03-23 15:23:57 +01:00 (Migrated from git.scicore.unibas.ch)

It has already been asked on the discord if this structure can be used.

The post can be found here

It has already been asked on the discord if this structure can be used. The post can be found [here](https://discord.com/channels/1472900989014245498/1485643041610928238)
lars.winzer commented 2026-03-23 15:28:04 +01:00 (Migrated from git.scicore.unibas.ch)

added 1h 50m of time spent at 2026-03-23 12:00:00 +0100

added 1h 50m of time spent at 2026-03-23 12:00:00 +0100
lars.winzer commented 2026-03-24 10:12:22 +01:00 (Migrated from git.scicore.unibas.ch)

Due to lack of response from my team members (after almost 24 hours), I decieded to move forward with the first approach (With END after each block).

Due to lack of response from my team members (after almost 24 hours), I decieded to move forward with the first approach (With END after each block).
lars.winzer commented 2026-03-24 12:07:02 +01:00 (Migrated from git.scicore.unibas.ch)

After doing some research I changed the model to match our needs.

The Encodable interface, the Response abstract class and the SuccessResponse and ErrorResponse will still serve the same purpose, albeit slightly different. Instead of storing the data directly and encoding it via the payload method, they now internally use the ResponseBody and ResponseBodyBuilder .

The purpose of the ResponseBody and ResponseBodyBuilder is it, to provide an usable API to create responses with.

After the Response has been created, it will be encoded by the ResponseEncoder to a PrimitiveResponse. If the post (mentioned in this comment) will reject the use of our structure, this would be the only part that needs to be touched to comply.


I used the following ressources as my base:

I probably forgot one or the other design-pattern, as I kinda got lost yesterday evening, and maybe did not apply each of them correctly. But I did so to the best of my ability.

In general I really enjoyed the guides and deep dives this site has to offer. The drawings and easy language makes it easy to follow along.

After doing some research I changed the model to match our needs. The `Encodable` interface, the `Response` abstract class and the `SuccessResponse` and `ErrorResponse` will still serve the same purpose, albeit slightly different. Instead of storing the data directly and encoding it via the payload method, they now internally use the `ResponseBody` and `ResponseBodyBuilder` . The purpose of the `ResponseBody` and `ResponseBodyBuilder` is it, to provide an usable API to create responses with. After the `Response` has been created, it will be encoded by the `ResponseEncoder` to a `PrimitiveResponse`. If the post (mentioned in [this comment](https://git.scicore.unibas.ch/cs108-fs26/Gruppe-13/-/work_items/8#note_44262)) will reject the use of our structure, this would be the only part that needs to be touched to comply. --- I used the following ressources as my base: * [Composite by Refactoring Guru](https://refactoring.guru/design-patterns/composite) * [Builder by Refactoring Guru](https://refactoring.guru/design-patterns/builder) * [Visitor by Refactoring Guru](https://refactoring.guru/design-patterns/visitor) I probably forgot one or the other design-pattern, _as I kinda got lost yesterday evening_, and maybe did not apply each of them correctly. But I did so to the best of my ability. In general I really enjoyed the guides and _deep dives_ this site has to offer. The drawings and easy language makes it easy to follow along.
lars.winzer commented 2026-03-24 12:07:53 +01:00 (Migrated from git.scicore.unibas.ch)

added 1h 15m of time spent at 2026-03-24 12:00:00 +0100

added 1h 15m of time spent at 2026-03-24 12:00:00 +0100
lars.winzer commented 2026-03-24 12:55:21 +01:00 (Migrated from git.scicore.unibas.ch)

In addition to the latest commit (796827cbb4), the code I tested the ResponseBodyBuilder with. Mostly for demonstrating how the user-facing API looks like.

public class BuilderTest {
    public static void main(String[] args) {
        ResponseBody body = ResponseBody.builder()
            .param("POT", 140)
            .param("PHASE", "FLOP")
            .block("CARDS", cards -> {
                cards.block("CARD", card -> card
                    .param("VALUE", 10)
                    .param("SUIT", "H")
                );
            })
            .build();

        System.out.println(body.nodes());
    }
}

Output:

[ResponseParameter[key=POT, value=140], ResponseParameter[key=PHASE, value=PLAY], ResponseBlock[tag=CARDS, children=[ResponseBlock[tag=CARD, children=[ResponseParameter[key=VALUE, value=12], ResponseParameter[key=SUIT, value=KJ]]]]]]
In addition to the latest commit (796827cbb4e57860d167ebffce3176affa92f0a7), the code I tested the `ResponseBodyBuilder` with. Mostly for demonstrating how the user-facing API looks like. ```java public class BuilderTest { public static void main(String[] args) { ResponseBody body = ResponseBody.builder() .param("POT", 140) .param("PHASE", "FLOP") .block("CARDS", cards -> { cards.block("CARD", card -> card .param("VALUE", 10) .param("SUIT", "H") ); }) .build(); System.out.println(body.nodes()); } } ``` Output: ``` [ResponseParameter[key=POT, value=140], ResponseParameter[key=PHASE, value=PLAY], ResponseBlock[tag=CARDS, children=[ResponseBlock[tag=CARD, children=[ResponseParameter[key=VALUE, value=12], ResponseParameter[key=SUIT, value=KJ]]]]]] ```
lars.winzer commented 2026-03-24 14:37:07 +01:00 (Migrated from git.scicore.unibas.ch)

added 2h 17m of time spent at 2026-03-24 12:00:00 +0100

added 2h 17m of time spent at 2026-03-24 12:00:00 +0100
lars.winzer commented 2026-03-24 14:46:27 +01:00 (Migrated from git.scicore.unibas.ch)

marked this task as related to #12

marked this task as related to #12
lars.winzer commented 2026-03-24 14:46:46 +01:00 (Migrated from git.scicore.unibas.ch)

marked the checklist item Created outlined interfaces as completed

marked the checklist item **Created outlined interfaces** as completed
lars.winzer commented 2026-03-24 14:46:47 +01:00 (Migrated from git.scicore.unibas.ch)

marked the checklist item Created class for ResponseDispatcher, ResponseEncoder as completed

marked the checklist item **Created class for ResponseDispatcher, ResponseEncoder** as completed
lars.winzer commented 2026-03-24 15:00:51 +01:00 (Migrated from git.scicore.unibas.ch)

mentioned in merge request !44

mentioned in merge request !44
lars.winzer commented 2026-03-24 15:02:16 +01:00 (Migrated from git.scicore.unibas.ch)

mentioned in commit 03b6c30625

mentioned in commit 03b6c3062591fb7a7f7c734f79a8a2f35b57cd29
lars.winzer (Migrated from git.scicore.unibas.ch) closed this issue 2026-03-24 15:02:17 +01:00
lars.winzer commented 2026-03-24 18:57:48 +01:00 (Migrated from git.scicore.unibas.ch)

mentioned in task #14

mentioned in task #14
This repo is archived. You cannot comment on issues.
1 Participants
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: University-of-Basel-Studentprojects/Programmierprojekt#8