Skip to main content

Architecture Overview

Glass Box follows a modular, layered architecture designed for transparency and educational value. The codebase is split into two packages: com.ns.tcpframework (the reusable HTTP server framework) and com.ns.webserver (the application layer with handlers and models).

Request Lifecycle

Every HTTP request passes through these stages:

  1. TCPServer accepts a raw TCP connection and submits the socket to a virtual thread pool.
  2. HTTPHandler receives the socket and delegates parsing to HTTPRequestParser.
  3. HTTPRequestParser reads the raw byte stream, detects the \r\n\r\n header boundary, and constructs an HTTPRequest with the method, path, headers, and body stream.
  4. VirtualHostManager resolves the Host header to the correct VirtualHostConfig.
  5. RouterConfig matches the request path against registered patterns (exact match first, then wildcard patterns like /api/todos/*). If no match is found, the StaticFileHandler is used as the default.
  6. RequestHandler processes the request and returns an HTTPResponse.
  7. The response is serialized and sent back through the socket.

If any stage throws an exception, HTTPErrorHandler catches it and maps it to the appropriate HTTP error response (400, 404, 500, or 501).

Core Components

TCPServer

The entry point of the server. Extends Thread and runs an accept loop on a ServerSocket. Each incoming connection is submitted to an ExecutorService backed by virtual threads.

while (true) {
var clientSocket = serverSocket.accept();
handler.handle(clientSocket, pool);
}

HTTPHandler

Coordinates the full request-response cycle. Receives a socket from TCPServer, delegates parsing, resolves the virtual host, finds the matching handler, and sends the response. Also increments the Stats request counter and logs the request via ServerLogger.

HTTPRequestParser

A stateless utility class that reads HTTP/1.1 from raw input streams. The parser uses a state machine to detect the \r\n\r\n header terminator, then extracts:

  • Request line — method, path, HTTP version
  • Headers — parsed into a LinkedHashMap<String, String[]> (case-insensitive keys, multi-value support)
  • Body — wrapped in a FixedLengthInputStream constrained by the Content-Length header

HTTPRequest and HTTPResponse

Simple data classes. HTTPRequest is immutable after construction. HTTPResponse provides a builder-style API:

HTTPResponse response = new HTTPResponse(200, "OK");
response.setHeader("X-Custom", "value");
response.setBody(jsonBytes, "application/json");
response.send(socket);

Handler Hierarchy

Glass Box provides three base classes for implementing request handlers, each offering a different level of abstraction:

Base ClassUse CasePattern
RequestHandlerFull control over request and socketDirect override
MethodeBasedHandlerHandle requests by HTTP methodTemplate Method
RouteBasedHandlerHandle requests by path patternCommand / Strategy

See Custom Handlers for implementation details.

Configuration and Handler Discovery

Configuration is loaded from YAML files by ConfigLoader, which uses Jackson for deserialization. The HandlerFactory uses the Reflections library to scan the classpath for all RequestHandler subclasses at startup. This means handlers are resolved by simple class name in the YAML config:

routes:
/api/todos/*: ToDoHandler # Resolves to com.ns.webserver.handlers.ToDoHandler
/api/sse: SSEHandler # Resolves to com.ns.tcpframework.reqeustHandlers.sse.SSEHandler

No manual registration or factory wiring is needed — just add a handler class anywhere under the com.ns package and reference it by name.

Threading Model

Glass Box uses Java 25 virtual threads (Executors.newVirtualThreadPerTaskExecutor()). Each incoming connection gets its own lightweight virtual thread, enabling thousands of concurrent connections without the overhead of platform threads.

Key threading details:

  • TCPServer runs on its own platform thread (extends Thread)
  • ServerLogger runs on a dedicated virtual thread, processing log entries from a BlockingQueue
  • Stats runs on a platform thread for system metrics collection (CPU, memory via OSHI)
  • SSE connections keep their virtual thread alive in a sleep loop, broadcasting heartbeats every second

Error Handling

Exceptions are mapped to HTTP status codes by HTTPErrorHandler:

ExceptionStatus CodeResponse
BadRequestException400Bad Request
NotFoundException404Not Found
InternalServerErrorException500Internal Server Error
NotImplementedException501Not Implemented
Any other Exception500Internal Server Error

All errors are also logged via ServerLogger and broadcast to SSE clients.

Full Class Diagram

Click to expand the complete class diagram