package org.openautonomousconnection.webserver.runtime; import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebRequestPacket; import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebResponsePacket; import org.openautonomousconnection.protocol.side.server.CustomConnectedClient; import org.openautonomousconnection.protocol.side.web.ProtocolWebServer; import org.openautonomousconnection.webserver.WebServer; import org.openautonomousconnection.webserver.api.WebPage; import org.openautonomousconnection.webserver.api.WebPageContext; import org.openautonomousconnection.webserver.utils.HeaderMaps; import org.openautonomousconnection.webserver.utils.RequestParams; import org.openautonomousconnection.webserver.utils.WebHasher; import java.io.File; import java.nio.charset.StandardCharsets; /** * Dispatches Java WebPages using {@code @Route} annotation. * *
This dispatcher relies on {@link JavaRouteRegistry} for route-to-source mapping * and uses {@link JavaPageCache} to compile/load classes from the content tree. */ public final class JavaPageDispatcher { private static final JavaRouteRegistry ROUTES = new JavaRouteRegistry(); private static final JavaPageCache CACHE = new JavaPageCache(); private JavaPageDispatcher() { } /** * Attempts to dispatch a request to a Java WebPage. * * @param client connected client * @param server protocol web server * @param request request packet * @return response packet or {@code null} if no Java route matches and static file handling should proceed * @throws Exception on unexpected failures */ public static WebResponsePacket dispatch( CustomConnectedClient client, ProtocolWebServer server, WebRequestPacket request ) throws Exception { if (request == null || request.getPath() == null) { return null; } String route = request.getPath(); if (!route.startsWith("/")) { route = "/" + route; } File contentRoot = server.getContentFolder(); ROUTES.refreshIfNeeded(contentRoot); JavaRouteRegistry.RouteLookupResult found = ROUTES.find(route); if (found == null) { return null; } long contentLm = ROUTES.currentContentLastModified(contentRoot); JavaPageCache.LoadedClass loaded = CACHE.getOrCompile(contentRoot, found.sourceFile(), contentLm); Class> clazz = loaded.clazz(); // Verify that the loaded class is actually routable. if (!WebPage.class.isAssignableFrom(clazz)) { return error(500, "Class has @Route but is not a WebPage: " + found.fqcn()); } Object instance = clazz.getDeclaredConstructor().newInstance(); WebPage page = (WebPage) instance; WebHasher hasher = (server instanceof WebServer ws) ? ws.getHasher() : null; if (hasher == null) { return error(500, "WebHasher missing on server instance."); } WebPageContext ctx = new WebPageContext(client, server, request, new RequestParams(request), hasher); return page.handle(ctx); } private static WebResponsePacket error(int code, String msg) { return new WebResponsePacket( code, "text/plain; charset=utf-8", HeaderMaps.mutable(), msg.getBytes(StandardCharsets.UTF_8) ); } }