package org.openautonomousconnection.webserver.runtime; import org.openautonomousconnection.protocol.packets.v1_0_1.beta.web.impl.resource.WebResourceRequestPacket; import org.openautonomousconnection.protocol.packets.v1_0_1.beta.web.impl.resource.WebResourceResponsePacket; 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 org.openautonomousconnection.webserver.utils.WebUrlUtil; import java.nio.charset.StandardCharsets; /** * Dispatches Java WebPages using {@code @Route} annotation (v1.0.1-BETA). */ 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 * @throws Exception on unexpected failures */ public static WebResourceResponsePacket dispatch( CustomConnectedClient client, ProtocolWebServer server, WebResourceRequestPacket request ) throws Exception { if (request == null || request.getUrl() == null) { return null; } String route = WebUrlUtil.extractPathAndQuery(request.getUrl()); if (route == null) return null; int q = route.indexOf('?'); if (q >= 0) route = route.substring(0, q); route = WebUrlUtil.normalizeRequestPath(route); java.io.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(); if (!WebPage.class.isAssignableFrom(clazz)) { return error(request, 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(request, 500, "WebHasher missing on server instance."); } WebPageContext ctx = new WebPageContext(client, server, request, new RequestParams(request), hasher); return page.handle(ctx); } private static WebResourceResponsePacket error(WebResourceRequestPacket req, int code, String msg) { byte[] body = (msg == null ? "" : msg).getBytes(StandardCharsets.UTF_8); // Mirror correlation from the incoming request if possible. org.openautonomousconnection.protocol.versions.v1_0_1.beta.WebPacketHeader in = (req != null && req.getHeader() != null) ? req.getHeader() : new org.openautonomousconnection.protocol.versions.v1_0_1.beta.WebPacketHeader( 0, 0, 0, 0, org.openautonomousconnection.protocol.versions.v1_0_1.beta.WebPacketFlags.RESOURCE, System.currentTimeMillis() ); org.openautonomousconnection.protocol.versions.v1_0_1.beta.WebPacketHeader out = new org.openautonomousconnection.protocol.versions.v1_0_1.beta.WebPacketHeader( in.getRequestId(), in.getTabId(), in.getPageId(), in.getFrameId(), in.getFlags() | org.openautonomousconnection.protocol.versions.v1_0_1.beta.WebPacketFlags.RESOURCE, System.currentTimeMillis() ); return new WebResourceResponsePacket( out, code, "text/plain; charset=utf-8", HeaderMaps.mutable(), body, null ); } }