2025-12-12 21:16:13 +01:00
|
|
|
package org.openautonomousconnection.webserver.runtime;
|
|
|
|
|
|
2026-01-18 18:41:59 +01:00
|
|
|
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebRequestPacket;
|
|
|
|
|
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebResponsePacket;
|
2026-02-01 19:28:45 +01:00
|
|
|
import org.openautonomousconnection.protocol.side.server.CustomConnectedClient;
|
2025-12-12 21:16:13 +01:00
|
|
|
import org.openautonomousconnection.protocol.side.web.ProtocolWebServer;
|
2026-01-19 14:23:53 +01:00
|
|
|
import org.openautonomousconnection.webserver.WebServer;
|
2025-12-12 21:16:13 +01:00
|
|
|
import org.openautonomousconnection.webserver.api.WebPage;
|
|
|
|
|
import org.openautonomousconnection.webserver.api.WebPageContext;
|
2026-02-08 21:40:23 +01:00
|
|
|
import org.openautonomousconnection.webserver.utils.HeaderMaps;
|
2026-01-19 14:23:53 +01:00
|
|
|
import org.openautonomousconnection.webserver.utils.RequestParams;
|
2026-02-06 18:03:32 +01:00
|
|
|
import org.openautonomousconnection.webserver.utils.WebHasher;
|
2025-12-12 21:16:13 +01:00
|
|
|
|
|
|
|
|
import java.io.File;
|
2026-01-19 14:23:53 +01:00
|
|
|
import java.nio.charset.StandardCharsets;
|
2025-12-12 21:16:13 +01:00
|
|
|
|
2026-01-19 14:23:53 +01:00
|
|
|
/**
|
2026-02-08 22:33:31 +01:00
|
|
|
* Dispatches Java WebPages using {@code @Route} annotation.
|
|
|
|
|
*
|
|
|
|
|
* <p>This dispatcher relies on {@link JavaRouteRegistry} for route-to-source mapping
|
|
|
|
|
* and uses {@link JavaPageCache} to compile/load classes from the content tree.
|
2026-01-19 14:23:53 +01:00
|
|
|
*/
|
2025-12-12 21:16:13 +01:00
|
|
|
public final class JavaPageDispatcher {
|
|
|
|
|
|
2026-01-19 14:23:53 +01:00
|
|
|
private static final JavaRouteRegistry ROUTES = new JavaRouteRegistry();
|
2026-02-08 22:33:31 +01:00
|
|
|
private static final JavaPageCache CACHE = new JavaPageCache();
|
2025-12-12 21:16:13 +01:00
|
|
|
|
2026-02-06 18:03:32 +01:00
|
|
|
private JavaPageDispatcher() {
|
|
|
|
|
}
|
2025-12-12 21:16:13 +01:00
|
|
|
|
2026-02-08 22:33:31 +01:00
|
|
|
/**
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
2025-12-12 21:16:13 +01:00
|
|
|
public static WebResponsePacket dispatch(
|
2026-02-01 19:28:45 +01:00
|
|
|
CustomConnectedClient client,
|
2025-12-12 21:16:13 +01:00
|
|
|
ProtocolWebServer server,
|
|
|
|
|
WebRequestPacket request
|
|
|
|
|
) throws Exception {
|
|
|
|
|
|
2026-02-08 22:33:31 +01:00
|
|
|
if (request == null || request.getPath() == null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2025-12-12 21:16:13 +01:00
|
|
|
|
2026-01-19 14:23:53 +01:00
|
|
|
String route = request.getPath();
|
2026-02-08 22:33:31 +01:00
|
|
|
if (!route.startsWith("/")) {
|
|
|
|
|
route = "/" + route;
|
|
|
|
|
}
|
2025-12-12 21:16:13 +01:00
|
|
|
|
2026-01-19 14:23:53 +01:00
|
|
|
File contentRoot = server.getContentFolder();
|
|
|
|
|
ROUTES.refreshIfNeeded(contentRoot);
|
2025-12-12 21:16:13 +01:00
|
|
|
|
2026-01-19 14:23:53 +01:00
|
|
|
JavaRouteRegistry.RouteLookupResult found = ROUTES.find(route);
|
|
|
|
|
if (found == null) {
|
2026-02-08 22:33:31 +01:00
|
|
|
return null;
|
2026-01-19 14:23:53 +01:00
|
|
|
}
|
|
|
|
|
|
2026-02-08 22:33:31 +01:00
|
|
|
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)) {
|
2026-01-19 14:23:53 +01:00
|
|
|
return error(500, "Class has @Route but is not a WebPage: " + found.fqcn());
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-12 21:16:13 +01:00
|
|
|
Object instance = clazz.getDeclaredConstructor().newInstance();
|
2026-02-08 22:33:31 +01:00
|
|
|
WebPage page = (WebPage) instance;
|
2025-12-12 21:16:13 +01:00
|
|
|
|
2026-01-19 14:23:53 +01:00
|
|
|
WebHasher hasher = (server instanceof WebServer ws) ? ws.getHasher() : null;
|
2026-02-08 22:33:31 +01:00
|
|
|
if (hasher == null) {
|
|
|
|
|
return error(500, "WebHasher missing on server instance.");
|
|
|
|
|
}
|
2026-01-19 14:23:53 +01:00
|
|
|
|
|
|
|
|
WebPageContext ctx = new WebPageContext(client, server, request, new RequestParams(request), hasher);
|
2025-12-12 21:16:13 +01:00
|
|
|
return page.handle(ctx);
|
|
|
|
|
}
|
2026-01-19 14:23:53 +01:00
|
|
|
|
|
|
|
|
private static WebResponsePacket error(int code, String msg) {
|
|
|
|
|
return new WebResponsePacket(
|
|
|
|
|
code,
|
|
|
|
|
"text/plain; charset=utf-8",
|
2026-02-08 21:40:23 +01:00
|
|
|
HeaderMaps.mutable(),
|
2026-01-19 14:23:53 +01:00
|
|
|
msg.getBytes(StandardCharsets.UTF_8)
|
|
|
|
|
);
|
|
|
|
|
}
|
2026-02-08 22:33:31 +01:00
|
|
|
}
|