Files
Flash5/flash/src/main/java/dev/relism/flash/routing/MiddlewareGraph.java
T
Zakaria El Orche 891ef99b8e
CI / Build & Test (push) Failing after 4m51s
CI / Build & Test (pull_request) Canceled after 23s
refactor(core): make boot and middleware ordering deterministic
2026-08-12 16:42:49 +00:00

56 lines
2.6 KiB
Java

package dev.relism.flash.routing;
import dev.relism.flash.models.RequestHandler;
import dev.relism.flash.models.SimpleHandler;
import java.util.*;
/** Boot-only DAG compiler for a route's middleware nodes. */
public final class MiddlewareGraph {
private MiddlewareGraph() {}
public static Middleware[] order(String route, List<MiddlewareNode> nodes) {
if (nodes.isEmpty()) return new Middleware[0];
Map<MiddlewareKey, Integer> index = new LinkedHashMap<>();
for (int i = 0; i < nodes.size(); i++) {
MiddlewareKey key = nodes.get(i).key();
if (index.putIfAbsent(key, i) != null)
throw new IllegalStateException("Duplicate middleware " + key.value() + " on " + route);
}
List<Set<Integer>> outgoing = new ArrayList<>(nodes.size());
int[] incoming = new int[nodes.size()];
for (int i = 0; i < nodes.size(); i++) outgoing.add(new LinkedHashSet<>());
for (int source = 0; source < nodes.size(); source++) {
for (MiddlewareNode.Constraint c : nodes.get(source).constraints()) {
Integer target = index.get(c.target());
if (target == null) {
if (c.required()) throw new IllegalStateException("Middleware " + nodes.get(source).key().value()
+ " on " + route + " requires " + c.target().value() + " to be present");
continue;
}
int from = c.relation() == MiddlewareNode.Relation.AFTER ? target : source;
int to = c.relation() == MiddlewareNode.Relation.AFTER ? source : target;
if (outgoing.get(from).add(to)) incoming[to]++;
}
}
PriorityQueue<Integer> ready = new PriorityQueue<>();
for (int i = 0; i < incoming.length; i++) if (incoming[i] == 0) ready.add(i);
Middleware[] ordered = new Middleware[nodes.size()];
int out = 0;
while (!ready.isEmpty()) {
int current = ready.remove();
ordered[out++] = nodes.get(current).middleware();
for (int next : outgoing.get(current)) if (--incoming[next] == 0) ready.add(next);
}
if (out != nodes.size()) throw new IllegalStateException("Middleware ordering cycle on " + route);
return ordered;
}
/** Pre-composes a sorted chain once at boot. */
public static RequestHandler compose(RequestHandler handler, Middleware[] ordered) {
RequestHandler current = handler;
for (int i = ordered.length - 1; i >= 0; i--) current = new SimpleHandler(ordered[i].wrap(current));
return current;
}
}