Add comprehensive Javadoc documentation to server components, including annotations, request/response handling, routing, and WebSocket support.

This commit is contained in:
CodingPhoenixx
2026-05-29 08:50:05 +02:00
parent f00a1098b4
commit 5d6e8622bf
33 changed files with 1938 additions and 53 deletions
@@ -8,11 +8,31 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Request-pipeline entry point that applies a {@link RateLimitConfig} to incoming requests and
* surfaces the outcome as standard {@code X-RateLimit-*} response headers.
*
* <p>For each request the gate evaluates every {@link RateLimitConfig.Rule rule} that applies
* to the request path. If any rule denies the request, evaluation stops and that denial is
* returned; otherwise the strictest (lowest remaining) allowance is returned so the headers
* reflect the tightest applicable budget.</p>
*
* <p>A daemon background thread periodically triggers cleanup of stale limiter state. The gate
* should be {@link #shutdown() shut down} when the server stops.</p>
*/
public final class RateLimitGate {
/** The rule set this gate enforces. */
private final RateLimitConfig config;
/** Single-threaded scheduler driving periodic cleanup of stale buckets. */
private final ScheduledExecutorService cleanup;
/**
* Creates a gate for the given configuration and starts a background cleanup task that runs
* every five minutes on a daemon thread.
*
* @param config the rate-limit rules to enforce
*/
public RateLimitGate(RateLimitConfig config) {
this.config = config;
this.cleanup = Executors.newSingleThreadScheduledExecutor(r -> {
@@ -22,8 +42,21 @@ public final class RateLimitGate {
});
cleanup.scheduleAtFixedRate(this::doCleanup, 5, 5, TimeUnit.MINUTES);
}
/**
* Evaluates all rules applicable to the given path and decides whether the request may
* proceed.
*
* <p>Each rule's key is namespaced with the rule name to keep buckets from different rules
* independent. The first denial short-circuits and is returned immediately; if every rule
* allows the request, the result with the least remaining quota is returned.</p>
*
* @param req the incoming request, used by key resolvers
* @param path the request path used to select rules
* @param remoteAddress the client's remote address, used as a key-resolver fallback
* @return the limiting result, or {@code null} if no rule applies to the path
*/
public RateLimiter.Result check(HttpRequest req, String path, String remoteAddress) {
List<RateLimitConfig.Rule> rules = config.rulesFor(path);
if (rules.isEmpty()) return null;
@@ -35,7 +68,7 @@ public final class RateLimitGate {
String key = rule.name() + ":" + rule.keyResolver().resolve(req, remoteAddress);
RateLimiter.Result result = rule.limiter().tryAcquire(key, now);
if (!result.allowed()) return result;
if (!result.allowed()) return result;
if (strictest == null || result.remaining() < strictest.remaining()) {
strictest = result;
@@ -44,6 +77,16 @@ public final class RateLimitGate {
return strictest;
}
/**
* Writes the standard rate-limit headers ({@code X-RateLimit-Limit},
* {@code X-RateLimit-Remaining}, and {@code Retry-After} when denied) onto a response.
*
* <p>Does nothing when {@code result} is {@code null} (no rule applied). The retry hint is
* rounded up to whole seconds as required by the {@code Retry-After} header.</p>
*
* @param result the limiting result, may be {@code null}
* @param res the response to decorate
*/
public static void applyHeaders(RateLimiter.Result result, Response res) {
if (result == null) return;
res.header("X-RateLimit-Limit", String.valueOf(result.limit()));
@@ -53,9 +96,16 @@ public final class RateLimitGate {
}
}
/**
* Periodic cleanup hook invoked by the background scheduler to evict limiter state that has
* not been touched recently (older than roughly ten minutes).
*/
private void doCleanup() {
long threshold = 10L * 60 * 1_000_000_000L;
}
/**
* Stops the background cleanup scheduler. Should be called when the server shuts down.
*/
public void shutdown() { cleanup.shutdown(); }
}
}