From e4acfff035521ed87385e520eb71d5f18dc83195 Mon Sep 17 00:00:00 2001 From: Alan Richardson Date: Thu, 16 Jul 2026 18:31:00 +0100 Subject: [PATCH 1/2] Migrate HTTP server from Spark to Javalin --- .../challenge/ChallengeMain.java | 11 +- .../challenge/ChallengeRouteHandler.java | 23 +-- .../challenge/ChallengerAuthData.java | 2 +- .../challenge/IndexNowRouteHandler.java | 13 +- .../ChallengerApiResponseHook.java | 3 +- .../ChallengerInternalHTTPRequestHook.java | 13 +- .../ChallengerInternalHTTPResponseHook.java | 4 +- .../definitions/StatusCodeChallenges.java | 6 +- .../challengesrouting/AuthRoutes.java | 65 ++++--- .../ChallengerIpAddressTracker.java | 4 +- .../ChallengerTrackingRoutes.java | 39 ++--- .../challengesrouting/ChallengesRoutes.java | 24 ++- .../challengesrouting/HeartBeatRoutes.java | 22 +-- .../challengesrouting/XChallengerHeader.java | 18 +- .../challenge/gui/ChallengerWebGUI.java | 36 ++-- .../challenge/gui/MarkdownContentManager.java | 4 +- .../challenge/gui/PageNotFoundResponse.java | 4 +- .../HttpMessageLengthValidator.java} | 40 +++-- .../practicemodes/mirror/MirrorRoutes.java | 32 ++-- .../practicemodes/mirror/RequestMirror.java | 23 +-- .../SimpleApiCorsHeadersResponseHook.java | 2 +- .../simpleapi/SimpleApiRoutes.java | 13 +- .../simulation/SimulationRoutes.java | 31 ++-- .../challenge/IndexNowRouteHandlerTest.java | 27 +-- .../ChallengeApiModelRepositoryTest.java | 9 +- .../ChallengerApiResponseHookTest.java | 16 +- ...ChallengerInternalHttpRequestHookTest.java | 2 +- .../challengesrouting/AuthRoutesTest.java | 6 +- .../ChallengerTrackingRoutesTest.java | 6 +- .../ChallengesRoutesTest.java | 6 +- .../HeartBeatRoutesTest.java | 6 +- .../ChallengeCompleteTest.java | 4 +- .../MultiPlayerModeHookTest.java | 2 +- .../http/conditions/ConfigSetupTest.java | 2 +- .../http/defects/MultiUserDefectsTest.java | 2 +- .../httpclient/HttpClientRequestSender.java | 12 +- .../http/httpclient/HttpRequestSender.java | 6 +- .../practicemodes/MirrorModeTest.java | 8 +- .../practicemodes/SmulationModeTest.java | 6 +- .../simpleapi/SimpleApiCrudTest.java | 6 +- .../simpleapi/SimpleApiModeTest.java | 6 +- .../Environment.java | 8 +- .../{sparkstart => serverstart}/Port.java | 2 +- .../uirouting/UiPagesAreReachableTest.java | 6 +- challengerAuto/readme.md | 2 +- .../restassured/ChallengerAutoSmokeTest.java | 2 +- .../C008HeadTodos200Test.java | 6 +- .../C017PostUpdateTodosSuccess200Test.java | 4 +- .../C018PostUpdateTodosFail404Test.java | 2 +- .../C024OptionsTodos200Test.java | 2 +- .../C025GetTodosAcceptXml200Test.java | 2 +- .../C026GetTodosAcceptJson200Test.java | 2 +- .../C027GetTodosAcceptAnyJson200Test.java | 2 +- .../C028GetTodosAcceptXmlPref200Test.java | 2 +- .../C029GetTodosJsonNoAccept200Test.java | 2 +- .../restassured/api/ChallengesStatus.java | 2 +- .../restassured/api/RestAssuredBaseTest.java | 2 +- .../challenger/restassured/api/TodosApi.java | 2 +- .../ChallengerAutoConfig.java | 2 +- .../ChallengerAutoConfigTest.java | 2 +- .../ChallengerAutoLocalArgsTest.java | 2 +- .../ChallengerAutoRunProfiles.java | 2 +- .../ChallengerAutoRuntime.java | 2 +- .../ChallengerAutoRuntimeHarnessCheck.java | 2 +- .../Environment.java | 2 +- .../co/compendiumdev/serverstart}/Port.java | 2 +- .../BasicSimpleApiCrudCoverageTest.java | 2 +- .../simulator/SimulatorHttpTest.java | 4 +- checkstyle-project-fqn.xml | 36 ++-- .../EntityInstanceDraftValidator.java | 6 +- .../core/query/QueryFiltersBooleanTest.java | 3 +- pom.xml | 7 +- .../todolist/sqlite/application/Main.java | 4 +- .../todolist/application/Main.java | 4 +- .../Environment.java | 6 +- .../co/compendiumdev/serverstart}/Port.java | 2 +- .../uk/co/compendiumdev/version4/api/Api.java | 2 +- .../version4/projects/ProjectEntityTest.java | 2 +- .../Tasks_ProjectToTodosTest.java | 2 +- .../version4/todos/TodoEntityTest.java | 2 +- .../todolist/application/Main.java | 4 +- thingifier-crud-ui/pom.xml | 5 - .../crudui/ApiDocumentationPage.java | 26 +-- .../thingifier/crudui/CrudUiMain.java | 2 +- .../crudui/SwingProjectPathChooser.java | 6 +- .../{spark => javalin}/CrudUiApplication.java | 103 ++++++----- .../crudui/e2e/CrudUiTestServer.java | 2 +- thingifier/pom.xml | 6 +- thingifier/readme.md | 4 +- .../bootstrap/ThingifierServerBootstrap.java | 8 +- .../AdhocDocumentedHttpRouteConfigurer.java} | 17 +- .../httpserver/HaltRequestException.java | 20 +++ .../adapter/httpserver/HttpAfterHandler.java | 6 + .../adapter/httpserver/HttpBeforeHandler.java | 6 + .../HttpGenericExceptionRoutings.java | 20 +++ .../httpserver/HttpRouteDefinition.java | 26 +++ .../adapter/httpserver/HttpRouteHandler.java | 6 + .../adapter/httpserver/HttpRouteRegistry.java | 58 +++++++ .../adapter/httpserver/HttpRouteVerb.java | 12 ++ .../adapter/httpserver/HttpServerRequest.java | 57 ++++++ .../HttpServerRequestAsText.java} | 16 +- .../httpserver/HttpServerResponse.java | 27 +++ .../MainImplementation.java | 37 ++-- .../adapter/httpserver/ServerRoutes.java | 67 +++++++ .../SimpleHttpRouteCreator.java} | 29 ++-- .../ThingifierAutoDocGenRouting.java | 6 +- .../ThingifierHttpApiRoutings.java | 72 ++++---- ...ttpServerRequestToInternalHttpRequest.java | 40 +++++ ...pServerResponseToInternalHttpResponse.java | 26 +++ .../InternalHttpResponseToHttpServer.java} | 18 +- .../ClearDataPreHttpRequestHook.java} | 12 +- .../messagehooks/HttpRequestResponseHook.java | 13 ++ .../messagehooks/InternalHttpRequestHook.java | 2 +- .../InternalHttpResponseHook.java | 2 +- .../messagehooks/LogTheHttpRequestHook.java | 20 +++ .../messagehooks/LogTheResponseHook.java | 17 ++ .../HttpApiRequestResponseHandler.java} | 31 ++-- .../routehandlers/ShutdownRouteHandler.java | 4 +- .../adapter/javalin/JavalinHttpServer.java | 163 ++++++++++++++++++ .../adapter/javalin/JavalinServerRequest.java | 149 ++++++++++++++++ .../javalin/JavalinServerResponse.java | 85 +++++++++ .../SparkHttpGenericExceptionRoutings.java | 46 ----- .../SparkResponseToInternalHttpResponse.java | 26 --- .../SparkToInternalHttpRequest.java | 64 ------- .../messagehooks/LogTheResponseHook.java | 17 -- .../messagehooks/LogTheSparkRequestHook.java | 20 --- .../SparkRequestResponseHook.java | 13 -- .../api/http/HttpApiRequestValidator.java | 2 +- .../api/http/ThingifierHttpApi.java | 16 +- .../htmlgui/routing/DefaultGuiRoutings.java | 20 +-- .../api/http/UrlQueryParamParserTest.java | 2 +- ...hingifierHttpApiRequestStatusCodeTest.java | 2 +- .../ArchitectureBoundaryTest.java | 2 +- .../thingifier/application/Main.java | 6 +- todoManagerRestAuto/pom.xml | 2 +- .../co/compendiumdev/serverstart}/Port.java | 2 +- .../postmanreplication/Environment.java | 34 ++-- 137 files changed, 1444 insertions(+), 772 deletions(-) rename challenger/src/main/java/uk/co/compendiumdev/challenge/{spark/SparkMessageLengthValidator.java => httpserver/HttpMessageLengthValidator.java} (54%) rename challenger/src/test/java/uk/co/compendiumdev/{sparkstart => serverstart}/Environment.java (94%) rename challenger/src/test/java/uk/co/compendiumdev/{sparkstart => serverstart}/Port.java (97%) rename challengerAuto/src/test/java/uk/co/compendiumdev/{sparkstart => serverstart}/ChallengerAutoConfig.java (99%) rename challengerAuto/src/test/java/uk/co/compendiumdev/{sparkstart => serverstart}/ChallengerAutoConfigTest.java (99%) rename challengerAuto/src/test/java/uk/co/compendiumdev/{sparkstart => serverstart}/ChallengerAutoLocalArgsTest.java (98%) rename challengerAuto/src/test/java/uk/co/compendiumdev/{sparkstart => serverstart}/ChallengerAutoRunProfiles.java (98%) rename challengerAuto/src/test/java/uk/co/compendiumdev/{sparkstart => serverstart}/ChallengerAutoRuntime.java (99%) rename challengerAuto/src/test/java/uk/co/compendiumdev/{sparkstart => serverstart}/ChallengerAutoRuntimeHarnessCheck.java (98%) rename challengerAuto/src/test/java/uk/co/compendiumdev/{sparkstart => serverstart}/Environment.java (94%) rename {standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/sparkstart => challengerAuto/src/test/java/uk/co/compendiumdev/serverstart}/Port.java (97%) rename standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/{sparkstart => serverstart}/Environment.java (94%) rename {todoManagerRestAuto/src/test/java/uk/co/compendiumdev/sparkstart => standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/serverstart}/Port.java (97%) rename thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/adapter/{spark => javalin}/CrudUiApplication.java (59%) rename thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/{spark/AdhocDocumentedSparkRouteConfigurer.java => httpserver/AdhocDocumentedHttpRouteConfigurer.java} (74%) create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HaltRequestException.java create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpAfterHandler.java create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpBeforeHandler.java create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpGenericExceptionRoutings.java create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpRouteDefinition.java create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpRouteHandler.java create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpRouteRegistry.java create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpRouteVerb.java create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpServerRequest.java rename thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/{spark/SparkAsText.java => httpserver/HttpServerRequestAsText.java} (74%) create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpServerResponse.java rename thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/{spark => httpserver}/MainImplementation.java (90%) create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/ServerRoutes.java rename thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/{spark/SimpleSparkRouteCreator.java => httpserver/SimpleHttpRouteCreator.java} (85%) rename thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/{spark => httpserver}/ThingifierAutoDocGenRouting.java (94%) rename thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/{spark => httpserver}/ThingifierHttpApiRoutings.java (86%) create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/conversion/HttpServerRequestToInternalHttpRequest.java create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/conversion/HttpServerResponseToInternalHttpResponse.java rename thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/{spark/conversion/InternalHttpResponseToSpark.java => httpserver/conversion/InternalHttpResponseToHttpServer.java} (55%) rename thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/{spark/messagehooks/ClearDataPreSparkRequestHook.java => httpserver/messagehooks/ClearDataPreHttpRequestHook.java} (65%) create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/HttpRequestResponseHook.java rename thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/{spark => httpserver}/messagehooks/InternalHttpRequestHook.java (82%) rename thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/{spark => httpserver}/messagehooks/InternalHttpResponseHook.java (83%) create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/LogTheHttpRequestHook.java create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/LogTheResponseHook.java rename thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/{spark/routehandlers/SparkApiRequestResponseHandler.java => httpserver/routehandlers/HttpApiRequestResponseHandler.java} (68%) rename thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/{spark => httpserver}/routehandlers/ShutdownRouteHandler.java (89%) create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinHttpServer.java create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinServerRequest.java create mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinServerResponse.java delete mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/SparkHttpGenericExceptionRoutings.java delete mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/conversion/SparkResponseToInternalHttpResponse.java delete mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/conversion/SparkToInternalHttpRequest.java delete mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/LogTheResponseHook.java delete mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/LogTheSparkRequestHook.java delete mode 100644 thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/SparkRequestResponseHook.java rename {challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart => todoManagerRestAuto/src/test/java/uk/co/compendiumdev/serverstart}/Port.java (97%) diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengeMain.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengeMain.java index da97aa03..7ba1f04c 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengeMain.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengeMain.java @@ -5,13 +5,14 @@ import uk.co.compendiumdev.challenge.apimodel.ChallengeApiModel; import uk.co.compendiumdev.challenge.challengers.Challengers; import uk.co.compendiumdev.thingifier.Thingifier; -import uk.co.compendiumdev.thingifier.adapter.spark.MainImplementation; -import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierHttpApiRoutings; +import uk.co.compendiumdev.thingifier.adapter.httpserver.MainImplementation; +import uk.co.compendiumdev.thingifier.adapter.httpserver.ThingifierHttpApiRoutings; import uk.co.compendiumdev.thingifier.core.repository.ThingStoreProviderConfig; public class ChallengeMain { static ChallengeRouteHandler challenger; + static MainImplementation app; public static void main(String[] args) { @@ -19,7 +20,7 @@ public static void main(String[] args) { logger.info("Starting Challenger"); - MainImplementation app = new MainImplementation(); + app = new MainImplementation(); ThingStoreProviderConfig repositoryConfig = ThingStoreProviderConfig.fromArgs(args); logger.info("Using Thingifier repository {}", repositoryConfig.describe()); Thingifier thingifier = new ChallengeApiModel().get(repositoryConfig.createProvider()); @@ -125,6 +126,10 @@ public static void stop() { if (challenger != null) { challenger.close(); } + if (app != null) { + app.close(); + } challenger = null; + app = null; } } diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengeRouteHandler.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengeRouteHandler.java index dd86ddb1..f3afc12c 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengeRouteHandler.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengeRouteHandler.java @@ -10,7 +10,7 @@ import uk.co.compendiumdev.challenge.practicemodes.simpleapi.SimpleApiRoutes; import uk.co.compendiumdev.challenge.practicemodes.simulation.SimulationRoutes; import uk.co.compendiumdev.thingifier.Thingifier; -import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierHttpApiRoutings; +import uk.co.compendiumdev.thingifier.adapter.httpserver.ThingifierHttpApiRoutings; import uk.co.compendiumdev.thingifier.api.docgen.ThingifierApiDocumentationDefn; import uk.co.compendiumdev.thingifier.htmlgui.htmlgen.DefaultGUIHTML; @@ -130,20 +130,21 @@ public ChallengeRouteHandler configureRoutes() { return this; } - public void addHooks(final ThingifierHttpApiRoutings restServer) { + public void addHooks(final ThingifierHttpApiRoutings apiRoutings) { - // TODO: this is wrong - rethink this - we need SparkLevel, InternalHttp level (pre-post - // these hooks are registered at a spark before and after level so run on every request, - // regardless of thingifier used - this is wrong - restServer.registerInternalHttpResponseHook( + // TODO: these internal HTTP hooks are registered through server-level before/after hooks. + // They can run for every HTTP request handled by the server, not just requests for this + // Thingifier API routing. Prefer route-scoped internal HTTP hooks or move this behavior + // into the API bridge boundary when it only applies to this Thingifier. + apiRoutings.registerInternalHttpResponseHook( new ChallengerInternalHTTPResponseHook(challengers)); - restServer.registerInternalHttpRequestHook( + apiRoutings.registerInternalHttpRequestHook( new ChallengerInternalHTTPRequestHook(challengers)); - // add hooks at the API bridge pre and post level so they only work in the specific - // thingifier - restServer.registerHttpApiRequestHook(new ChallengerApiRequestHook(challengers)); - restServer.registerHttpApiResponseHook( + // These hooks run inside the Thingifier API bridge for this routing instance, so they are + // scoped to this Thingifier's API request/response processing. + apiRoutings.registerHttpApiRequestHook(new ChallengerApiRequestHook(challengers)); + apiRoutings.registerHttpApiResponseHook( new ChallengerApiResponseHook(challengers, thingifier)); } diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengerAuthData.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengerAuthData.java index d729ea8c..5d79a2f5 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengerAuthData.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengerAuthData.java @@ -24,7 +24,7 @@ public ChallengerAuthData(Collection definedChallenges) { this.xChallenger = UUID.randomUUID().toString(); this.xAuthToken = UUID.randomUUID().toString(); this.expiresin = 600000; // 10 * 60 * 1000; // 10 minutes - this.extratime = 30000; // 30 * 1000 - extra time on each request + this.extratime = 30000; // 30 * 1000 - extra time on each HttpServerRequest touch(); this.secretNote = ""; resetChallengesStatus(definedChallenges); diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/IndexNowRouteHandler.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/IndexNowRouteHandler.java index cc2cc716..a3816c4b 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/IndexNowRouteHandler.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/IndexNowRouteHandler.java @@ -3,8 +3,8 @@ import java.util.function.BiConsumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import spark.Route; -import spark.Spark; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpRouteHandler; +import uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes; public class IndexNowRouteHandler { @@ -15,16 +15,19 @@ public class IndexNowRouteHandler { private final String keyLocation; private final String key; - private final BiConsumer getRouteRegistrar; + private final BiConsumer getRouteRegistrar; public IndexNowRouteHandler() { - this(System.getenv(INDEX_NOW_KEY_LOCATION), System.getenv(INDEX_NOW_KEY), Spark::get); + this( + System.getenv(INDEX_NOW_KEY_LOCATION), + System.getenv(INDEX_NOW_KEY), + ServerRoutes::get); } IndexNowRouteHandler( final String keyLocation, final String key, - final BiConsumer getRouteRegistrar) { + final BiConsumer getRouteRegistrar) { this.keyLocation = normalize(keyLocation); this.key = normalize(key); this.getRouteRegistrar = getRouteRegistrar; diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerApiResponseHook.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerApiResponseHook.java index 4a85730b..b9ec358e 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerApiResponseHook.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerApiResponseHook.java @@ -253,7 +253,8 @@ && collate(response.apiResponse().getErrorMessages()) && request.getPath().matches("todos") && response.getStatusCode() == 413 && collate(response.apiResponse().getErrorMessages()) - .contains("Error: Request body too large, max allowed is 5000 bytes")) { + .toLowerCase() + .contains("request body too large")) { challengers.pass(challenger, CHALLENGE.POST_TODOS_TOO_LONG_PAYLOAD_SIZE); } diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerInternalHTTPRequestHook.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerInternalHTTPRequestHook.java index 04942495..57241614 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerInternalHTTPRequestHook.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerInternalHTTPRequestHook.java @@ -6,13 +6,13 @@ import uk.co.compendiumdev.challenge.CHALLENGE; import uk.co.compendiumdev.challenge.ChallengerAuthData; import uk.co.compendiumdev.challenge.challengers.Challengers; +import uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks.InternalHttpRequestHook; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpMethod; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpRequest; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpResponse; -import uk.co.compendiumdev.thingifier.adapter.spark.messagehooks.InternalHttpRequestHook; /* - This is an Internal HTTP Request because it covers functionality for endpoints that do not + This is an Internal HTTP request because it covers functionality for endpoints that do not go through the normal API process i.e. heartbeat, challenges, challenger */ public class ChallengerInternalHTTPRequestHook implements InternalHttpRequestHook { @@ -71,20 +71,17 @@ public InternalHttpResponse run(final InternalHttpRequest request) { challengers.pass(challenger, CHALLENGE.TRACE_HEARTBEAT_501); } - if (method == InternalHttpMethod.POST - && path.equals("heartbeat") + if (path.equals("heartbeat") && request.getHeader("x-http-method-override").equalsIgnoreCase("patch")) { challengers.pass(challenger, CHALLENGE.OVERRIDE_PATCH_HEARTBEAT_500); } - if (method == InternalHttpMethod.POST - && path.equals("heartbeat") + if (path.equals("heartbeat") && request.getHeader("x-http-method-override").equalsIgnoreCase("delete")) { challengers.pass(challenger, CHALLENGE.OVERRIDE_DELETE_HEARTBEAT_405); } - if (method == InternalHttpMethod.POST - && path.equals("heartbeat") + if (path.equals("heartbeat") && request.getHeader("x-http-method-override").equalsIgnoreCase("trace")) { challengers.pass(challenger, CHALLENGE.OVERRIDE_TRACE_HEARTBEAT_501); } diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerInternalHTTPResponseHook.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerInternalHTTPResponseHook.java index aafb0b8a..e8653432 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerInternalHTTPResponseHook.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerInternalHTTPResponseHook.java @@ -8,9 +8,9 @@ import uk.co.compendiumdev.challenge.ChallengerState; import uk.co.compendiumdev.challenge.challengers.Challengers; import uk.co.compendiumdev.challenge.challengesrouting.XChallengerHeader; +import uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks.InternalHttpResponseHook; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpRequest; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpResponse; -import uk.co.compendiumdev.thingifier.adapter.spark.messagehooks.InternalHttpResponseHook; import uk.co.compendiumdev.thingifier.api.http.headers.headerparser.BearerAuthHeaderParser; public class ChallengerInternalHTTPResponseHook implements InternalHttpResponseHook { @@ -178,7 +178,7 @@ public void run(final InternalHttpRequest request, final InternalHttpResponse re } } - // No endpoint defined so this 404 created by Spark routing + // No endpoint defined so this 404 created by HTTP server routing if (request.getVerb() == GET && request.getPath().contentEquals("todo") && response.getStatusCode() == 404) { diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/challenges/definitions/StatusCodeChallenges.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/challenges/definitions/StatusCodeChallenges.java index 97ac60a0..2cbfe445 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/challenges/definitions/StatusCodeChallenges.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/challenges/definitions/StatusCodeChallenges.java @@ -79,7 +79,7 @@ public static ChallengeDefinitionData overridePostToPatchFor500(int challengeOrd "POST /heartbeat as PATCH (500)", "Issue a POST request on the `/heartbeat` end point and receive 500 when you override the Method Verb to a PATCH"); - aChallenge.addHint("Use a normal POST Request, but add an X-HTTP-Method-Override header"); + aChallenge.addHint("Use a normal POST request, but add an X-HTTP-Method-Override header"); aChallenge.addSolutionLink( "Add a header 'X-HTTP-Method-Override: PATCH' to a POST /heartbeat request", @@ -100,7 +100,7 @@ public static ChallengeDefinitionData overridePostToDeleteFor405(int challengeOr "POST /heartbeat as DELETE (405)", "Issue a POST request on the `/heartbeat` end point and receive 405 when you override the Method Verb to a DELETE"); - aChallenge.addHint("Use a normal POST Request, but add an X-HTTP-Method-Override header"); + aChallenge.addHint("Use a normal POST request, but add an X-HTTP-Method-Override header"); aChallenge.addSolutionLink( "Add a header 'X-HTTP-Method-Override: DELETE' to a POST /heartbeat request", @@ -121,7 +121,7 @@ public static ChallengeDefinitionData overridePostToTraceFor501(int challengeOrd ChallengeRenderer.renderChallengeNumber(challengeOrder), "POST /heartbeat as Trace (501)", "Issue a POST request on the `/heartbeat` end point and receive 501 (Not Implemented) when you override the Method Verb to a TRACE"); - aChallenge.addHint("Use a normal POST Request, but add an X-HTTP-Method-Override header"); + aChallenge.addHint("Use a normal POST request, but add an X-HTTP-Method-Override header"); aChallenge.addSolutionLink( "Add a header 'X-HTTP-Method-Override: TRACE' to a POST /heartbeat request", diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/AuthRoutes.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/AuthRoutes.java index 350009cd..f42fd933 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/AuthRoutes.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/AuthRoutes.java @@ -1,18 +1,18 @@ package uk.co.compendiumdev.challenge.challengesrouting; -import static spark.Spark.*; +import static uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes.*; import java.util.List; -import spark.Route; import uk.co.compendiumdev.challenge.ChallengerAuthData; import uk.co.compendiumdev.challenge.challengers.Challengers; import uk.co.compendiumdev.thingifier.Thingifier; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpRouteHandler; +import uk.co.compendiumdev.thingifier.adapter.httpserver.SimpleHttpRouteCreator; +import uk.co.compendiumdev.thingifier.adapter.httpserver.conversion.HttpServerRequestToInternalHttpRequest; +import uk.co.compendiumdev.thingifier.adapter.httpserver.conversion.InternalHttpResponseToHttpServer; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpRequest; import uk.co.compendiumdev.thingifier.adapter.internalhttp.conversion.HttpApiResponseToInternalHttpResponse; import uk.co.compendiumdev.thingifier.adapter.internalhttp.conversion.InternalHttpRequestToHttpApiRequest; -import uk.co.compendiumdev.thingifier.adapter.spark.SimpleSparkRouteCreator; -import uk.co.compendiumdev.thingifier.adapter.spark.conversion.InternalHttpResponseToSpark; -import uk.co.compendiumdev.thingifier.adapter.spark.conversion.SparkToInternalHttpRequest; import uk.co.compendiumdev.thingifier.api.docgen.RoutingDefinition; import uk.co.compendiumdev.thingifier.api.docgen.RoutingStatus; import uk.co.compendiumdev.thingifier.api.docgen.RoutingVerb; @@ -61,7 +61,7 @@ public void configure( this.httpApi = new ThingifierHttpApi(this.secretNoteStore); this.jsonThing = new JsonThing(this.secretNoteStore.apiConfig().jsonOutput()); - SimpleSparkRouteCreator.addHandler( + SimpleHttpRouteCreator.addHandler( "/secret/token", "options", (request, result) -> { @@ -71,8 +71,8 @@ public void configure( return ""; }); - // TODO: this all feels too tightly coupled to SparkJava we should have our own routing - // internally that spark delegates too + // TODO: this still feels tightly coupled to HTTP routing; route handling should delegate + // to an internal auth use case. // POST /secret/token with basic auth to get a secret/token to use as X-AUTH-TOKEN header // todo: or {username, password} payload @@ -80,19 +80,17 @@ public void configure( "/secret/token", (request, result) -> { BasicAuthHeaderParser basicAuth = - new BasicAuthHeaderParser(request.headers("Authorization")); + new BasicAuthHeaderParser(request.header("Authorization")); // admin/password as default username:password if (!basicAuth.matches("admin", "password")) { - result.raw() - .setHeader( - "WWW-Authenticate", "Basic realm=\"User Visible Realm\""); + result.header("WWW-Authenticate", "Basic realm=\"User Visible Realm\""); result.status(401); return ""; } ChallengerAuthData challenger = - challengers.getChallenger(request.headers("X-CHALLENGER")); + challengers.getChallenger(request.header("X-CHALLENGER")); if (challenger == null) { result.status(401); @@ -101,13 +99,12 @@ public void configure( } // if no header X-AUTH-TOKEN then grant one - result.raw().setHeader("X-AUTH-TOKEN", challenger.getXAuthToken()); + result.header("X-AUTH-TOKEN", challenger.getXAuthToken()); result.status(201); return ""; }); - SimpleSparkRouteCreator.routeStatusWhenNot( - 405, "/secret/token", List.of("post", "options")); + SimpleHttpRouteCreator.routeStatusWhenNot(405, "/secret/token", List.of("post", "options")); apiDefn.addRouteToDocumentation( new RoutingDefinition( @@ -127,7 +124,7 @@ public void configure( // auth token which does not match the session will receive a 401 // header X-AUTH-TOKEN: token given - if token not found (then) 401 - SimpleSparkRouteCreator.addHandler( + SimpleHttpRouteCreator.addHandler( "/secret/note", "options", (request, result) -> { @@ -137,15 +134,15 @@ public void configure( return ""; }); - Route getSecretNote = + HttpRouteHandler getSecretNote = (request, result) -> { - String authToken = request.headers("X-AUTH-TOKEN"); - final String authorization = request.headers("Authorization"); + String authToken = request.header("X-AUTH-TOKEN"); + final String authorization = request.header("Authorization"); result.header("Content-Type", "application/json"); ChallengerAuthData challenger = - challengers.getChallenger(request.headers("X-CHALLENGER")); + challengers.getChallenger(request.header("X-CHALLENGER")); if (challenger == null) { result.status(401); @@ -173,7 +170,7 @@ public void configure( } AcceptHeaderParser acceptHeaderParser = - new AcceptHeaderParser(request.headers("ACCEPT")); + new AcceptHeaderParser(request.header("ACCEPT")); if (!acceptHeaderParser.missingAcceptHeader() && !acceptHeaderParser.isSupportedHeader()) { result.status(406); @@ -181,7 +178,7 @@ public void configure( } final InternalHttpRequest internalRequest = - SparkToInternalHttpRequest.convert(request); + HttpServerRequestToInternalHttpRequest.convert(request); final HttpApiRequest myRequest = InternalHttpRequestToHttpApiRequest.convert(internalRequest); @@ -198,10 +195,10 @@ public void configure( jsonThing, this.secretNoteStore.apiConfig()); - return InternalHttpResponseToSpark.convert( + return InternalHttpResponseToHttpServer.convert( HttpApiResponseToInternalHttpResponse.convert(httpApiResponse), result); - // return resultBasedOnAcceptHeader(result, request.headers("ACCEPT"), + // return resultBasedOnAcceptHeader(result, request.header("ACCEPT"), // challenger.getNote()); }; @@ -232,11 +229,11 @@ public void configure( post( "/secret/note", (request, result) -> { - final String authorization = request.headers("Authorization"); - String authToken = request.headers("X-AUTH-TOKEN"); + final String authorization = request.header("Authorization"); + String authToken = request.header("X-AUTH-TOKEN"); AcceptHeaderParser acceptHeaderParser = - new AcceptHeaderParser(request.headers("ACCEPT")); + new AcceptHeaderParser(request.header("ACCEPT")); if (!acceptHeaderParser.missingAcceptHeader() && !acceptHeaderParser.isSupportedHeader()) { result.status(406); @@ -244,7 +241,7 @@ public void configure( } ContentTypeHeaderParser contentTypeParser = - new ContentTypeHeaderParser(request.headers("CONTENT-TYPE")); + new ContentTypeHeaderParser(request.header("CONTENT-TYPE")); if (!contentTypeParser.isJSON() && !contentTypeParser.isXML()) { result.status(415); return ""; @@ -254,7 +251,7 @@ public void configure( // associated // challenger ChallengerAuthData challenger = - challengers.getChallenger(request.headers("X-CHALLENGER")); + challengers.getChallenger(request.header("X-CHALLENGER")); if (challenger == null) { result.status(401); @@ -262,7 +259,7 @@ public void configure( return ""; } - result.raw().setHeader("X-CHALLENGER", challenger.getXChallenger()); + result.header("X-CHALLENGER", challenger.getXChallenger()); // set content-type header for error responses if (acceptHeaderParser.hasAPreferenceForXml()) { result.header("Content-Type", "application/xml"); @@ -296,7 +293,7 @@ public void configure( } final InternalHttpRequest internalRequest = - SparkToInternalHttpRequest.convert(request); + HttpServerRequestToInternalHttpRequest.convert(request); final HttpApiRequest myRequest = InternalHttpRequestToHttpApiRequest.convert(internalRequest); HttpApiResponse httpApiResponse = @@ -357,11 +354,11 @@ public void configure( this.secretNoteStore.apiConfig()); } - return InternalHttpResponseToSpark.convert( + return InternalHttpResponseToHttpServer.convert( HttpApiResponseToInternalHttpResponse.convert(httpApiResponse), result); }); - SimpleSparkRouteCreator.routeStatusWhenNot( + SimpleHttpRouteCreator.routeStatusWhenNot( 405, "/secret/note", List.of("get", "post", "head", "options")); apiDefn.addRouteToDocumentation( diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengerIpAddressTracker.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengerIpAddressTracker.java index 8884d5bc..8b13cb7f 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengerIpAddressTracker.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengerIpAddressTracker.java @@ -46,7 +46,9 @@ public void purgeEmptyIpAddresses(Set existingChallengerGuids) { public boolean hasLimitBeenReachedFor(String ip) { - if (!addressLimitingOn) return false; + if (!addressLimitingOn) { + return false; + } if (countFor(ip) < maxChallengers) { return false; diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengerTrackingRoutes.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengerTrackingRoutes.java index 8e5aaeb3..93557722 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengerTrackingRoutes.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengerTrackingRoutes.java @@ -1,16 +1,16 @@ package uk.co.compendiumdev.challenge.challengesrouting; -import static spark.Spark.*; +import static uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes.*; import com.google.gson.Gson; import java.util.*; -import spark.Route; import uk.co.compendiumdev.challenge.ChallengerAuthData; import uk.co.compendiumdev.challenge.challengers.Challengers; import uk.co.compendiumdev.challenge.challenges.ChallengeDefinitions; import uk.co.compendiumdev.challenge.persistence.PersistenceLayer; import uk.co.compendiumdev.thingifier.Thingifier; -import uk.co.compendiumdev.thingifier.adapter.spark.SimpleSparkRouteCreator; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpRouteHandler; +import uk.co.compendiumdev.thingifier.adapter.httpserver.SimpleHttpRouteCreator; import uk.co.compendiumdev.thingifier.api.docgen.*; import uk.co.compendiumdev.thingifier.api.response.ApiResponseAsJson; import uk.co.compendiumdev.thingifier.api.response.ApiResponseError; @@ -35,7 +35,7 @@ public void configure( ChallengerIpAddressTracker ipAddressTracker = new ChallengerIpAddressTracker(MAX_CHALLENGERS_PER_IP, false); - Route getChallengerId = + HttpRouteHandler getChallengerId = (request, result) -> { ChallengerAuthData challenger = null; String xChallengerGuid = request.params("id"); @@ -60,7 +60,7 @@ public void configure( return ""; }; - SimpleSparkRouteCreator.addHandler( + SimpleHttpRouteCreator.addHandler( "/challenger/:id", "options", (request, result) -> { @@ -70,7 +70,7 @@ public void configure( return ""; }); - SimpleSparkRouteCreator.routeStatusWhenNot( + SimpleHttpRouteCreator.routeStatusWhenNot( 405, "/challenger/:id", List.of("get", "put", "head", "options")); // refresh challenger to avoid purging @@ -176,7 +176,7 @@ public void configure( result.header("content-type", "application/json"); result.header("X-CHALLENGER", xChallengerGuid); return ApiResponseError.asAppropriate( - request.headers("accept"), + request.header("accept"), "Attempted to create too many challengers, wait and try again later."); } @@ -216,7 +216,7 @@ public void configure( */ - SimpleSparkRouteCreator.addHandler( + SimpleHttpRouteCreator.addHandler( "/challenger", "options", (request, result) -> { @@ -233,12 +233,12 @@ public void configure( if (single_player_mode) { XChallengerHeader.setResultHeaderBasedOnChallenger( result, challengers.SINGLE_PLAYER.getXChallenger()); - result.raw().setHeader("Location", "/gui/challenges"); + result.header("Location", "/gui/challenges"); result.status(201); return ""; } - String xChallengerGuid = request.headers("X-CHALLENGER"); + String xChallengerGuid = request.header("X-CHALLENGER"); if (xChallengerGuid == null || xChallengerGuid.trim().isEmpty()) { // create a new challenger with a database final ChallengerAuthData challenger = challengers.createNewChallenger(); @@ -246,10 +246,7 @@ public void configure( thingifier.ensureCreatedAndPopulatedInstanceDatabaseNamed( challenger.getXChallenger()); XChallengerHeader.setResultHeaderBasedOnChallenger(result, challenger); - result.raw() - .setHeader( - "Location", - "/gui/challenges/" + challenger.getXChallenger()); + result.header("Location", "/gui/challenges/" + challenger.getXChallenger()); result.status(201); } else { ChallengerAuthData challenger = challengers.getChallenger(xChallengerGuid); @@ -264,10 +261,8 @@ public void configure( challenger.getXChallenger()); // if X-CHALLENGER header exists, and has a valid UUID, and UUID exists, // then return 200 - result.raw() - .setHeader( - "Location", - "/gui/challenges/" + challenger.getXChallenger()); + result.header( + "Location", "/gui/challenges/" + challenger.getXChallenger()); result.status(200); } XChallengerHeader.setResultHeaderBasedOnChallenger(result, challenger); @@ -284,7 +279,7 @@ public void configure( .addDocumentation("Create a challenger using the X-CHALLENGER guid header.") .addPossibleStatuses(200, 400, 405)); - SimpleSparkRouteCreator.routeStatusWhenNot(405, "/challenger", List.of("post", "options")); + SimpleHttpRouteCreator.routeStatusWhenNot(405, "/challenger", List.of("post", "options")); /* The todos restore endpoint @@ -302,7 +297,7 @@ public void configure( .addPossibleStatuses(200, 400, 404) .addRequestUrlParam(guidField)); - Route getChallengerDatabaseId = + HttpRouteHandler getChallengerDatabaseId = (request, result) -> { ChallengerAuthData challenger; @@ -346,7 +341,7 @@ public void configure( } }; - SimpleSparkRouteCreator.addHandler( + SimpleHttpRouteCreator.addHandler( "/challenger/database/:id", "options", (request, result) -> { @@ -356,7 +351,7 @@ public void configure( return ""; }); - SimpleSparkRouteCreator.routeStatusWhenNot( + SimpleHttpRouteCreator.routeStatusWhenNot( 405, "/challenger/database/:id", List.of("get", "put", "head", "options")); // add a GET challenger/database/:id in the proper database format diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengesRoutes.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengesRoutes.java index 6a455576..80ce65b8 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengesRoutes.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengesRoutes.java @@ -1,15 +1,15 @@ package uk.co.compendiumdev.challenge.challengesrouting; -import static spark.Spark.*; +import static uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes.*; import java.util.List; import uk.co.compendiumdev.challenge.ChallengerAuthData; import uk.co.compendiumdev.challenge.apimodel.ChallengeThingifier; import uk.co.compendiumdev.challenge.challengers.Challengers; import uk.co.compendiumdev.challenge.challenges.ChallengeDefinitions; -import uk.co.compendiumdev.thingifier.adapter.spark.AdhocDocumentedSparkRouteConfigurer; -import uk.co.compendiumdev.thingifier.adapter.spark.SimpleSparkRouteCreator; -import uk.co.compendiumdev.thingifier.adapter.spark.routehandlers.SparkApiRequestResponseHandler; +import uk.co.compendiumdev.thingifier.adapter.httpserver.AdhocDocumentedHttpRouteConfigurer; +import uk.co.compendiumdev.thingifier.adapter.httpserver.SimpleHttpRouteCreator; +import uk.co.compendiumdev.thingifier.adapter.httpserver.routehandlers.HttpApiRequestResponseHandler; import uk.co.compendiumdev.thingifier.api.docgen.RoutingDefinition; import uk.co.compendiumdev.thingifier.api.docgen.RoutingStatus; import uk.co.compendiumdev.thingifier.api.docgen.RoutingVerb; @@ -31,17 +31,15 @@ public void configure( "/challenges", (request, result) -> { ChallengerAuthData challenger = - challengers.getChallenger(request.headers("X-CHALLENGER")); + challengers.getChallenger(request.header("X-CHALLENGER")); if (!single_player_mode) { if (challenger != null) { - result.raw() - .setHeader( - "Location", - "/gui/challenges/" + challenger.getXChallenger()); + result.header( + "Location", "/gui/challenges/" + challenger.getXChallenger()); } } else { - result.raw().setHeader("Location", "/gui/challenges"); + result.header("Location", "/gui/challenges"); } // Todo: use the cloneThingifierWithNewData here and simplify the @@ -50,7 +48,7 @@ public void configure( final EntityDefinition challengeDefn = challengeThingifier.challengeDefn; challengeThingifier.populateThingifierFrom(challengeDefinitions); - return new SparkApiRequestResponseHandler( + return new HttpApiRequestResponseHandler( request, result, challengeThingifier.challengeThingifier) .usingHandler( (anHttpApiRequest) -> { @@ -92,7 +90,7 @@ public void configure( // TODO: because these hardcode contentType and ignore Accept there should be a light weight // wrapper available - new AdhocDocumentedSparkRouteConfigurer(apiDefn) + new AdhocDocumentedHttpRouteConfigurer(apiDefn) .add( "/challenges", RoutingVerb.HEAD, @@ -115,7 +113,7 @@ public void configure( return ""; })); - SimpleSparkRouteCreator.routeStatusWhenNot( + SimpleHttpRouteCreator.routeStatusWhenNot( 405, "/challenges", List.of("get", "head", "options")); } } diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/HeartBeatRoutes.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/HeartBeatRoutes.java index 42a31d16..78ff63e9 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/HeartBeatRoutes.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/HeartBeatRoutes.java @@ -1,8 +1,8 @@ package uk.co.compendiumdev.challenge.challengesrouting; import java.util.List; -import uk.co.compendiumdev.thingifier.adapter.spark.AdhocDocumentedSparkRouteConfigurer; -import uk.co.compendiumdev.thingifier.adapter.spark.SimpleSparkRouteCreator; +import uk.co.compendiumdev.thingifier.adapter.httpserver.AdhocDocumentedHttpRouteConfigurer; +import uk.co.compendiumdev.thingifier.adapter.httpserver.SimpleHttpRouteCreator; import uk.co.compendiumdev.thingifier.api.docgen.RoutingVerb; import uk.co.compendiumdev.thingifier.api.docgen.ThingifierApiDocumentationDefn; @@ -12,14 +12,14 @@ public void configure(final ThingifierApiDocumentationDefn apiDefn) { String endpoint = "/heartbeat"; - final AdhocDocumentedSparkRouteConfigurer sparkRouteConfig = - new AdhocDocumentedSparkRouteConfigurer(apiDefn); + final AdhocDocumentedHttpRouteConfigurer routeConfig = + new AdhocDocumentedHttpRouteConfigurer(apiDefn); - sparkRouteConfig.add(endpoint, RoutingVerb.GET, 204, "Is the server running? YES 204"); + routeConfig.add(endpoint, RoutingVerb.GET, 204, "Is the server running? YES 204"); - sparkRouteConfig.add(endpoint, RoutingVerb.HEAD, 204, "Headers for heartbeat endpoint"); + routeConfig.add(endpoint, RoutingVerb.HEAD, 204, "Headers for heartbeat endpoint"); - sparkRouteConfig.add( + routeConfig.add( endpoint, RoutingVerb.OPTIONS, 204, @@ -31,9 +31,9 @@ public void configure(final ThingifierApiDocumentationDefn apiDefn) { }); // undocumented handlers - SimpleSparkRouteCreator simpleSparkRouteCreator = new SimpleSparkRouteCreator(endpoint); - simpleSparkRouteCreator.status(405, true, List.of("post", "delete", "put")); - simpleSparkRouteCreator.status(500, true, List.of("patch")); - simpleSparkRouteCreator.status(501, true, List.of("trace")); + SimpleHttpRouteCreator SimpleHttpRouteCreator = new SimpleHttpRouteCreator(endpoint); + SimpleHttpRouteCreator.status(405, true, List.of("post", "delete", "put")); + SimpleHttpRouteCreator.status(500, true, List.of("patch")); + SimpleHttpRouteCreator.status(501, true, List.of("trace")); } } diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/XChallengerHeader.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/XChallengerHeader.java index 85aec839..025cd40f 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/XChallengerHeader.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/XChallengerHeader.java @@ -1,7 +1,7 @@ package uk.co.compendiumdev.challenge.challengesrouting; -import spark.Response; import uk.co.compendiumdev.challenge.ChallengerAuthData; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerResponse; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpResponse; public class XChallengerHeader { @@ -10,32 +10,32 @@ public class XChallengerHeader { "UNKNOWN CHALLENGER - Challenger not found"; public static void setResultHeaderBasedOnChallenger( - final Response result, final ChallengerAuthData challenger) { + final HttpServerResponse result, final ChallengerAuthData challenger) { if (result == null) { return; } if (challenger == null) { - result.raw().setHeader("X-CHALLENGER", NOT_FOUND_ERROR_MESSAGE); - // result.raw().setHeader("X-CHALLENGER", "Challenger not recognised"); + result.header("X-CHALLENGER", NOT_FOUND_ERROR_MESSAGE); + // result.header("X-CHALLENGER", "Challenger not recognised"); } else { - result.raw().setHeader("X-CHALLENGER", challenger.getXChallenger()); + result.header("X-CHALLENGER", challenger.getXChallenger()); } } public static void setResultHeaderBasedOnChallenger( - final Response result, final String challengerGUID) { + final HttpServerResponse result, final String challengerGUID) { if (result == null) { return; } if (challengerGUID == null || challengerGUID.trim().length() == 0) { - result.raw().setHeader("X-CHALLENGER", NOT_FOUND_ERROR_MESSAGE); - // result.raw().setHeader("X-CHALLENGER", "Challenger not recognised"); + result.header("X-CHALLENGER", NOT_FOUND_ERROR_MESSAGE); + // result.header("X-CHALLENGER", "Challenger not recognised"); } else { - result.raw().setHeader("X-CHALLENGER", challengerGUID); + result.header("X-CHALLENGER", challengerGUID); } } diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/gui/ChallengerWebGUI.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/gui/ChallengerWebGUI.java index e9b8f0c3..7fc491fb 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/gui/ChallengerWebGUI.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/gui/ChallengerWebGUI.java @@ -1,18 +1,18 @@ package uk.co.compendiumdev.challenge.gui; -import static spark.Spark.*; +import static uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes.*; import java.time.LocalDate; import java.util.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import spark.Request; import uk.co.compendiumdev.challenge.CHALLENGE; import uk.co.compendiumdev.challenge.ChallengerAuthData; import uk.co.compendiumdev.challenge.challengers.Challengers; import uk.co.compendiumdev.challenge.challenges.*; import uk.co.compendiumdev.challenge.persistence.PersistenceLayer; import uk.co.compendiumdev.challenge.persistence.PersistenceResponse; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerRequest; import uk.co.compendiumdev.thingifier.core.EntityRelModel; import uk.co.compendiumdev.thingifier.htmlgui.htmlgen.DefaultGUIHTML; @@ -180,7 +180,7 @@ function setMenuNavBasedOnUrl(){ // request.url().startsWith("https://apichallenges.herokuapp.com") // ) { // // and it is a browser request - // if (request.headers("accept").contains("text/html")) { + // if (request.header("accept").contains("text/html")) { // // then redirect // response.header("location", // "https://apichallenges.eviltester.com" + request.uri()); @@ -215,9 +215,9 @@ function setMenuNavBasedOnUrl(){ getMarkdownParamsFromRequest(request)); response.body(responseBody); response.type("text/html"); - if (response.raw().containsHeader("x-robots-tag")) { + if (response.containsHeader("x-robots-tag")) { // we want it indexed because it is content - response.raw().setHeader("x-robots-tag", "all"); + response.header("x-robots-tag", "all"); } response.status(200); } catch (IllegalArgumentException e) { @@ -236,9 +236,9 @@ function setMenuNavBasedOnUrl(){ request.pathInfo(), getMarkdownParamsFromRequest(request)); response.type("text/html"); - if (response.raw().containsHeader("x-robots-tag")) { + if (response.containsHeader("x-robots-tag")) { // we want it indexed because it is content - response.raw().setHeader("x-robots-tag", "all"); + response.header("x-robots-tag", "all"); } response.status(200); } catch (IllegalArgumentException e) { @@ -298,9 +298,9 @@ function setMenuNavBasedOnUrl(){ "site", "/index", getMarkdownParamsFromRequest(request)); response.body(responseBody); response.type("text/html"); - if (response.raw().containsHeader("x-robots-tag")) { + if (response.containsHeader("x-robots-tag")) { // we want it indexed because it is content - response.raw().setHeader("x-robots-tag", "all"); + response.header("x-robots-tag", "all"); } response.status(200); return ""; @@ -311,9 +311,9 @@ function setMenuNavBasedOnUrl(){ contentManager.getHtmlVersionOfMarkdownContent( "site", "/index", getMarkdownParamsFromRequest(request)); response.type("text/html"); - if (response.raw().containsHeader("x-robots-tag")) { + if (response.containsHeader("x-robots-tag")) { // we want it indexed because it is content - response.raw().setHeader("x-robots-tag", "all"); + response.header("x-robots-tag", "all"); } response.status(200); return ""; @@ -416,7 +416,7 @@ function setMenuNavBasedOnUrl(){ String xChallenger = null; try { - xChallenger = request.splat()[0]; + xChallenger = request.splat(); } catch (Exception e) { logger.warn("No challenger id to render"); } @@ -525,7 +525,7 @@ function setMenuNavBasedOnUrl(){ String urltoshow = ""; try { - urltoshow = request.splat()[0]; + urltoshow = request.splat(); } catch (Exception e) { logger.error("No url to pretend to be on 404", e); } @@ -544,8 +544,8 @@ function setMenuNavBasedOnUrl(){ // Since we already scanned for static content we can just htmlise a 404 if // necessary if (response.status() == 404 - && request.headers("accept") != null - && request.headers("accept").contains("html")) { + && request.header("accept") != null + && request.header("accept").contains("html")) { logger.info("An HTML 404"); pageNotFoundHtmlResponse.amendResponse(response, ""); @@ -553,7 +553,7 @@ function setMenuNavBasedOnUrl(){ }); } - private Map getMarkdownParamsFromRequest(Request request) { + private Map getMarkdownParamsFromRequest(HttpServerRequest request) { String originUrl = request.scheme() + "://" + request.host(); Map params = new HashMap<>(); params.put("ORIGIN_URL", originUrl); @@ -651,7 +651,9 @@ private String multiUserShortHelp( private String refreshScriptFor(final String xChallenger) { - if (!guiStayAlive) return ""; + if (!guiStayAlive) { + return ""; + } StringBuilder html = new StringBuilder(); diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/gui/MarkdownContentManager.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/gui/MarkdownContentManager.java index 855b908a..656846d4 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/gui/MarkdownContentManager.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/gui/MarkdownContentManager.java @@ -529,7 +529,9 @@ private String dropDownMenuAsMarkdown() { */ private String processMacrosInContentLine(String line, Map params) { - if (!line.contains("{{<")) return line; + if (!line.contains("{{<")) { + return line; + } // String youTubeHtmlBlock = """ //
diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/gui/PageNotFoundResponse.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/gui/PageNotFoundResponse.java index 43115533..7a16105a 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/gui/PageNotFoundResponse.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/gui/PageNotFoundResponse.java @@ -1,6 +1,6 @@ package uk.co.compendiumdev.challenge.gui; -import spark.Response; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerResponse; import uk.co.compendiumdev.thingifier.htmlgui.htmlgen.DefaultGUIHTML; public class PageNotFoundResponse { @@ -10,7 +10,7 @@ public PageNotFoundResponse(DefaultGUIHTML guiManagement) { this.guiManagement = guiManagement; } - public void amendResponse(Response response, String bodyStringAppend) { + public void amendResponse(HttpServerResponse response, String bodyStringAppend) { response.status(404); response.type("text/html"); StringBuilder html = new StringBuilder(); diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/spark/SparkMessageLengthValidator.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/httpserver/HttpMessageLengthValidator.java similarity index 54% rename from challenger/src/main/java/uk/co/compendiumdev/challenge/spark/SparkMessageLengthValidator.java rename to challenger/src/main/java/uk/co/compendiumdev/challenge/httpserver/HttpMessageLengthValidator.java index 8a4e8fdc..a12bebb3 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/spark/SparkMessageLengthValidator.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/httpserver/HttpMessageLengthValidator.java @@ -1,34 +1,35 @@ -package uk.co.compendiumdev.challenge.spark; +package uk.co.compendiumdev.challenge.httpserver; -import spark.Request; -import spark.Response; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerRequest; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerResponse; +import uk.co.compendiumdev.thingifier.adapter.httpserver.conversion.HttpServerRequestToInternalHttpRequest; +import uk.co.compendiumdev.thingifier.adapter.httpserver.conversion.InternalHttpResponseToHttpServer; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpRequest; import uk.co.compendiumdev.thingifier.adapter.internalhttp.conversion.HttpApiResponseToInternalHttpResponse; import uk.co.compendiumdev.thingifier.adapter.internalhttp.conversion.InternalHttpRequestToHttpApiRequest; -import uk.co.compendiumdev.thingifier.adapter.spark.conversion.InternalHttpResponseToSpark; -import uk.co.compendiumdev.thingifier.adapter.spark.conversion.SparkToInternalHttpRequest; import uk.co.compendiumdev.thingifier.api.ermodelconversion.JsonThing; import uk.co.compendiumdev.thingifier.api.http.HttpApiRequest; import uk.co.compendiumdev.thingifier.api.http.HttpApiResponse; import uk.co.compendiumdev.thingifier.api.response.ApiResponse; import uk.co.compendiumdev.thingifier.apiconfig.ThingifierApiConfig; -public class SparkMessageLengthValidator { +public class HttpMessageLengthValidator { public static final int DEFAULT_MAX_LENGTH = 24000; private final int maxLength; - public SparkMessageLengthValidator() { + public HttpMessageLengthValidator() { this(DEFAULT_MAX_LENGTH); } - SparkMessageLengthValidator(int maxLength) { + HttpMessageLengthValidator(int maxLength) { this.maxLength = maxLength; } - public boolean rejectRequestTooLong(final Request request, final Response result) { - if (request.contentLength() > this.maxLength) { + public boolean rejectRequestTooLong( + final HttpServerRequest request, final HttpServerResponse result) { + if (contentLength(request) > this.maxLength) { // randomly picked 24K result.status(413); return true; @@ -37,22 +38,33 @@ public boolean rejectRequestTooLong(final Request request, final Response result } public String messageTooLongErrorResponse( - final ThingifierApiConfig apiConfig, final Request request, final Response result) { + final ThingifierApiConfig apiConfig, + final HttpServerRequest request, + final HttpServerResponse result) { final ApiResponse response = ApiResponse.error( 413, String.format( - "Error: Request too large, max allowed is %d bytes", + "Error: request too large, max allowed is %d bytes", this.maxLength)); - final InternalHttpRequest internalRequest = SparkToInternalHttpRequest.convert(request); + final InternalHttpRequest internalRequest = + HttpServerRequestToInternalHttpRequest.convert(request); final HttpApiRequest myRequest = InternalHttpRequestToHttpApiRequest.convert(internalRequest); JsonThing jsonThing = new JsonThing(apiConfig.jsonOutput()); final HttpApiResponse httpApiResponse = new HttpApiResponse(myRequest.getHeaders(), response, jsonThing, apiConfig); - return InternalHttpResponseToSpark.convert( + return InternalHttpResponseToHttpServer.convert( HttpApiResponseToInternalHttpResponse.convert(httpApiResponse), result); } + + private int contentLength(final HttpServerRequest request) { + try { + return Integer.parseInt(request.contentLength()); + } catch (NumberFormatException e) { + return 0; + } + } } diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/mirror/MirrorRoutes.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/mirror/MirrorRoutes.java index da33d30f..5282448d 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/mirror/MirrorRoutes.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/mirror/MirrorRoutes.java @@ -1,14 +1,14 @@ package uk.co.compendiumdev.challenge.practicemodes.mirror; -import static spark.Spark.*; +import static uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes.*; import java.util.ArrayList; import java.util.List; -import spark.Route; import uk.co.compendiumdev.thingifier.Thingifier; -import uk.co.compendiumdev.thingifier.adapter.spark.AdhocDocumentedSparkRouteConfigurer; -import uk.co.compendiumdev.thingifier.adapter.spark.SimpleSparkRouteCreator; -import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierAutoDocGenRouting; +import uk.co.compendiumdev.thingifier.adapter.httpserver.AdhocDocumentedHttpRouteConfigurer; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpRouteHandler; +import uk.co.compendiumdev.thingifier.adapter.httpserver.SimpleHttpRouteCreator; +import uk.co.compendiumdev.thingifier.adapter.httpserver.ThingifierAutoDocGenRouting; import uk.co.compendiumdev.thingifier.api.docgen.RoutingVerb; import uk.co.compendiumdev.thingifier.api.docgen.ThingifierApiDocumentationDefn; import uk.co.compendiumdev.thingifier.htmlgui.htmlgen.DefaultGUIHTML; @@ -38,11 +38,11 @@ public void configure( verbEndpoints.add(rawEndPoint); verbEndpoints.add(rawEndPoint + "/*"); - AdhocDocumentedSparkRouteConfigurer routeCreatorAndDocumentor = - new AdhocDocumentedSparkRouteConfigurer(apiDefn); + AdhocDocumentedHttpRouteConfigurer routeCreatorAndDocumentor = + new AdhocDocumentedHttpRouteConfigurer(apiDefn); for (String anEndpoint : verbEndpoints) { - Route routeHandler = + HttpRouteHandler routeHandler = (request, result) -> { result.status(204); result.header( @@ -51,7 +51,7 @@ public void configure( }; if (anEndpoint.endsWith("/*")) { // add to routing but not to the api documentation - SimpleSparkRouteCreator.addHandler(anEndpoint, "options", routeHandler); + SimpleHttpRouteCreator.addHandler(anEndpoint, "options", routeHandler); } else { routeCreatorAndDocumentor.add( anEndpoint, @@ -62,12 +62,12 @@ public void configure( } } - Route mirroredRoute = + HttpRouteHandler mirroredRoute = (request, result) -> { return requestMirror.mirrorRequest(request, result); }; - Route rawTextMirroredRoute = + HttpRouteHandler rawTextMirroredRoute = (request, result) -> { return requestMirror.mirrorRequestAsText(request, result); }; @@ -81,14 +81,14 @@ public void configure( for (RoutingVerb routing : verbs200status) { if (anEndpoint.endsWith("/*")) { // add to routing but not to the api documentation - SimpleSparkRouteCreator.addHandler(anEndpoint, routing.name(), mirroredRoute); + SimpleHttpRouteCreator.addHandler(anEndpoint, routing.name(), mirroredRoute); } else { if (anEndpoint.startsWith(endpoint)) { routeCreatorAndDocumentor.add( anEndpoint, routing, 200, - "Mirror a " + routing.name().toUpperCase() + " Request", + "Mirror a " + routing.name().toUpperCase() + " request", mirroredRoute); } if (anEndpoint.startsWith(rawEndPoint)) { @@ -96,7 +96,7 @@ public void configure( anEndpoint, routing, 200, - "Raw Text Mirror of a " + routing.name().toUpperCase() + " Request", + "Raw Text Mirror of a " + routing.name().toUpperCase() + " request", rawTextMirroredRoute); } } @@ -107,14 +107,14 @@ public void configure( Handle HEAD verb - special handling to only return headers */ for (String anEndpoint : verbEndpoints) { - Route routeHAndler = + HttpRouteHandler routeHAndler = (request, result) -> { requestMirror.mirrorRequest(request, result); return ""; }; if (anEndpoint.endsWith("/*")) { // add to routing but not to the api documentation - SimpleSparkRouteCreator.addHandler(anEndpoint, "head", routeHAndler); + SimpleHttpRouteCreator.addHandler(anEndpoint, "head", routeHAndler); } else { routeCreatorAndDocumentor.add( anEndpoint, diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/mirror/RequestMirror.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/mirror/RequestMirror.java index 7703a1a7..5ba81d57 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/mirror/RequestMirror.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/mirror/RequestMirror.java @@ -1,10 +1,10 @@ package uk.co.compendiumdev.challenge.practicemodes.mirror; -import spark.Request; -import spark.Response; -import uk.co.compendiumdev.challenge.spark.SparkMessageLengthValidator; +import uk.co.compendiumdev.challenge.httpserver.HttpMessageLengthValidator; import uk.co.compendiumdev.thingifier.Thingifier; -import uk.co.compendiumdev.thingifier.adapter.spark.routehandlers.SparkApiRequestResponseHandler; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerRequest; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerResponse; +import uk.co.compendiumdev.thingifier.adapter.httpserver.routehandlers.HttpApiRequestResponseHandler; import uk.co.compendiumdev.thingifier.api.http.headers.headerparser.AcceptHeaderParser; import uk.co.compendiumdev.thingifier.core.domain.definitions.EntityDefinition; import uk.co.compendiumdev.thingifier.core.domain.definitions.field.definition.Field; @@ -15,7 +15,7 @@ public class RequestMirror { EntityDefinition entityDefn; // new RequestMirror().mirrorRequest(request, result); - public String mirrorRequest(final Request request, final Response result) { + public String mirrorRequest(final HttpServerRequest request, final HttpServerResponse result) { final Thingifier mirrorThingifier = new Thingifier(); @@ -24,7 +24,7 @@ public String mirrorRequest(final Request request, final Response result) { entityDefn.addFields(Field.is("details", FieldType.STRING)); // reject large requests - SparkMessageLengthValidator lengthValidator = new SparkMessageLengthValidator(); + HttpMessageLengthValidator lengthValidator = new HttpMessageLengthValidator(); if (lengthValidator.rejectRequestTooLong(request, result)) { return lengthValidator.messageTooLongErrorResponse( @@ -32,12 +32,12 @@ public String mirrorRequest(final Request request, final Response result) { } String returnValue = - new SparkApiRequestResponseHandler(request, result, mirrorThingifier) + new HttpApiRequestResponseHandler(request, result, mirrorThingifier) .usingHandler(new MirrorHttpApiRequestHandler(this.entityDefn)) .validateRequestSyntax(false) .handle(); - final AcceptHeaderParser parser = new AcceptHeaderParser(request.headers("accept")); + final AcceptHeaderParser parser = new AcceptHeaderParser(request.header("accept")); // handle text separately as the main api does not 'do' text if (parser.hasAskedForTEXT()) { @@ -47,14 +47,15 @@ public String mirrorRequest(final Request request, final Response result) { return returnValue; } - public String mirrorRequestAsText(final Request request, final Response result) { + public String mirrorRequestAsText( + final HttpServerRequest request, final HttpServerResponse result) { // The raw unfiltered request as text final Thingifier mirrorThingifier = new Thingifier(); // reject large requests - SparkMessageLengthValidator lengthValidator = new SparkMessageLengthValidator(); + HttpMessageLengthValidator lengthValidator = new HttpMessageLengthValidator(); if (lengthValidator.rejectRequestTooLong(request, result)) { return lengthValidator.messageTooLongErrorResponse( @@ -62,7 +63,7 @@ public String mirrorRequestAsText(final Request request, final Response result) } String returnValue = - new SparkApiRequestResponseHandler(request, result, mirrorThingifier) + new HttpApiRequestResponseHandler(request, result, mirrorThingifier) .usingHandler(new MirrorHttpApiTextRequestHandler()) .validateRequestSyntax(false) .handle(); diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simpleapi/SimpleApiCorsHeadersResponseHook.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simpleapi/SimpleApiCorsHeadersResponseHook.java index 8b5f1b97..96696bdc 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simpleapi/SimpleApiCorsHeadersResponseHook.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simpleapi/SimpleApiCorsHeadersResponseHook.java @@ -3,9 +3,9 @@ import static uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpMethod.OPTIONS; import java.util.List; +import uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks.InternalHttpResponseHook; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpRequest; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpResponse; -import uk.co.compendiumdev.thingifier.adapter.spark.messagehooks.InternalHttpResponseHook; public class SimpleApiCorsHeadersResponseHook implements InternalHttpResponseHook { diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simpleapi/SimpleApiRoutes.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simpleapi/SimpleApiRoutes.java index 6d9906dc..e7e16269 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simpleapi/SimpleApiRoutes.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simpleapi/SimpleApiRoutes.java @@ -1,12 +1,12 @@ package uk.co.compendiumdev.challenge.practicemodes.simpleapi; -import static spark.Spark.*; +import static uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes.*; import java.util.List; import uk.co.compendiumdev.thingifier.Thingifier; -import uk.co.compendiumdev.thingifier.adapter.spark.SimpleSparkRouteCreator; -import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierAutoDocGenRouting; -import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierHttpApiRoutings; +import uk.co.compendiumdev.thingifier.adapter.httpserver.SimpleHttpRouteCreator; +import uk.co.compendiumdev.thingifier.adapter.httpserver.ThingifierAutoDocGenRouting; +import uk.co.compendiumdev.thingifier.adapter.httpserver.ThingifierHttpApiRoutings; import uk.co.compendiumdev.thingifier.api.docgen.RoutingDefinition; import uk.co.compendiumdev.thingifier.api.docgen.RoutingStatus; import uk.co.compendiumdev.thingifier.api.docgen.RoutingVerb; @@ -102,8 +102,7 @@ public void configure() { apiDocDefn.setOgType("website"); apiDocDefn.setTwitterCard("summary_large_image"); - new SimpleSparkRouteCreator("/simpleapi/items") - .status(501, true, List.of("patch", "trace")); + new SimpleHttpRouteCreator("/simpleapi/items").status(501, true, List.of("patch", "trace")); get( "/simpleapi/randomisbn", @@ -140,7 +139,7 @@ public void configure() { "return a random ISBN that can be used for testing purposes with the Simple API.") .addPossibleStatuses(200)); - new SimpleSparkRouteCreator("/simpleapi/randomisbn") + new SimpleHttpRouteCreator("/simpleapi/randomisbn") .status(405, true, List.of("put", "post", "delete", "patch", "trace")); new ThingifierAutoDocGenRouting(simplethings, apiDocDefn, gui); diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simulation/SimulationRoutes.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simulation/SimulationRoutes.java index 71c2522d..1b58c3c8 100644 --- a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simulation/SimulationRoutes.java +++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simulation/SimulationRoutes.java @@ -1,14 +1,14 @@ package uk.co.compendiumdev.challenge.practicemodes.simulation; -import static spark.Spark.*; +import static uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes.*; import java.util.List; import uk.co.compendiumdev.challenge.ChallengerConfig; import uk.co.compendiumdev.thingifier.Thingifier; import uk.co.compendiumdev.thingifier.adapter.http.routehandlers.HttpApiRequestHandler; -import uk.co.compendiumdev.thingifier.adapter.spark.SimpleSparkRouteCreator; -import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierAutoDocGenRouting; -import uk.co.compendiumdev.thingifier.adapter.spark.routehandlers.SparkApiRequestResponseHandler; +import uk.co.compendiumdev.thingifier.adapter.httpserver.SimpleHttpRouteCreator; +import uk.co.compendiumdev.thingifier.adapter.httpserver.ThingifierAutoDocGenRouting; +import uk.co.compendiumdev.thingifier.adapter.httpserver.routehandlers.HttpApiRequestResponseHandler; import uk.co.compendiumdev.thingifier.api.docgen.ThingifierApiDocumentationDefn; import uk.co.compendiumdev.thingifier.api.http.HttpApiRequest; import uk.co.compendiumdev.thingifier.api.response.ApiResponse; @@ -149,11 +149,10 @@ public void configure() { return ""; }); - new SimpleSparkRouteCreator(apiEndpoint).status(501, true, List.of("patch", "trace")); - new SimpleSparkRouteCreator(apiEndpoint).status(405, true, List.of("delete")); + new SimpleHttpRouteCreator(apiEndpoint).status(501, true, List.of("patch", "trace")); + new SimpleHttpRouteCreator(apiEndpoint).status(405, true, List.of("delete")); - new SimpleSparkRouteCreator(apiEndpoint + "/*") - .status(501, true, List.of("patch", "trace")); + new SimpleHttpRouteCreator(apiEndpoint + "/*").status(501, true, List.of("patch", "trace")); options( apiEndpoint + "/*", @@ -180,7 +179,7 @@ public void configure() { get( apiEndpoint, (request, result) -> { - return new SparkApiRequestResponseHandler(request, result, simulation) + return new HttpApiRequestResponseHandler(request, result, simulation) .usingHandler(getEntitiesHandler) .handle(); }); @@ -188,7 +187,7 @@ public void configure() { head( apiEndpoint, (request, result) -> { - new SparkApiRequestResponseHandler(request, result, simulation) + new HttpApiRequestResponseHandler(request, result, simulation) .usingHandler(getEntitiesHandler) .handle(); return ""; @@ -229,7 +228,7 @@ public void configure() { get( apiEndpoint + "/:id", (request, result) -> { - return new SparkApiRequestResponseHandler(request, result, simulation) + return new HttpApiRequestResponseHandler(request, result, simulation) .usingHandler(getEntityHandler) .handle(); }); @@ -237,7 +236,7 @@ public void configure() { head( apiEndpoint + "/:id", (request, result) -> { - new SparkApiRequestResponseHandler(request, result, simulation) + new HttpApiRequestResponseHandler(request, result, simulation) .usingHandler(getEntityHandler) .handle(); @@ -248,7 +247,7 @@ public void configure() { post( apiEndpoint, (request, result) -> { - return new SparkApiRequestResponseHandler(request, result, simulation) + return new HttpApiRequestResponseHandler(request, result, simulation) .usingHandler( (anHttpApiRequest) -> { return ApiResponse.created( @@ -306,7 +305,7 @@ public void configure() { post( apiEndpoint + "/:id", (request, result) -> { - return new SparkApiRequestResponseHandler(request, result, simulation) + return new HttpApiRequestResponseHandler(request, result, simulation) .usingHandler(putAndPostEntityHandler) .handle(); }); @@ -316,7 +315,7 @@ public void configure() { put( apiEndpoint + "/:id", (request, result) -> { - return new SparkApiRequestResponseHandler(request, result, simulation) + return new HttpApiRequestResponseHandler(request, result, simulation) .usingHandler(putAndPostEntityHandler) .handle(); }); @@ -324,7 +323,7 @@ public void configure() { delete( apiEndpoint + "/:id", (request, result) -> { - return new SparkApiRequestResponseHandler(request, result, simulation) + return new HttpApiRequestResponseHandler(request, result, simulation) .usingHandler( (anHttpApiRequest) -> { ApiResponse response; diff --git a/challenger/src/test/java/uk/co/compendiumdev/challenge/IndexNowRouteHandlerTest.java b/challenger/src/test/java/uk/co/compendiumdev/challenge/IndexNowRouteHandlerTest.java index f0999a28..d8075f02 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/challenge/IndexNowRouteHandlerTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/challenge/IndexNowRouteHandlerTest.java @@ -4,7 +4,7 @@ import java.util.function.BiConsumer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import spark.Route; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpRouteHandler; public class IndexNowRouteHandlerTest { @@ -12,12 +12,12 @@ public class IndexNowRouteHandlerTest { public void routeCanBeConfiguredWhenValuesAreValid() { AtomicReference capturedPath = new AtomicReference<>(null); - AtomicReference capturedRoute = new AtomicReference<>(null); + AtomicReference capturedRoute = new AtomicReference<>(null); - BiConsumer registrar = - (path, route) -> { + BiConsumer registrar = + (path, HttpRouteHandler) -> { capturedPath.set(path); - capturedRoute.set(route); + capturedRoute.set(HttpRouteHandler); }; IndexNowRouteHandler handler = @@ -31,13 +31,13 @@ public void routeCanBeConfiguredWhenValuesAreValid() { @Test public void routeReturnsConfiguredKey() throws Exception { - AtomicReference capturedRoute = new AtomicReference<>(null); + AtomicReference capturedRoute = new AtomicReference<>(null); IndexNowRouteHandler handler = new IndexNowRouteHandler( "/myIndexNowKey63638.txt", "abc123", - (path, route) -> capturedRoute.set(route)); + (path, HttpRouteHandler) -> capturedRoute.set(HttpRouteHandler)); handler.configureRoutes(); @@ -48,11 +48,13 @@ public void routeReturnsConfiguredKey() throws Exception { @Test public void doesNotConfigureRouteWhenKeyMissing() { - AtomicReference capturedRoute = new AtomicReference<>(null); + AtomicReference capturedRoute = new AtomicReference<>(null); IndexNowRouteHandler handler = new IndexNowRouteHandler( - "/myIndexNowKey63638.txt", " ", (path, route) -> capturedRoute.set(route)); + "/myIndexNowKey63638.txt", + " ", + (path, HttpRouteHandler) -> capturedRoute.set(HttpRouteHandler)); Assertions.assertFalse(handler.configureRoutes()); Assertions.assertNull(capturedRoute.get()); @@ -61,10 +63,13 @@ public void doesNotConfigureRouteWhenKeyMissing() { @Test public void doesNotConfigureRouteWhenLocationMissing() { - AtomicReference capturedRoute = new AtomicReference<>(null); + AtomicReference capturedRoute = new AtomicReference<>(null); IndexNowRouteHandler handler = - new IndexNowRouteHandler(" ", "abc123", (path, route) -> capturedRoute.set(route)); + new IndexNowRouteHandler( + " ", + "abc123", + (path, HttpRouteHandler) -> capturedRoute.set(HttpRouteHandler)); Assertions.assertFalse(handler.configureRoutes()); Assertions.assertNull(capturedRoute.get()); diff --git a/challenger/src/test/java/uk/co/compendiumdev/challenge/apimodel/ChallengeApiModelRepositoryTest.java b/challenger/src/test/java/uk/co/compendiumdev/challenge/apimodel/ChallengeApiModelRepositoryTest.java index 7976291f..cb705e53 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/challenge/apimodel/ChallengeApiModelRepositoryTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/challenge/apimodel/ChallengeApiModelRepositoryTest.java @@ -126,7 +126,7 @@ public void relationshipGetRoutesStillFallBackToLegacyQueryTraversal() { .withField("title", "File paperwork")); repository.relationships().connect(projectInstance, "tasks", taskInstance); - ApiResponse response = + ApiResponse apiResponse = thingifier .api() .get( @@ -134,11 +134,12 @@ public void relationshipGetRoutesStillFallBackToLegacyQueryTraversal() { new QueryFilterParams(), new HttpHeadersBlock()); - Assertions.assertEquals(200, response.getStatusCode()); - Assertions.assertEquals(1, response.getReturnedInstanceCollection().size()); + Assertions.assertEquals(200, apiResponse.getStatusCode()); + Assertions.assertEquals(1, apiResponse.getReturnedInstanceCollection().size()); Assertions.assertEquals( "File paperwork", - response.getReturnedInstanceCollection() + apiResponse + .getReturnedInstanceCollection() .get(0) .getFieldValue("title") .asString()); diff --git a/challenger/src/test/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerApiResponseHookTest.java b/challenger/src/test/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerApiResponseHookTest.java index 777ff48a..0799f493 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerApiResponseHookTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerApiResponseHookTest.java @@ -45,7 +45,7 @@ public void filteredTodosChallengeCompletesWhenDoneAndNotDoneTodosExist( fixture.hook.run( fixture.request("todos", GET).setQueryParams(Map.of("doneStatus", "true")), - fixture.response(200), + fixture.apiResponse(200), fixture.thingifier.apiConfig()); Assertions.assertTrue( @@ -63,7 +63,7 @@ public void filteredTodosChallengeDoesNotCompleteWithoutMixedDoneStatusTodos( fixture.hook.run( fixture.request("todos", GET).setQueryParams(Map.of("doneStatus", "true")), - fixture.response(200), + fixture.apiResponse(200), fixture.thingifier.apiConfig()); Assertions.assertFalse( @@ -91,7 +91,7 @@ public void postMaxContentChallengeReadsCreatedTodoThroughRepository( fixture.hook.run( fixture.request("todos", POST), - fixture.response(created), + fixture.apiResponse(created), fixture.thingifier.apiConfig()); Assertions.assertTrue( @@ -111,7 +111,7 @@ public void deleteAllTodosChallengeCompletesWhenRepositoryIsEmpty( fixture.hook.run( fixture.request("todos/" + todo.getPrimaryKeyValue(), DELETE), - fixture.response(200), + fixture.apiResponse(200), fixture.thingifier.apiConfig()); Assertions.assertTrue(fixture.challenger.statusOfChallenge(CHALLENGE.DELETE_ALL_TODOS)); @@ -130,7 +130,7 @@ public void deleteAllTodosChallengeDoesNotCompleteWhenRepositoryStillHasTodos( fixture.hook.run( fixture.request("todos/" + deletedTodo.getPrimaryKeyValue(), DELETE), - fixture.response(200), + fixture.apiResponse(200), fixture.thingifier.apiConfig()); Assertions.assertFalse( @@ -195,11 +195,11 @@ HttpApiRequest request(final String path, final HttpApiRequest.VERB verb) { .addHeader("X-CHALLENGER", challenger.getXChallenger()); } - HttpApiResponse response(final int statusCode) { - return response(new ApiResponse(statusCode)); + HttpApiResponse apiResponse(final int statusCode) { + return apiResponse(new ApiResponse(statusCode)); } - HttpApiResponse response(final ApiResponse apiResponse) { + HttpApiResponse apiResponse(final ApiResponse apiResponse) { return new HttpApiResponse( new HttpHeadersBlock(), apiResponse, diff --git a/challenger/src/test/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerInternalHttpRequestHookTest.java b/challenger/src/test/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerInternalHttpRequestHookTest.java index 435d56a4..610720f2 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerInternalHttpRequestHookTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/challenge/challengehooks/ChallengerInternalHttpRequestHookTest.java @@ -41,7 +41,7 @@ public void inMultUserModeAddingAnXChallengerHeaderWillTouchTheChallenger() // if so could 'wait' in the test, or 'hack the object to have a different last accessed // time' // set private variable that test will 'touch' - // when using mock at spark level, did not need to 'hack' the object + // when using mock at HTTP server level, did not need to 'hack' the object Field lastAccessedField = ChallengerAuthData.class.getDeclaredField("lastAccessed"); lastAccessedField.setAccessible(true); lastAccessedField.set(challenger, 0L); diff --git a/challenger/src/test/java/uk/co/compendiumdev/challenge/challengesrouting/AuthRoutesTest.java b/challenger/src/test/java/uk/co/compendiumdev/challenge/challengesrouting/AuthRoutesTest.java index ff23609f..a5662e3c 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/challenge/challengesrouting/AuthRoutesTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/challenge/challengesrouting/AuthRoutesTest.java @@ -14,7 +14,7 @@ import uk.co.compendiumdev.challenge.ChallengerAuthData; import uk.co.compendiumdev.challenger.http.httpclient.HttpMessageSender; import uk.co.compendiumdev.challenger.http.httpclient.HttpResponseDetails; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; public class AuthRoutesTest { private static HttpMessageSender http; @@ -22,8 +22,8 @@ public class AuthRoutesTest { @BeforeAll static void createHttp() { - // this uses the Environment to startup the spark app to - // issue http tests and test the routing in spark + // this uses the Environment to startup the server app to + // issue http tests and test the server routing http = new HttpMessageSender(Environment.getBaseUri()); challenger = ChallengeMain.getChallenger().getChallengers().createNewChallenger(); } diff --git a/challenger/src/test/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengerTrackingRoutesTest.java b/challenger/src/test/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengerTrackingRoutesTest.java index def80ec3..c1bfe3a4 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengerTrackingRoutesTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengerTrackingRoutesTest.java @@ -11,7 +11,7 @@ import uk.co.compendiumdev.challenge.challengers.Challengers; import uk.co.compendiumdev.challenger.http.httpclient.HttpMessageSender; import uk.co.compendiumdev.challenger.http.httpclient.HttpResponseDetails; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; public class ChallengerTrackingRoutesTest { @@ -22,8 +22,8 @@ public class ChallengerTrackingRoutesTest { static void createHttp() { Environment.stop(); - // this uses the Environment to startup the spark app to - // issue http tests and test the routing in spark + // this uses the Environment to startup the server app to + // issue http tests and test the server routing // test this in multi user mode http = new HttpMessageSender(Environment.getBaseUri(false)); // challenger = Environment.getNewChallenger(); diff --git a/challenger/src/test/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengesRoutesTest.java b/challenger/src/test/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengesRoutesTest.java index 60d23936..0cc20da5 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengesRoutesTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengesRoutesTest.java @@ -17,7 +17,7 @@ import uk.co.compendiumdev.challenge.challenges.ChallengeDefinitions; import uk.co.compendiumdev.challenger.http.httpclient.HttpMessageSender; import uk.co.compendiumdev.challenger.http.httpclient.HttpResponseDetails; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; public class ChallengesRoutesTest { @@ -26,8 +26,8 @@ public class ChallengesRoutesTest { @BeforeAll static void createHttp() { - // this uses the Environment to startup the spark app to - // issue http tests and test the routing in spark + // this uses the Environment to startup the server app to + // issue http tests and test the server routing http = new HttpMessageSender(Environment.getBaseUri()); ChallengerConfig config = new ChallengerConfig(); config.setToNoPersistenceMode(); diff --git a/challenger/src/test/java/uk/co/compendiumdev/challenge/challengesrouting/HeartBeatRoutesTest.java b/challenger/src/test/java/uk/co/compendiumdev/challenge/challengesrouting/HeartBeatRoutesTest.java index c5f9257b..d79bd755 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/challenge/challengesrouting/HeartBeatRoutesTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/challenge/challengesrouting/HeartBeatRoutesTest.java @@ -11,15 +11,15 @@ import org.junit.jupiter.params.provider.MethodSource; import uk.co.compendiumdev.challenger.http.httpclient.HttpMessageSender; import uk.co.compendiumdev.challenger.http.httpclient.HttpResponseDetails; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; public class HeartBeatRoutesTest { private static HttpMessageSender http; @BeforeAll static void createHttp() { - // this uses the Environment to startup the spark app to - // issue http tests and test the routing in spark + // this uses the Environment to startup the server app to + // issue http tests and test the server routing http = new HttpMessageSender(Environment.getBaseUri()); } diff --git a/challenger/src/test/java/uk/co/compendiumdev/challenger/http/completechallenges/ChallengeCompleteTest.java b/challenger/src/test/java/uk/co/compendiumdev/challenger/http/completechallenges/ChallengeCompleteTest.java index 1560c47a..4f1ec1af 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/challenger/http/completechallenges/ChallengeCompleteTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/challenger/http/completechallenges/ChallengeCompleteTest.java @@ -15,7 +15,7 @@ import uk.co.compendiumdev.challenger.http.httpclient.HttpResponseDetails; import uk.co.compendiumdev.challenger.payloads.Todo; import uk.co.compendiumdev.challenger.payloads.Todos; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; import uk.co.compendiumdev.thingifier.core.domain.definitions.EntityDefinition; import uk.co.compendiumdev.thingifier.core.domain.instances.EntityInstance; import uk.co.compendiumdev.thingifier.core.domain.instances.EntityInstanceDraft; @@ -530,7 +530,7 @@ public void canPostTodosFailPayloadLenValidationPass() { Assertions.assertEquals(413, response.statusCode); Assertions.assertTrue( - response.body.contains("Request body too large, max allowed is 5000 bytes")); + response.body.contains("request body too large, max allowed is 5000 bytes")); Assertions.assertTrue( challenger.statusOfChallenge(CHALLENGE.POST_TODOS_TOO_LONG_PAYLOAD_SIZE)); } diff --git a/challenger/src/test/java/uk/co/compendiumdev/challenger/http/completechallenges/MultiPlayerModeHookTest.java b/challenger/src/test/java/uk/co/compendiumdev/challenger/http/completechallenges/MultiPlayerModeHookTest.java index b45a9d72..6f0b7d26 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/challenger/http/completechallenges/MultiPlayerModeHookTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/challenger/http/completechallenges/MultiPlayerModeHookTest.java @@ -9,7 +9,7 @@ import org.junit.jupiter.params.provider.ValueSource; import uk.co.compendiumdev.challenger.http.httpclient.HttpMessageSender; import uk.co.compendiumdev.challenger.http.httpclient.HttpResponseDetails; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; import uk.co.compendiumdev.thingifier.core.EntityRelModel; public class MultiPlayerModeHookTest { diff --git a/challenger/src/test/java/uk/co/compendiumdev/challenger/http/conditions/ConfigSetupTest.java b/challenger/src/test/java/uk/co/compendiumdev/challenger/http/conditions/ConfigSetupTest.java index 4d12a162..627ad12a 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/challenger/http/conditions/ConfigSetupTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/challenger/http/conditions/ConfigSetupTest.java @@ -6,7 +6,7 @@ import org.junit.jupiter.api.Test; import uk.co.compendiumdev.challenger.http.httpclient.HttpMessageSender; import uk.co.compendiumdev.challenger.http.httpclient.HttpResponseDetails; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; public class ConfigSetupTest { diff --git a/challenger/src/test/java/uk/co/compendiumdev/challenger/http/defects/MultiUserDefectsTest.java b/challenger/src/test/java/uk/co/compendiumdev/challenger/http/defects/MultiUserDefectsTest.java index ebc77ac9..fee0d8db 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/challenger/http/defects/MultiUserDefectsTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/challenger/http/defects/MultiUserDefectsTest.java @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test; import uk.co.compendiumdev.challenger.http.httpclient.HttpMessageSender; import uk.co.compendiumdev.challenger.http.httpclient.HttpResponseDetails; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; public class MultiUserDefectsTest { diff --git a/challenger/src/test/java/uk/co/compendiumdev/challenger/http/httpclient/HttpClientRequestSender.java b/challenger/src/test/java/uk/co/compendiumdev/challenger/http/httpclient/HttpClientRequestSender.java index 52dda164..5fd4a387 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/challenger/http/httpclient/HttpClientRequestSender.java +++ b/challenger/src/test/java/uk/co/compendiumdev/challenger/http/httpclient/HttpClientRequestSender.java @@ -6,6 +6,7 @@ import java.net.http.HttpResponse; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,10 +57,11 @@ public HttpResponseDetails send( lastRequest = new HttpRequestDetails(); + String normalizedVerb = verb.toUpperCase(Locale.ROOT); final HttpRequest.Builder request = HttpRequest.newBuilder() .uri(url.toURI()) - .method(verb, HttpRequest.BodyPublishers.ofString(body)); + .method(normalizedVerb, HttpRequest.BodyPublishers.ofString(body)); // SET HEADERS for (Map.Entry header : headers.entrySet()) { @@ -67,7 +69,7 @@ public HttpResponseDetails send( logger.info("Header - " + header.getKey() + " : " + headers.get(header.getValue())); } - logger.info("\nSending '" + verb + "' request to URL : " + url); + logger.info("\nSending '" + normalizedVerb + "' request to URL : " + url); final HttpRequest actualRequest = request.build(); @@ -77,7 +79,7 @@ public HttpResponseDetails send( lastRequest.addHeader(actualHeader.getKey(), actualHeader.getValue().get(0)); logger.info( String.format( - "Request Header - %s:%s", + "request Header - %s:%s", actualHeader.getKey(), actualHeader.getValue().get(0))); } @@ -86,12 +88,12 @@ public HttpResponseDetails send( response.statusCode = actualResponse.statusCode(); - logger.info("Response Code : " + response.statusCode); + logger.info("response Code : " + response.statusCode); response.body = actualResponse.body(); // print result - logger.info("Response Body: " + response.body); + logger.info("response Body: " + response.body); // add the headers Map responseHeaders = new HashMap<>(); diff --git a/challenger/src/test/java/uk/co/compendiumdev/challenger/http/httpclient/HttpRequestSender.java b/challenger/src/test/java/uk/co/compendiumdev/challenger/http/httpclient/HttpRequestSender.java index 917fd1fa..ed7fd494 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/challenger/http/httpclient/HttpRequestSender.java +++ b/challenger/src/test/java/uk/co/compendiumdev/challenger/http/httpclient/HttpRequestSender.java @@ -104,11 +104,11 @@ public HttpResponseDetails send( int statusCode = con.getResponseCode(); response.statusCode = statusCode; - logger.info("Response Code : " + statusCode); + logger.info("response Code : " + statusCode); String responseBody = getResponseBody(con); - logger.info("Response Body: " + responseBody); + logger.info("response Body: " + responseBody); response.body = responseBody.toString(); // add the headers to readable response @@ -125,7 +125,7 @@ public HttpResponseDetails send( for (String sentHeader : lastRequest.getHeaders().keySet()) { logger.info( String.format( - "Request Header - %s:%s", + "request Header - %s:%s", sentHeader, lastRequest.getHeaders().get(sentHeader))); } diff --git a/challenger/src/test/java/uk/co/compendiumdev/practicemodes/MirrorModeTest.java b/challenger/src/test/java/uk/co/compendiumdev/practicemodes/MirrorModeTest.java index 1dc48f6b..637f35f5 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/practicemodes/MirrorModeTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/practicemodes/MirrorModeTest.java @@ -10,7 +10,7 @@ import org.junit.jupiter.params.provider.MethodSource; import uk.co.compendiumdev.challenger.http.httpclient.HttpMessageSender; import uk.co.compendiumdev.challenger.http.httpclient.HttpResponseDetails; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; import uk.co.compendiumdev.thingifier.api.http.headers.HttpHeadersBlock; public class MirrorModeTest { @@ -19,8 +19,8 @@ public class MirrorModeTest { @BeforeAll static void createHttp() { - // this uses the Environment to startup the spark app to - // issue http tests and test the routing in spark + // this uses the Environment to startup the server app to + // issue http tests and test the server routing http = new HttpMessageSender(Environment.getBaseUri()); } @@ -255,7 +255,7 @@ void requestContentLengthIsCheckedForLength() { Assertions.assertEquals(413, response.statusCode); Assertions.assertEquals("application/json", response.getHeader("Content-Type")); Assertions.assertTrue( - response.body.contains("Error: Request too large, max allowed is 24000 bytes")); + response.body.contains("Error: request too large, max allowed is 24000 bytes")); } private String stringOfLength(int length) { diff --git a/challenger/src/test/java/uk/co/compendiumdev/practicemodes/SmulationModeTest.java b/challenger/src/test/java/uk/co/compendiumdev/practicemodes/SmulationModeTest.java index cfabd95c..26c02cb5 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/practicemodes/SmulationModeTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/practicemodes/SmulationModeTest.java @@ -11,15 +11,15 @@ import org.junit.jupiter.params.provider.MethodSource; import uk.co.compendiumdev.challenger.http.httpclient.HttpMessageSender; import uk.co.compendiumdev.challenger.http.httpclient.HttpResponseDetails; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; public class SmulationModeTest { private static HttpMessageSender http; @BeforeAll static void createHttp() { - // this uses the Environment to startup the spark app to - // issue http tests and test the routing in spark + // this uses the Environment to startup the server app to + // issue http tests and test the server routing http = new HttpMessageSender(Environment.getBaseUri()); } diff --git a/challenger/src/test/java/uk/co/compendiumdev/practicemodes/simpleapi/SimpleApiCrudTest.java b/challenger/src/test/java/uk/co/compendiumdev/practicemodes/simpleapi/SimpleApiCrudTest.java index f67dd593..609f8e58 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/practicemodes/simpleapi/SimpleApiCrudTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/practicemodes/simpleapi/SimpleApiCrudTest.java @@ -9,7 +9,7 @@ import uk.co.compendiumdev.challenger.http.httpclient.HttpResponseDetails; import uk.co.compendiumdev.practicemodes.simpleapi.testabstractions.Item; import uk.co.compendiumdev.practicemodes.simpleapi.testabstractions.SimpleAPIApi; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; public class SimpleApiCrudTest { @@ -95,8 +95,8 @@ Create Existing (*) Delete @BeforeAll static void createHttp() { - // this uses the Environment to startup the spark app to - // issue http tests and test the routing in spark + // this uses the Environment to startup the server app to + // issue http tests and test the server routing http = new HttpMessageSender(Environment.getBaseUri()); api = new SimpleAPIApi(http); random = new Random(); diff --git a/challenger/src/test/java/uk/co/compendiumdev/practicemodes/simpleapi/SimpleApiModeTest.java b/challenger/src/test/java/uk/co/compendiumdev/practicemodes/simpleapi/SimpleApiModeTest.java index 120e79a3..a753b8f2 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/practicemodes/simpleapi/SimpleApiModeTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/practicemodes/simpleapi/SimpleApiModeTest.java @@ -16,7 +16,7 @@ import uk.co.compendiumdev.practicemodes.simpleapi.testabstractions.Item; import uk.co.compendiumdev.practicemodes.simpleapi.testabstractions.Items; import uk.co.compendiumdev.practicemodes.simpleapi.testabstractions.SimpleAPIApi; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; /* The Simple API is wired up using the default thingifier so we are mainly confirming format, @@ -29,8 +29,8 @@ public class SimpleApiModeTest { @BeforeAll static void createHttp() { - // this uses the Environment to startup the spark app to - // issue http tests and test the routing in spark + // this uses the Environment to startup the server app to + // issue http tests and test the server routing http = new HttpMessageSender(Environment.getBaseUri()); api = new SimpleAPIApi(http); } diff --git a/challenger/src/test/java/uk/co/compendiumdev/sparkstart/Environment.java b/challenger/src/test/java/uk/co/compendiumdev/serverstart/Environment.java similarity index 94% rename from challenger/src/test/java/uk/co/compendiumdev/sparkstart/Environment.java rename to challenger/src/test/java/uk/co/compendiumdev/serverstart/Environment.java index cdddce73..970895c8 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/sparkstart/Environment.java +++ b/challenger/src/test/java/uk/co/compendiumdev/serverstart/Environment.java @@ -1,10 +1,9 @@ -package uk.co.compendiumdev.sparkstart; +package uk.co.compendiumdev.serverstart; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import spark.Spark; import uk.co.compendiumdev.challenge.ChallengeMain; public class Environment { @@ -33,13 +32,12 @@ public static String getBaseUri(boolean isSinglePlayerMode, boolean writeFiles) // return "https://apichallenges.eviltester.com"; logger.info("Checking app running"); - // if not running then start the spark + // if not running then start the server if (ChallengeMain.getChallenger() == null || !Port.inUse("localhost", 4567)) { logger.info( "App not running starting with single player mode == " + isSinglePlayerMode); // start it up - Spark.port(4567); List args = new ArrayList<>(); if (isSinglePlayerMode) { @@ -87,8 +85,6 @@ public static void waitTillRunningStatus(final boolean running) { } public static void stop() { - Spark.stop(); - Spark.awaitStop(); ChallengeMain.stop(); waitTillRunningStatus(false); } diff --git a/challenger/src/test/java/uk/co/compendiumdev/sparkstart/Port.java b/challenger/src/test/java/uk/co/compendiumdev/serverstart/Port.java similarity index 97% rename from challenger/src/test/java/uk/co/compendiumdev/sparkstart/Port.java rename to challenger/src/test/java/uk/co/compendiumdev/serverstart/Port.java index b83ed7eb..1b5cec35 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/sparkstart/Port.java +++ b/challenger/src/test/java/uk/co/compendiumdev/serverstart/Port.java @@ -1,4 +1,4 @@ -package uk.co.compendiumdev.sparkstart; +package uk.co.compendiumdev.serverstart; import java.io.IOException; import java.net.InetSocketAddress; diff --git a/challenger/src/test/java/uk/co/compendiumdev/uirouting/UiPagesAreReachableTest.java b/challenger/src/test/java/uk/co/compendiumdev/uirouting/UiPagesAreReachableTest.java index 58373bfc..f6d5d191 100644 --- a/challenger/src/test/java/uk/co/compendiumdev/uirouting/UiPagesAreReachableTest.java +++ b/challenger/src/test/java/uk/co/compendiumdev/uirouting/UiPagesAreReachableTest.java @@ -11,7 +11,7 @@ import org.junit.jupiter.params.provider.MethodSource; import uk.co.compendiumdev.challenger.http.httpclient.HttpMessageSender; import uk.co.compendiumdev.challenger.http.httpclient.HttpResponseDetails; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; public class UiPagesAreReachableTest { @@ -23,8 +23,8 @@ public class UiPagesAreReachableTest { @BeforeAll static void createHttp() { - // this uses the Environment to startup the spark app to - // issue http tests and test the routing in spark + // this uses the Environment to startup the server app to + // issue http tests and test the server routing http = new HttpMessageSender(Environment.getBaseUri()); // Basic Browser Headers diff --git a/challengerAuto/readme.md b/challengerAuto/readme.md index 80f93b39..9f04574a 100644 --- a/challengerAuto/readme.md +++ b/challengerAuto/readme.md @@ -151,7 +151,7 @@ Environment variables use uppercase names with underscores, for example `CHALLEN ## IDE Run Profiles -`uk.co.compendiumdev.sparkstart.ChallengerAutoRunProfiles` contains convenience methods that can be right-clicked in IntelliJ: +`uk.co.compendiumdev.serverstart.ChallengerAutoRunProfiles` contains convenience methods that can be right-clicked in IntelliJ: - `localMemorySinglePlayer()` - `localMemoryMultiPlayer()` diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/ChallengerAutoSmokeTest.java b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/ChallengerAutoSmokeTest.java index e14655b7..375e0334 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/ChallengerAutoSmokeTest.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/ChallengerAutoSmokeTest.java @@ -3,7 +3,7 @@ import io.restassured.RestAssured; import io.restassured.http.ContentType; import org.junit.jupiter.api.Test; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; public class ChallengerAutoSmokeTest { diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_04_head_challenges/C008HeadTodos200Test.java b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_04_head_challenges/C008HeadTodos200Test.java index 10c6388b..5ea73b75 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_04_head_challenges/C008HeadTodos200Test.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_04_head_challenges/C008HeadTodos200Test.java @@ -33,7 +33,7 @@ void canCheckHeadForTodos() { Assertions.assertTrue(statuses.getChallengeNamed("HEAD /todos (200)").status); Assertions.assertTrue( - headresponse.body().asString().equals(""), "Expected no Body for Head response"); + headresponse.body().asString().equals(""), "Expected no Body for Head Response"); final Response todosgetresponse = RestAssured.given() @@ -55,8 +55,8 @@ void canCheckHeadForTodos() { "Reporting-Endpoints", "Connection", "Date", - "X-Railway-Request-Id", - "x-railway-request-id", + "X-Railway-HttpServerRequest-Id", + "x-railway-HttpServerRequest-id", "x-railway-cdn-edge", "x-served-by", "date"); diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_07_post_update_challenges/C017PostUpdateTodosSuccess200Test.java b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_07_post_update_challenges/C017PostUpdateTodosSuccess200Test.java index f71aa488..02af2e9a 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_07_post_update_challenges/C017PostUpdateTodosSuccess200Test.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_07_post_update_challenges/C017PostUpdateTodosSuccess200Test.java @@ -45,13 +45,13 @@ void canUpdateATodoWithPost() { statuses.get(); Assertions.assertTrue(statuses.getChallengeNamed("POST /todos/{id} (200)").status); - // check it reported as updated in the details of the response + // check it reported as updated in the details of the Response Assertions.assertEquals(updatedDetails.id, updatedTodo.id); Assertions.assertEquals(updatedDetails.title, updatedTodo.title); Assertions.assertEquals(updatedDetails.description, updatedTodo.description); Assertions.assertEquals(updatedDetails.doneStatus, updatedTodo.doneStatus); - // issue a get request on the to do, just to double check it updated + // issue a get HttpServerRequest on the to do, just to double check it updated final Todos getTodo = RestAssured.given() .header("X-CHALLENGER", xChallenger) diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_07_post_update_challenges/C018PostUpdateTodosFail404Test.java b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_07_post_update_challenges/C018PostUpdateTodosFail404Test.java index c861f82b..306295c1 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_07_post_update_challenges/C018PostUpdateTodosFail404Test.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_07_post_update_challenges/C018PostUpdateTodosFail404Test.java @@ -54,7 +54,7 @@ void canNotUpdateANonExistantTodoWithPost() { statuses.get(); Assertions.assertTrue(statuses.getChallengeNamed("POST /todos/{id} (404)").status); - // check it reported as updated in the details of the response + // check it reported as updated in the details of the Response Assertions.assertEquals( String.format( "No such todo entity instance with id == %d found", updatedDetails.id), diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_10_options_challenges/C024OptionsTodos200Test.java b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_10_options_challenges/C024OptionsTodos200Test.java index 1488ef2c..6e78f708 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_10_options_challenges/C024OptionsTodos200Test.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_10_options_challenges/C024OptionsTodos200Test.java @@ -23,7 +23,7 @@ void canCheckOptionsForTodos() { . // this should really be 204, but to keep the challenge docs etc. // backwards compatible there is a hack in the hook to return - // 200 for this option request + // 200 for this option HttpServerRequest statusCode(200) .and() .extract() diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C025GetTodosAcceptXml200Test.java b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C025GetTodosAcceptXml200Test.java index 6af05181..2aea77d0 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C025GetTodosAcceptXml200Test.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C025GetTodosAcceptXml200Test.java @@ -28,7 +28,7 @@ void canGetTodosAsXML() { statuses.get(); Assertions.assertTrue(statuses.getChallengeNamed("GET /todos (200) XML").status); - // XML in response + // XML in Response Assertions.assertTrue(response.body().asString().contains("")); Assertions.assertTrue(response.body().asString().contains("")); } diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C026GetTodosAcceptJson200Test.java b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C026GetTodosAcceptJson200Test.java index eeaed330..2b60ab00 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C026GetTodosAcceptJson200Test.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C026GetTodosAcceptJson200Test.java @@ -30,7 +30,7 @@ void canGetTodosAsJSON() { statuses.get(); Assertions.assertTrue(statuses.getChallengeNamed("GET /todos (200) JSON").status); - // should be able to parse with GSON if JSON response + // should be able to parse with GSON if JSON Response new Gson().fromJson(response.body().asString(), Todos.class); } } diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C027GetTodosAcceptAnyJson200Test.java b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C027GetTodosAcceptAnyJson200Test.java index f508c4a4..311ceb60 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C027GetTodosAcceptAnyJson200Test.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C027GetTodosAcceptAnyJson200Test.java @@ -30,7 +30,7 @@ void canGetTodosAsAny() { statuses.get(); Assertions.assertTrue(statuses.getChallengeNamed("GET /todos (200) ANY").status); - // should be able to parse with GSON if JSON response by default + // should be able to parse with GSON if JSON Response by default new Gson().fromJson(response.body().asString(), Todos.class); } } diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C028GetTodosAcceptXmlPref200Test.java b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C028GetTodosAcceptXmlPref200Test.java index 6e97b5b8..a22255a8 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C028GetTodosAcceptXmlPref200Test.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C028GetTodosAcceptXmlPref200Test.java @@ -29,7 +29,7 @@ void canGetTodosAsPreferredXML() { statuses.get(); Assertions.assertTrue(statuses.getChallengeNamed("GET /todos (200) XML pref").status); - // XML in response + // XML in Response Assertions.assertTrue(response.body().asString().contains("")); Assertions.assertTrue(response.body().asString().contains("")); } diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C029GetTodosJsonNoAccept200Test.java b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C029GetTodosJsonNoAccept200Test.java index 7638bfaf..043f50bb 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C029GetTodosJsonNoAccept200Test.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C029GetTodosJsonNoAccept200Test.java @@ -32,7 +32,7 @@ void canGetTodosAsJSONWhenNoAcceptHeaderSent() { statuses.get(); Assertions.assertTrue(statuses.getChallengeNamed("GET /todos (200) no accept").status); - // should be able to parse with GSON if JSON response + // should be able to parse with GSON if JSON Response new Gson().fromJson(response.body().asString(), Todos.class); } } diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/api/ChallengesStatus.java b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/api/ChallengesStatus.java index 0bc58171..8058a5a1 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/api/ChallengesStatus.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/api/ChallengesStatus.java @@ -7,7 +7,7 @@ import java.util.List; import uk.co.compendiumdev.challenger.payloads.Challenge; import uk.co.compendiumdev.challenger.payloads.Challenges; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; public class ChallengesStatus { diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/api/RestAssuredBaseTest.java b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/api/RestAssuredBaseTest.java index 3e80ac27..f80596fa 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/api/RestAssuredBaseTest.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/api/RestAssuredBaseTest.java @@ -3,7 +3,7 @@ import io.restassured.RestAssured; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeAll; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; public class RestAssuredBaseTest { diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/api/TodosApi.java b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/api/TodosApi.java index 6cba383e..f7a931a7 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/api/TodosApi.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/api/TodosApi.java @@ -8,7 +8,7 @@ import java.util.List; import uk.co.compendiumdev.challenger.payloads.Todo; import uk.co.compendiumdev.challenger.payloads.Todos; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; public class TodosApi { public Todo createTodo(final String title, final String description, final boolean doneStatus) { diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoConfig.java b/challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoConfig.java similarity index 99% rename from challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoConfig.java rename to challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoConfig.java index 4edc6ca6..2edfd962 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoConfig.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoConfig.java @@ -1,4 +1,4 @@ -package uk.co.compendiumdev.sparkstart; +package uk.co.compendiumdev.serverstart; import java.util.ArrayList; import java.util.Collections; diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoConfigTest.java b/challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoConfigTest.java similarity index 99% rename from challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoConfigTest.java rename to challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoConfigTest.java index 4cb63e27..2d04724a 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoConfigTest.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoConfigTest.java @@ -1,4 +1,4 @@ -package uk.co.compendiumdev.sparkstart; +package uk.co.compendiumdev.serverstart; import java.util.Collections; import java.util.HashMap; diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoLocalArgsTest.java b/challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoLocalArgsTest.java similarity index 98% rename from challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoLocalArgsTest.java rename to challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoLocalArgsTest.java index 73424840..35698cce 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoLocalArgsTest.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoLocalArgsTest.java @@ -1,4 +1,4 @@ -package uk.co.compendiumdev.sparkstart; +package uk.co.compendiumdev.serverstart; import java.util.Collections; import java.util.List; diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoRunProfiles.java b/challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoRunProfiles.java similarity index 98% rename from challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoRunProfiles.java rename to challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoRunProfiles.java index 015d7f6c..8f923be5 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoRunProfiles.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoRunProfiles.java @@ -1,4 +1,4 @@ -package uk.co.compendiumdev.sparkstart; +package uk.co.compendiumdev.serverstart; import io.restassured.RestAssured; import io.restassured.http.ContentType; diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoRuntime.java b/challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoRuntime.java similarity index 99% rename from challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoRuntime.java rename to challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoRuntime.java index 4b18d076..04356582 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoRuntime.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoRuntime.java @@ -1,4 +1,4 @@ -package uk.co.compendiumdev.sparkstart; +package uk.co.compendiumdev.serverstart; import java.io.File; import java.io.IOException; diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoRuntimeHarnessCheck.java b/challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoRuntimeHarnessCheck.java similarity index 98% rename from challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoRuntimeHarnessCheck.java rename to challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoRuntimeHarnessCheck.java index 0ac85e05..fea20cfb 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/ChallengerAutoRuntimeHarnessCheck.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/ChallengerAutoRuntimeHarnessCheck.java @@ -1,4 +1,4 @@ -package uk.co.compendiumdev.sparkstart; +package uk.co.compendiumdev.serverstart; import io.restassured.RestAssured; import java.util.Collections; diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/Environment.java b/challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/Environment.java similarity index 94% rename from challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/Environment.java rename to challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/Environment.java index 5d9106d8..1e670e75 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/Environment.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/Environment.java @@ -1,4 +1,4 @@ -package uk.co.compendiumdev.sparkstart; +package uk.co.compendiumdev.serverstart; public class Environment { diff --git a/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/sparkstart/Port.java b/challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/Port.java similarity index 97% rename from standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/sparkstart/Port.java rename to challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/Port.java index 1e74ccee..81797bf7 100644 --- a/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/sparkstart/Port.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/serverstart/Port.java @@ -1,4 +1,4 @@ -package uk.co.compendiumdev.sparkstart; +package uk.co.compendiumdev.serverstart; import java.io.IOException; import java.net.InetSocketAddress; diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/simpleapi/BasicSimpleApiCrudCoverageTest.java b/challengerAuto/src/test/java/uk/co/compendiumdev/simpleapi/BasicSimpleApiCrudCoverageTest.java index 51aa8d5f..07171dcf 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/simpleapi/BasicSimpleApiCrudCoverageTest.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/simpleapi/BasicSimpleApiCrudCoverageTest.java @@ -9,9 +9,9 @@ import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import uk.co.compendiumdev.serverstart.Environment; import uk.co.compendiumdev.simpleapi.payloads.Item; import uk.co.compendiumdev.simpleapi.payloads.Items; -import uk.co.compendiumdev.sparkstart.Environment; public class BasicSimpleApiCrudCoverageTest { diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/simulator/SimulatorHttpTest.java b/challengerAuto/src/test/java/uk/co/compendiumdev/simulator/SimulatorHttpTest.java index f630d7e6..32c2f6a9 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/simulator/SimulatorHttpTest.java +++ b/challengerAuto/src/test/java/uk/co/compendiumdev/simulator/SimulatorHttpTest.java @@ -289,8 +289,8 @@ void step009_headRequestReturnsHeadersFromGet() { "Reporting-Endpoints", "Connection", "Date", - "X-Railway-Request-Id", - "x-railway-request-id", + "X-Railway-HttpServerRequest-Id", + "x-railway-HttpServerRequest-id", "x-railway-cdn-edge", "x-served-by", "date"); diff --git a/checkstyle-project-fqn.xml b/checkstyle-project-fqn.xml index 6c66ca88..af9b74f8 100644 --- a/checkstyle-project-fqn.xml +++ b/checkstyle-project-fqn.xml @@ -69,28 +69,8 @@ - - - - - - - - - - - - - - - - - - - - - - + + @@ -221,10 +201,16 @@ - - + + + + + + + + - + diff --git a/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/domain/instances/validation/EntityInstanceDraftValidator.java b/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/domain/instances/validation/EntityInstanceDraftValidator.java index e297ebf0..d4bb9597 100644 --- a/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/domain/instances/validation/EntityInstanceDraftValidator.java +++ b/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/domain/instances/validation/EntityInstanceDraftValidator.java @@ -82,7 +82,7 @@ private ValidationReport validateFieldValue( report.combine(field.validate(fieldValue, protectedWrite)); validateProtectedAutoIncrement(field, fieldValue, report); validateProtectedAutoGuid(field, fieldValue, report); - } catch (RuntimeException e) { + } catch (IllegalArgumentException e) { report.setValid(false); report.addErrorMessage( TypeValidationFailedMessageGenerator.thisValueDoesNotMatchType( @@ -100,7 +100,7 @@ private void validateProtectedAutoIncrement( try { fieldValue.asInteger(); - } catch (RuntimeException e) { + } catch (IllegalArgumentException e) { report.setValid(false); report.addErrorMessage( TypeValidationFailedMessageGenerator.thisValueDoesNotMatchType( @@ -116,7 +116,7 @@ private void validateProtectedAutoGuid( try { UUID.fromString(fieldValue.asString()); - } catch (RuntimeException e) { + } catch (IllegalArgumentException e) { report.setValid(false); report.addErrorMessage( TypeValidationFailedMessageGenerator.thisValueDoesNotMatchType( diff --git a/ercoremodel/src/test/java/uk/co/compendiumdev/thingifier/core/query/QueryFiltersBooleanTest.java b/ercoremodel/src/test/java/uk/co/compendiumdev/thingifier/core/query/QueryFiltersBooleanTest.java index c0e7c109..d3a44b87 100644 --- a/ercoremodel/src/test/java/uk/co/compendiumdev/thingifier/core/query/QueryFiltersBooleanTest.java +++ b/ercoremodel/src/test/java/uk/co/compendiumdev/thingifier/core/query/QueryFiltersBooleanTest.java @@ -18,7 +18,8 @@ public class QueryFiltersBooleanTest { // https://www.moesif.com/blog/technical/api-design/REST-API-Design-Filtering-Sorting-and-Pagination/ // https://softwareengineering.stackexchange.com/questions/233164/how-do-searches-fit-into-a-restful-interface - // TODO: risk that Spark does not pass in args in a way that flow through to repository URL + // TODO: risk that the HTTP server does not pass in args in a way that flow through to + // repository URL // query // so test this at an HTTP level as well diff --git a/pom.xml b/pom.xml index 370bd37a..71b11794 100644 --- a/pom.xml +++ b/pom.xml @@ -9,8 +9,8 @@ - 15 - 15 + 17 + 17 UTF-8 1.5.6-SNAPSHOT @@ -19,7 +19,8 @@ 3.53.2.0 2.6 5.6.2 - 16 + 17 + 7.2.2 5.5.0 2.3.1 2.0.10 diff --git a/standAloneSqlLiteTodoListManagerRestApi/src/main/java/uk/co/compendiumdev/todolist/sqlite/application/Main.java b/standAloneSqlLiteTodoListManagerRestApi/src/main/java/uk/co/compendiumdev/todolist/sqlite/application/Main.java index 6d027d4e..d2ffbd0e 100644 --- a/standAloneSqlLiteTodoListManagerRestApi/src/main/java/uk/co/compendiumdev/todolist/sqlite/application/Main.java +++ b/standAloneSqlLiteTodoListManagerRestApi/src/main/java/uk/co/compendiumdev/todolist/sqlite/application/Main.java @@ -1,8 +1,8 @@ package uk.co.compendiumdev.todolist.sqlite.application; -import static spark.Spark.get; +import static uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes.get; -import uk.co.compendiumdev.thingifier.adapter.spark.MainImplementation; +import uk.co.compendiumdev.thingifier.adapter.httpserver.MainImplementation; import uk.co.compendiumdev.thingifier.application.examples.TodoManagerThingifier; import uk.co.compendiumdev.thingifier.core.repository.sqlite.SqliteThingStoreProvider; diff --git a/standAloneTodoListManagerRestApi/src/main/java/uk/co/compendiumdev/todolist/application/Main.java b/standAloneTodoListManagerRestApi/src/main/java/uk/co/compendiumdev/todolist/application/Main.java index f67fd96b..ac18815c 100644 --- a/standAloneTodoListManagerRestApi/src/main/java/uk/co/compendiumdev/todolist/application/Main.java +++ b/standAloneTodoListManagerRestApi/src/main/java/uk/co/compendiumdev/todolist/application/Main.java @@ -1,8 +1,8 @@ package uk.co.compendiumdev.todolist.application; -import static spark.Spark.get; +import static uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes.get; -import uk.co.compendiumdev.thingifier.adapter.spark.MainImplementation; +import uk.co.compendiumdev.thingifier.adapter.httpserver.MainImplementation; import uk.co.compendiumdev.thingifier.application.examples.TodoManagerThingifier; public class Main { diff --git a/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/sparkstart/Environment.java b/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/serverstart/Environment.java similarity index 94% rename from standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/sparkstart/Environment.java rename to standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/serverstart/Environment.java index 3ba150b7..ed2b4c3d 100644 --- a/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/sparkstart/Environment.java +++ b/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/serverstart/Environment.java @@ -1,9 +1,8 @@ -package uk.co.compendiumdev.sparkstart; +package uk.co.compendiumdev.serverstart; import io.restassured.RestAssured; import io.restassured.filter.log.RequestLoggingFilter; import io.restassured.filter.log.ResponseLoggingFilter; -import spark.Spark; public class Environment { @@ -24,12 +23,11 @@ public static String getBaseUri() { // switch rest assured logging on RestAssured.filters(new RequestLoggingFilter(), new ResponseLoggingFilter()); - // if not running then start the spark + // if not running then start the server if (Port.inUse("localhost", 4567)) { return "http://localhost:4567"; } else { // start it up - Spark.port(4567); String[] args = configuredAppArgs(); if (useSqliteMemoryApp()) { diff --git a/todoManagerRestAuto/src/test/java/uk/co/compendiumdev/sparkstart/Port.java b/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/serverstart/Port.java similarity index 97% rename from todoManagerRestAuto/src/test/java/uk/co/compendiumdev/sparkstart/Port.java rename to standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/serverstart/Port.java index 1e74ccee..81797bf7 100644 --- a/todoManagerRestAuto/src/test/java/uk/co/compendiumdev/sparkstart/Port.java +++ b/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/serverstart/Port.java @@ -1,4 +1,4 @@ -package uk.co.compendiumdev.sparkstart; +package uk.co.compendiumdev.serverstart; import java.io.IOException; import java.net.InetSocketAddress; diff --git a/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/version4/api/Api.java b/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/version4/api/Api.java index 641ccce9..64b4c734 100644 --- a/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/version4/api/Api.java +++ b/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/version4/api/Api.java @@ -3,7 +3,7 @@ import io.restassured.RestAssured; import io.restassured.http.ContentType; import io.restassured.response.Response; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; public class Api { diff --git a/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/version4/projects/ProjectEntityTest.java b/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/version4/projects/ProjectEntityTest.java index ab118f4a..a75ff2e5 100644 --- a/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/version4/projects/ProjectEntityTest.java +++ b/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/version4/projects/ProjectEntityTest.java @@ -4,7 +4,7 @@ import io.restassured.response.Response; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; import uk.co.compendiumdev.version4.api.Api; import uk.co.compendiumdev.version4.api.Payloads; diff --git a/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/version4/relationships/Tasks_ProjectToTodosTest.java b/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/version4/relationships/Tasks_ProjectToTodosTest.java index 1c3f08e5..bc9a83e8 100644 --- a/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/version4/relationships/Tasks_ProjectToTodosTest.java +++ b/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/version4/relationships/Tasks_ProjectToTodosTest.java @@ -5,7 +5,7 @@ import io.restassured.response.Response; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; import uk.co.compendiumdev.version4.api.Api; import uk.co.compendiumdev.version4.api.Payloads; diff --git a/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/version4/todos/TodoEntityTest.java b/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/version4/todos/TodoEntityTest.java index af82e646..c7a49382 100644 --- a/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/version4/todos/TodoEntityTest.java +++ b/standAloneTodoListManagerRestApiAuto/src/test/java/uk/co/compendiumdev/version4/todos/TodoEntityTest.java @@ -4,7 +4,7 @@ import io.restassured.response.Response; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import uk.co.compendiumdev.sparkstart.Environment; +import uk.co.compendiumdev.serverstart.Environment; import uk.co.compendiumdev.version4.api.Api; import uk.co.compendiumdev.version4.api.Payloads; diff --git a/standAloneTodoListRestApi/src/main/java/uk/co/compendiumdev/todolist/application/Main.java b/standAloneTodoListRestApi/src/main/java/uk/co/compendiumdev/todolist/application/Main.java index 97c67116..f0060966 100644 --- a/standAloneTodoListRestApi/src/main/java/uk/co/compendiumdev/todolist/application/Main.java +++ b/standAloneTodoListRestApi/src/main/java/uk/co/compendiumdev/todolist/application/Main.java @@ -1,8 +1,8 @@ package uk.co.compendiumdev.todolist.application; -import static spark.Spark.get; +import static uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes.get; -import uk.co.compendiumdev.thingifier.adapter.spark.MainImplementation; +import uk.co.compendiumdev.thingifier.adapter.httpserver.MainImplementation; import uk.co.compendiumdev.thingifier.application.examples.TodoListThingifier; public class Main { diff --git a/thingifier-crud-ui/pom.xml b/thingifier-crud-ui/pom.xml index 8cdfd001..615130f0 100644 --- a/thingifier-crud-ui/pom.xml +++ b/thingifier-crud-ui/pom.xml @@ -38,11 +38,6 @@ examplemodels ${thingifier.version} - - com.sparkjava - spark-core - 2.8.0 - com.google.code.gson gson diff --git a/thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/ApiDocumentationPage.java b/thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/ApiDocumentationPage.java index 1581a67e..c6b15375 100644 --- a/thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/ApiDocumentationPage.java +++ b/thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/ApiDocumentationPage.java @@ -135,15 +135,15 @@ private void appendEndpoints(final StringBuilder html) { html.append( " MethodPathResultDescription\n"); html.append(" \n"); - for (RoutingDefinition route : generatedRoutes()) { + for (RoutingDefinition HttpRouteHandler : generatedRoutes()) { html.append(" ") - .append(route.verb()) + .append(HttpRouteHandler.verb()) .append("") - .append(escape(endpointPath(route))) + .append(escape(endpointPath(HttpRouteHandler))) .append("") - .append(escape(statusesFor(route))) + .append(escape(statusesFor(HttpRouteHandler))) .append("") - .append(escape(route.getDocumentation())) + .append(escape(HttpRouteHandler.getDocumentation())) .append("\n"); } html.append(" \n"); @@ -157,20 +157,22 @@ private List generatedRoutes() { List definitions = new ArrayList<>(routes.definitions()); definitions.sort( Comparator.comparing(this::endpointPath) - .thenComparing(route -> route.verb().name())); + .thenComparing(HttpRouteHandler -> HttpRouteHandler.verb().name())); return definitions; } - private String endpointPath(final RoutingDefinition route) { - return API_PREFIX + "/" + route.urlWithParamFormatter("{", "}"); + private String endpointPath(final RoutingDefinition HttpRouteHandler) { + return API_PREFIX + "/" + HttpRouteHandler.urlWithParamFormatter("{", "}"); } - private String statusesFor(final RoutingDefinition route) { - if (!route.status().isReturnedFromCall()) { - return route.status().value() + " " + route.status().description(); + private String statusesFor(final RoutingDefinition HttpRouteHandler) { + if (!HttpRouteHandler.status().isReturnedFromCall()) { + return HttpRouteHandler.status().value() + + " " + + HttpRouteHandler.status().description(); } List statuses = new ArrayList<>(); - for (RoutingStatus status : route.getPossibleStatusReponses()) { + for (RoutingStatus status : HttpRouteHandler.getPossibleStatusReponses()) { statuses.add(status.value() + " " + status.description()); } return String.join(", ", statuses); diff --git a/thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/CrudUiMain.java b/thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/CrudUiMain.java index d923afc3..e873362c 100644 --- a/thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/CrudUiMain.java +++ b/thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/CrudUiMain.java @@ -2,7 +2,7 @@ import java.io.IOException; import java.util.Map; -import uk.co.compendiumdev.thingifier.crudui.adapter.spark.CrudUiApplication; +import uk.co.compendiumdev.thingifier.crudui.adapter.javalin.CrudUiApplication; public final class CrudUiMain { diff --git a/thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/SwingProjectPathChooser.java b/thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/SwingProjectPathChooser.java index 3e051eb1..b8aca97f 100644 --- a/thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/SwingProjectPathChooser.java +++ b/thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/SwingProjectPathChooser.java @@ -2,6 +2,7 @@ import java.awt.EventQueue; import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; import java.awt.Window; import java.io.File; import java.lang.reflect.InvocationTargetException; @@ -22,7 +23,10 @@ public ProjectPathSelection choose(final ProjectActionRequest request) { } catch (InterruptedException e) { Thread.currentThread().interrupt(); return ProjectPathSelection.unavailable("Native project browsing was interrupted."); - } catch (InvocationTargetException | RuntimeException e) { + } catch (HeadlessException + | IllegalStateException + | InvocationTargetException + | SecurityException e) { return ProjectPathSelection.unavailable( "Native project browsing is unavailable: " + rootMessage(e)); } diff --git a/thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/adapter/spark/CrudUiApplication.java b/thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/adapter/javalin/CrudUiApplication.java similarity index 59% rename from thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/adapter/spark/CrudUiApplication.java rename to thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/adapter/javalin/CrudUiApplication.java index 03fd731f..2a94b404 100644 --- a/thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/adapter/spark/CrudUiApplication.java +++ b/thingifier-crud-ui/src/main/java/uk/co/compendiumdev/thingifier/crudui/adapter/javalin/CrudUiApplication.java @@ -1,11 +1,13 @@ -package uk.co.compendiumdev.thingifier.crudui.adapter.spark; +package uk.co.compendiumdev.thingifier.crudui.adapter.javalin; import java.util.Map; -import spark.Request; -import spark.Response; -import spark.Spark; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpRouteRegistry; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerRequest; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerResponse; +import uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes; +import uk.co.compendiumdev.thingifier.adapter.httpserver.conversion.HttpServerRequestToInternalHttpRequest; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpRequest; -import uk.co.compendiumdev.thingifier.adapter.spark.conversion.SparkToInternalHttpRequest; +import uk.co.compendiumdev.thingifier.adapter.javalin.JavalinHttpServer; import uk.co.compendiumdev.thingifier.crudui.ActiveThingifierWorkspace; import uk.co.compendiumdev.thingifier.crudui.CrudUiController; import uk.co.compendiumdev.thingifier.crudui.DynamicThingifierApiProxy; @@ -19,6 +21,7 @@ public final class CrudUiApplication implements AutoCloseable { private final DynamicThingifierApiProxy apiProxy; private final ResourceReader resourceReader; private final int port; + private JavalinHttpServer server; public CrudUiApplication(final ActiveThingifierWorkspace workspace, final int port) { this.workspace = workspace; @@ -29,83 +32,87 @@ public CrudUiApplication(final ActiveThingifierWorkspace workspace, final int po } public void start() { - Spark.port(port); - Spark.staticFileLocation("/public"); + HttpRouteRegistry registry = new HttpRouteRegistry(); + HttpRouteRegistry.use(registry); configureRoutes(); - Spark.awaitInitialization(); + server = new JavalinHttpServer(port, "/public", registry); + server.start(); } public void configureRoutes() { - Spark.get("/", (request, response) -> write(response, index())); - Spark.get("/schema", (request, response) -> write(response, schema())); - Spark.get("/ui/workspace", (request, response) -> write(response, controller.workspace())); - Spark.post( + ServerRoutes.get("/", (request, response) -> write(response, index())); + ServerRoutes.get("/schema", (request, response) -> write(response, schema())); + ServerRoutes.get( + "/ui/workspace", (request, response) -> write(response, controller.workspace())); + ServerRoutes.post( "/ui/model/yaml", (request, response) -> write(response, controller.loadYaml(request.body()))); - Spark.post( + ServerRoutes.post( "/ui/schema/from-yaml", (request, response) -> write(response, controller.schemaFromYaml(request.body()))); - Spark.post( + ServerRoutes.post( "/ui/schema/preview", (request, response) -> write(response, controller.previewSchema(request.body()))); - Spark.post( + ServerRoutes.post( "/ui/schema/upgrade/preview", (request, response) -> write(response, controller.previewSchemaUpgrade(request.body()))); - Spark.post( + ServerRoutes.post( "/ui/schema/upgrade/apply", (request, response) -> write(response, controller.applySchemaUpgrade(request.body()))); - Spark.get("/ui/export", (request, response) -> write(response, controller.exportData())); - Spark.post( + ServerRoutes.get( + "/ui/export", (request, response) -> write(response, controller.exportData())); + ServerRoutes.post( "/ui/import", (request, response) -> write(response, controller.importData(request.body()))); - Spark.post( + ServerRoutes.post( "/ui/project/save", (request, response) -> write(response, controller.saveProject(request.body()))); - Spark.post( + ServerRoutes.post( "/ui/project/load", (request, response) -> write(response, controller.loadProject(request.body()))); - Spark.post( + ServerRoutes.post( "/ui/project/browse", (request, response) -> write(response, controller.browseProject(request.body()))); - Spark.post( + ServerRoutes.post( "/ui/project/check", (request, response) -> write(response, controller.checkProject(request.body()))); - Spark.post( + ServerRoutes.post( "/ui/project/export-files", (request, response) -> write(response, controller.exportProjectFiles(request.body()))); - Spark.post( + ServerRoutes.post( "/ui/project/load-files", (request, response) -> write(response, controller.loadProjectFiles(request.body()))); - Spark.post( + ServerRoutes.post( "/ui/storage/switch", (request, response) -> write(response, controller.switchStorage(request.body()))); - Spark.get( + ServerRoutes.get( "/docs", (request, response) -> write(response, controller.apiDocumentationPage())); - Spark.get( + ServerRoutes.get( "/docs/swagger", (request, response) -> write( response, controller.downloadOpenApi( - request.queryParams("permissive") != null))); - Spark.get( + request.queryParam("permissive") != null))); + ServerRoutes.get( "/openapi.json", (request, response) -> write(response, controller.openApiJson())); - Spark.get("/swagger", (request, response) -> write(response, controller.swaggerUi())); + ServerRoutes.get( + "/swagger", (request, response) -> write(response, controller.swaggerUi())); - Spark.get("/api", this::forwardApi); - Spark.get("/api/*", this::forwardApi); - Spark.head("/api", this::forwardApi); - Spark.head("/api/*", this::forwardApi); - Spark.post("/api", this::forwardApi); - Spark.post("/api/*", this::forwardApi); - Spark.put("/api", this::forwardApi); - Spark.put("/api/*", this::forwardApi); - Spark.delete("/api", this::forwardApi); - Spark.delete("/api/*", this::forwardApi); + ServerRoutes.get("/api", this::forwardApi); + ServerRoutes.get("/api/*", this::forwardApi); + ServerRoutes.head("/api", this::forwardApi); + ServerRoutes.head("/api/*", this::forwardApi); + ServerRoutes.post("/api", this::forwardApi); + ServerRoutes.post("/api/*", this::forwardApi); + ServerRoutes.put("/api", this::forwardApi); + ServerRoutes.put("/api/*", this::forwardApi); + ServerRoutes.delete("/api", this::forwardApi); + ServerRoutes.delete("/api/*", this::forwardApi); } private UiHttpResponse index() { @@ -116,16 +123,17 @@ private UiHttpResponse schema() { return UiHttpResponse.html(resourceReader.read("/public/schema.html")); } - private String forwardApi(final Request request, final Response response) { - InternalHttpRequest internalRequest = SparkToInternalHttpRequest.convert(request); + private String forwardApi(final HttpServerRequest request, final HttpServerResponse response) { + InternalHttpRequest internalRequest = + HttpServerRequestToInternalHttpRequest.convert(request); return write(response, apiProxy.forward(internalRequest)); } - private String write(final Response response, final UiHttpResponse uiResponse) { + private String write(final HttpServerResponse response, final UiHttpResponse uiResponse) { response.status(uiResponse.statusCode()); response.type(uiResponse.contentType()); for (Map.Entry header : uiResponse.headers().entrySet()) { - response.raw().setHeader(header.getKey(), header.getValue()); + response.header(header.getKey(), header.getValue()); } response.body(uiResponse.body()); return uiResponse.body(); @@ -133,8 +141,11 @@ private String write(final Response response, final UiHttpResponse uiResponse) { @Override public void close() { - Spark.stop(); - Spark.awaitStop(); + if (server != null) { + server.stop(); + server = null; + } workspace.close(); + HttpRouteRegistry.clearCurrent(); } } diff --git a/thingifier-crud-ui/src/test/java/uk/co/compendiumdev/thingifier/crudui/e2e/CrudUiTestServer.java b/thingifier-crud-ui/src/test/java/uk/co/compendiumdev/thingifier/crudui/e2e/CrudUiTestServer.java index 06b41041..dd47e762 100644 --- a/thingifier-crud-ui/src/test/java/uk/co/compendiumdev/thingifier/crudui/e2e/CrudUiTestServer.java +++ b/thingifier-crud-ui/src/test/java/uk/co/compendiumdev/thingifier/crudui/e2e/CrudUiTestServer.java @@ -3,7 +3,7 @@ import java.io.IOException; import java.net.ServerSocket; import uk.co.compendiumdev.thingifier.crudui.ActiveThingifierWorkspace; -import uk.co.compendiumdev.thingifier.crudui.adapter.spark.CrudUiApplication; +import uk.co.compendiumdev.thingifier.crudui.adapter.javalin.CrudUiApplication; final class CrudUiTestServer implements AutoCloseable { diff --git a/thingifier/pom.xml b/thingifier/pom.xml index 830adbf2..097a9c52 100644 --- a/thingifier/pom.xml +++ b/thingifier/pom.xml @@ -49,9 +49,9 @@ 1.4.21 - com.sparkjava - spark-core - 2.8.0 + io.javalin + javalin + ${javalin.version} org.json diff --git a/thingifier/readme.md b/thingifier/readme.md index 2119a333..0020dc4e 100644 --- a/thingifier/readme.md +++ b/thingifier/readme.md @@ -134,8 +134,8 @@ In theory it could be split into separate modules, but these are currently repre - The API definition to model an api on top of an ER Model - Generation of a Swagger/Open API file from the API Defn/ER Model -- Internal HTTP representations to allow handling of HTTP messages independently of the chosen HTTP Server technology (Spark) -- The Spark routing generation +- Internal HTTP representations to allow handling of HTTP messages independently of the chosen HTTP Server technology +- The HTTP route registration and server adapter - The main start point for an application that wires it all together and starts the http server The intent is that it does as much as possible from the API Defn and ER Model. While supporting hooks to allow other applications to build on top of it e.g. API Challenges has hooks for tracking challenge completion but should not need to implement much of the API. diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/bootstrap/ThingifierServerBootstrap.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/bootstrap/ThingifierServerBootstrap.java index f8bd5f53..f38bc1dc 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/bootstrap/ThingifierServerBootstrap.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/bootstrap/ThingifierServerBootstrap.java @@ -1,9 +1,9 @@ package uk.co.compendiumdev.thingifier.adapter.bootstrap; import uk.co.compendiumdev.thingifier.Thingifier; -import uk.co.compendiumdev.thingifier.adapter.spark.SparkHttpGenericExceptionRoutings; -import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierAutoDocGenRouting; -import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierHttpApiRoutings; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpGenericExceptionRoutings; +import uk.co.compendiumdev.thingifier.adapter.httpserver.ThingifierAutoDocGenRouting; +import uk.co.compendiumdev.thingifier.adapter.httpserver.ThingifierHttpApiRoutings; import uk.co.compendiumdev.thingifier.api.docgen.ThingifierApiDocumentationDefn; import uk.co.compendiumdev.thingifier.htmlgui.htmlgen.DefaultGUIHTML; @@ -18,7 +18,7 @@ public ThingifierHttpApiRoutings startRestServer( new ThingifierAutoDocGenRouting(thingifier, apiDefn, guiManagement); ThingifierHttpApiRoutings restServer = new ThingifierHttpApiRoutings(thingifier, apiDefn); - new SparkHttpGenericExceptionRoutings(); + new HttpGenericExceptionRoutings(); return restServer; } diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/AdhocDocumentedSparkRouteConfigurer.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/AdhocDocumentedHttpRouteConfigurer.java similarity index 74% rename from thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/AdhocDocumentedSparkRouteConfigurer.java rename to thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/AdhocDocumentedHttpRouteConfigurer.java index 9054d682..ac124eac 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/AdhocDocumentedSparkRouteConfigurer.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/AdhocDocumentedHttpRouteConfigurer.java @@ -1,7 +1,6 @@ -package uk.co.compendiumdev.thingifier.adapter.spark; +package uk.co.compendiumdev.thingifier.adapter.httpserver; import java.util.List; -import spark.Route; import uk.co.compendiumdev.thingifier.api.docgen.RoutingDefinition; import uk.co.compendiumdev.thingifier.api.docgen.RoutingStatus; import uk.co.compendiumdev.thingifier.api.docgen.RoutingVerb; @@ -13,21 +12,21 @@ This class allows us to add adhoc Urls into the documentation which are implemented via a handler or specific status */ -public class AdhocDocumentedSparkRouteConfigurer { +public class AdhocDocumentedHttpRouteConfigurer { private final ThingifierApiDocumentationDefn apiDefn; - public AdhocDocumentedSparkRouteConfigurer(final ThingifierApiDocumentationDefn apiDefn) { + public AdhocDocumentedHttpRouteConfigurer(final ThingifierApiDocumentationDefn apiDefn) { this.apiDefn = apiDefn; } - public AdhocDocumentedSparkRouteConfigurer add( + public AdhocDocumentedHttpRouteConfigurer add( final String endpoint, final RoutingVerb verb, final int statusCode, final String documentation, - Route routeHandler) { + HttpRouteHandler routeHandler) { - SimpleSparkRouteCreator.addHandler(endpoint, verb.name(), routeHandler); + SimpleHttpRouteCreator.addHandler(endpoint, verb.name(), routeHandler); apiDefn.addRouteToDocumentation( new RoutingDefinition(verb, endpoint, RoutingStatus.returnedFromCall(), null) @@ -37,13 +36,13 @@ public AdhocDocumentedSparkRouteConfigurer add( return this; } - public AdhocDocumentedSparkRouteConfigurer add( + public AdhocDocumentedHttpRouteConfigurer add( final String endpoint, final RoutingVerb verb, final int statusCode, final String documentation) { - SimpleSparkRouteCreator.routeStatus(statusCode, endpoint, true, List.of(verb.name())); + SimpleHttpRouteCreator.routeStatus(statusCode, endpoint, true, List.of(verb.name())); apiDefn.addRouteToDocumentation( new RoutingDefinition(verb, endpoint, RoutingStatus.returnValue(statusCode), null) diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HaltRequestException.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HaltRequestException.java new file mode 100644 index 00000000..6c4ba8dc --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HaltRequestException.java @@ -0,0 +1,20 @@ +package uk.co.compendiumdev.thingifier.adapter.httpserver; + +public final class HaltRequestException extends RuntimeException { + private final int statusCode; + private final String body; + + public HaltRequestException(final int statusCode, final String body) { + super(body); + this.statusCode = statusCode; + this.body = body == null ? "" : body; + } + + public int statusCode() { + return statusCode; + } + + public String body() { + return body; + } +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpAfterHandler.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpAfterHandler.java new file mode 100644 index 00000000..7bc0e4fd --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpAfterHandler.java @@ -0,0 +1,6 @@ +package uk.co.compendiumdev.thingifier.adapter.httpserver; + +@FunctionalInterface +public interface HttpAfterHandler { + void handle(HttpServerRequest request, HttpServerResponse response) throws Exception; +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpBeforeHandler.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpBeforeHandler.java new file mode 100644 index 00000000..36518d5d --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpBeforeHandler.java @@ -0,0 +1,6 @@ +package uk.co.compendiumdev.thingifier.adapter.httpserver; + +@FunctionalInterface +public interface HttpBeforeHandler { + void handle(HttpServerRequest request, HttpServerResponse response) throws Exception; +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpGenericExceptionRoutings.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpGenericExceptionRoutings.java new file mode 100644 index 00000000..d314558a --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpGenericExceptionRoutings.java @@ -0,0 +1,20 @@ +package uk.co.compendiumdev.thingifier.adapter.httpserver; + +import java.util.List; + +public class HttpGenericExceptionRoutings { + + public HttpGenericExceptionRoutings() { + + // TODO: this is too permissive since it creates an HTTP end point that would also cover GUI + // it should only be "*" if the api config root is missing + // TODO : allow this to be overwritten by config + // nothing else is supported + + SimpleHttpRouteCreator.routeStatus( + 404, + "*", + true, + List.of("head", "get", "options", "put", "post", "patch", "delete")); + } +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpRouteDefinition.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpRouteDefinition.java new file mode 100644 index 00000000..12c06b43 --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpRouteDefinition.java @@ -0,0 +1,26 @@ +package uk.co.compendiumdev.thingifier.adapter.httpserver; + +public final class HttpRouteDefinition { + private final HttpRouteVerb verb; + private final String path; + private final HttpRouteHandler handler; + + HttpRouteDefinition( + final HttpRouteVerb verb, final String path, final HttpRouteHandler handler) { + this.verb = verb; + this.path = path; + this.handler = handler; + } + + public HttpRouteVerb verb() { + return verb; + } + + public String path() { + return path; + } + + public HttpRouteHandler handler() { + return handler; + } +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpRouteHandler.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpRouteHandler.java new file mode 100644 index 00000000..903a9134 --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpRouteHandler.java @@ -0,0 +1,6 @@ +package uk.co.compendiumdev.thingifier.adapter.httpserver; + +@FunctionalInterface +public interface HttpRouteHandler { + String handle(HttpServerRequest request, HttpServerResponse response) throws Exception; +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpRouteRegistry.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpRouteRegistry.java new file mode 100644 index 00000000..a444dd1d --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpRouteRegistry.java @@ -0,0 +1,58 @@ +package uk.co.compendiumdev.thingifier.adapter.httpserver; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public final class HttpRouteRegistry { + private static HttpRouteRegistry current; + + private final List routes; + private final List beforeHandlers; + private final List afterHandlers; + + public HttpRouteRegistry() { + this.routes = new ArrayList<>(); + this.beforeHandlers = new ArrayList<>(); + this.afterHandlers = new ArrayList<>(); + } + + public static HttpRouteRegistry current() { + if (current == null) { + current = new HttpRouteRegistry(); + } + return current; + } + + public static void use(final HttpRouteRegistry registry) { + current = registry; + } + + public static void clearCurrent() { + current = null; + } + + public void add(final HttpRouteVerb verb, final String path, final HttpRouteHandler handler) { + routes.add(new HttpRouteDefinition(verb, path, handler)); + } + + public void before(final HttpBeforeHandler handler) { + beforeHandlers.add(handler); + } + + public void after(final HttpAfterHandler handler) { + afterHandlers.add(handler); + } + + public List routes() { + return Collections.unmodifiableList(routes); + } + + public List beforeHandlers() { + return Collections.unmodifiableList(beforeHandlers); + } + + public List afterHandlers() { + return Collections.unmodifiableList(afterHandlers); + } +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpRouteVerb.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpRouteVerb.java new file mode 100644 index 00000000..26f0d9e9 --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpRouteVerb.java @@ -0,0 +1,12 @@ +package uk.co.compendiumdev.thingifier.adapter.httpserver; + +public enum HttpRouteVerb { + GET, + HEAD, + OPTIONS, + POST, + PUT, + PATCH, + DELETE, + TRACE +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpServerRequest.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpServerRequest.java new file mode 100644 index 00000000..2e4656d2 --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpServerRequest.java @@ -0,0 +1,57 @@ +package uk.co.compendiumdev.thingifier.adapter.httpserver; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public interface HttpServerRequest { + Object attribute(String name); + + void attribute(String name, Object value); + + String body(); + + String contentLength(); + + String cookie(String name); + + String header(String name); + + Set headerNames(); + + String host(); + + String ip(); + + String method(); + + String path(); + + String pathInfo(); + + default String params(final String name) { + return urlParams().get(name); + } + + String protocol(); + + String queryParam(String name); + + Set queryParamNames(); + + List queryParams(String name); + + Map> queryParamMap(); + + String queryString(); + + String scheme(); + + String splat(); + + String[] splatValues(); + + String url(); + + Map urlParams(); +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/SparkAsText.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpServerRequestAsText.java similarity index 74% rename from thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/SparkAsText.java rename to thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpServerRequestAsText.java index ed03a5f9..b1d7fba2 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/SparkAsText.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpServerRequestAsText.java @@ -1,14 +1,12 @@ -package uk.co.compendiumdev.thingifier.adapter.spark; +package uk.co.compendiumdev.thingifier.adapter.httpserver; -import spark.Request; +public class HttpServerRequestAsText { -public class SparkAsText { - - public String getRequestDetails(final Request request) { + public String getRequestDetails(final HttpServerRequest request) { StringBuilder output = new StringBuilder(); - output.append(String.format("%s %s", request.requestMethod(), request.url())); + output.append(String.format("%s %s", request.method(), request.url())); output.append("\n"); output.append("\n"); @@ -16,7 +14,7 @@ public String getRequestDetails(final Request request) { output.append("\n"); output.append("============"); output.append("\n"); - for (String queryParam : request.queryParams()) { + for (String queryParam : request.queryParamNames()) { output.append(String.format("%s: %s", queryParam, request.queryParams(queryParam))); output.append("\n"); } @@ -34,8 +32,8 @@ public String getRequestDetails(final Request request) { output.append("\n"); output.append("======="); output.append("\n"); - for (String header : request.headers()) { - output.append(String.format("%s: %s", header, request.headers(header))); + for (String header : request.headerNames()) { + output.append(String.format("%s: %s", header, request.header(header))); output.append("\n"); } output.append("\n"); diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpServerResponse.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpServerResponse.java new file mode 100644 index 00000000..77f71de3 --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/HttpServerResponse.java @@ -0,0 +1,27 @@ +package uk.co.compendiumdev.thingifier.adapter.httpserver; + +import java.util.Map; + +public interface HttpServerResponse { + String body(); + + void body(String body); + + boolean containsHeader(String name); + + void header(String name, String value); + + Map headers(); + + void redirect(String location); + + void redirect(String location, int statusCode); + + int status(); + + void status(int statusCode); + + String type(); + + void type(String contentType); +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/MainImplementation.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/MainImplementation.java similarity index 90% rename from thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/MainImplementation.java rename to thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/MainImplementation.java index 5ebfc74e..ee721632 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/MainImplementation.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/MainImplementation.java @@ -1,15 +1,15 @@ -package uk.co.compendiumdev.thingifier.adapter.spark; +package uk.co.compendiumdev.thingifier.adapter.httpserver; import java.util.HashMap; import java.util.List; import java.util.Map; -import spark.Spark; import uk.co.compendiumdev.thingifier.Thingifier; import uk.co.compendiumdev.thingifier.adapter.bootstrap.ThingifierServerBootstrap; -import uk.co.compendiumdev.thingifier.adapter.spark.messagehooks.ClearDataPreSparkRequestHook; -import uk.co.compendiumdev.thingifier.adapter.spark.messagehooks.LogTheResponseHook; -import uk.co.compendiumdev.thingifier.adapter.spark.messagehooks.LogTheSparkRequestHook; -import uk.co.compendiumdev.thingifier.adapter.spark.routehandlers.ShutdownRouteHandler; +import uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks.ClearDataPreHttpRequestHook; +import uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks.LogTheHttpRequestHook; +import uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks.LogTheResponseHook; +import uk.co.compendiumdev.thingifier.adapter.httpserver.routehandlers.ShutdownRouteHandler; +import uk.co.compendiumdev.thingifier.adapter.javalin.JavalinHttpServer; import uk.co.compendiumdev.thingifier.api.docgen.RoutingDefinition; import uk.co.compendiumdev.thingifier.api.docgen.ThingifierApiDocumentationDefn; import uk.co.compendiumdev.thingifier.apiconfig.ThingifierApiConfigProfile; @@ -35,6 +35,8 @@ public class MainImplementation implements AutoCloseable { private Thingifier thingifier; private ThingifierApiConfigProfile profileToUse; ThingifierHttpApiRoutings restServer; + private HttpRouteRegistry routeRegistry; + private JavalinHttpServer httpServer; // prevent shutdown verb as configurable through arguments e.g. -noshutdown boolean allowShutdown; // clear data every 10 minutes configurable through arguments e.g. -autocleardown @@ -51,10 +53,8 @@ public class MainImplementation implements AutoCloseable { public MainImplementation() { - proxyport = 4567; // default for spark + proxyport = 4567; // default local port - // added to support heroku as per - // https://sparktutorials.github.io/2015/08/24/spark-heroku.html // environment can override config for port if (hasHerokuAssignedPort()) { proxyport = getHerokuAssignedPort(); @@ -233,8 +233,8 @@ public void setClearDataPeriodically(boolean config, int minutes) { } public void configurePortAndDefaultRoutes() { - Spark.port(proxyport); - Spark.staticFileLocation(staticFilePath); + routeRegistry = new HttpRouteRegistry(); + HttpRouteRegistry.use(routeRegistry); } public void setupBuiltInConfigurableRoutes() { @@ -280,8 +280,11 @@ public ThingifierHttpApiRoutings startRestServer() { restServer = new ThingifierServerBootstrap().startRestServer(thingifier, apiDefn, guiManagement); - System.out.println("Running on " + Spark.port()); - System.out.println(" e.g. http://localhost:" + Spark.port()); + httpServer = new JavalinHttpServer(proxyport, staticFilePath, routeRegistry); + httpServer.start(); + + System.out.println("Running on " + proxyport); + System.out.println(" e.g. http://localhost:" + proxyport); return restServer; } @@ -290,11 +293,11 @@ public void addBuiltInArgConfiguredHooks() { if (clearDataPeriodically) { restServer.registerPreRequestHook( - new ClearDataPreSparkRequestHook(clearDownMinutes, thingifier)); + new ClearDataPreHttpRequestHook(clearDownMinutes, thingifier)); } if (verboseMode) { - restServer.registerPreRequestHook(new LogTheSparkRequestHook()); + restServer.registerPreRequestHook(new LogTheHttpRequestHook()); restServer.registerPreRequestHook(new LogTheResponseHook()); } } @@ -361,8 +364,12 @@ public ThingifierApiDocumentationDefn getApiDefn() { @Override public void close() { + if (httpServer != null) { + httpServer.stop(); + } for (Thingifier model : thingifierModels.values()) { model.close(); } + HttpRouteRegistry.clearCurrent(); } } diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/ServerRoutes.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/ServerRoutes.java new file mode 100644 index 00000000..8c10b282 --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/ServerRoutes.java @@ -0,0 +1,67 @@ +package uk.co.compendiumdev.thingifier.adapter.httpserver; + +public final class ServerRoutes { + public static final Redirect redirect = new Redirect(); + + private ServerRoutes() {} + + public static void get(final String path, final HttpRouteHandler handler) { + route(HttpRouteVerb.GET, path, handler); + } + + public static void head(final String path, final HttpRouteHandler handler) { + route(HttpRouteVerb.HEAD, path, handler); + } + + public static void options(final String path, final HttpRouteHandler handler) { + route(HttpRouteVerb.OPTIONS, path, handler); + } + + public static void post(final String path, final HttpRouteHandler handler) { + route(HttpRouteVerb.POST, path, handler); + } + + public static void put(final String path, final HttpRouteHandler handler) { + route(HttpRouteVerb.PUT, path, handler); + } + + public static void patch(final String path, final HttpRouteHandler handler) { + route(HttpRouteVerb.PATCH, path, handler); + } + + public static void delete(final String path, final HttpRouteHandler handler) { + route(HttpRouteVerb.DELETE, path, handler); + } + + public static void trace(final String path, final HttpRouteHandler handler) { + route(HttpRouteVerb.TRACE, path, handler); + } + + public static void after(final HttpAfterHandler handler) { + HttpRouteRegistry.current().after(handler); + } + + public static void before(final HttpBeforeHandler handler) { + HttpRouteRegistry.current().before(handler); + } + + public static void halt(final int statusCode, final String body) { + throw new HaltRequestException(statusCode, body); + } + + public static void route( + final HttpRouteVerb verb, final String path, final HttpRouteHandler handler) { + HttpRouteRegistry.current().add(verb, path, handler); + } + + public static final class Redirect { + public void get(final String fromPath, final String toPath) { + ServerRoutes.get( + fromPath, + (request, response) -> { + response.redirect(toPath); + return ""; + }); + } + } +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/SimpleSparkRouteCreator.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/SimpleHttpRouteCreator.java similarity index 85% rename from thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/SimpleSparkRouteCreator.java rename to thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/SimpleHttpRouteCreator.java index b95cf48d..606a3afb 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/SimpleSparkRouteCreator.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/SimpleHttpRouteCreator.java @@ -1,39 +1,37 @@ -package uk.co.compendiumdev.thingifier.adapter.spark; +package uk.co.compendiumdev.thingifier.adapter.httpserver; -import static spark.Spark.*; +import static uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes.*; import java.util.List; -import spark.Request; -import spark.Response; -import spark.Route; import uk.co.compendiumdev.thingifier.api.http.headers.headerparser.AcceptHeaderParser; /* Simple route config is a 'no code' handler for a verb it just returns the defined status code */ -public class SimpleSparkRouteCreator { +public class SimpleHttpRouteCreator { private final String endpoint; - public SimpleSparkRouteCreator(String endpoint) { + public SimpleHttpRouteCreator(String endpoint) { this.endpoint = endpoint; } - public SimpleSparkRouteCreator handledRouteStatus(final String verb, Route routeHandler) { + public SimpleHttpRouteCreator handledRouteStatus( + final String verb, HttpRouteHandler routeHandler) { addHandler(endpoint, verb, routeHandler); return this; } - public SimpleSparkRouteCreator status( + public SimpleHttpRouteCreator status( final int statusCode, boolean allowResponseIndexing, final List verbs) { routeStatus(statusCode, endpoint, allowResponseIndexing, verbs); return this; } - public SimpleSparkRouteCreator statusWhenNot( + public SimpleHttpRouteCreator statusWhenNot( final int statusCode, final List excludedVerbs) { routeStatusWhenNot(statusCode, endpoint, excludedVerbs); @@ -58,13 +56,12 @@ public static void routeStatus( // TODO: this should really reject if the the accept header is one that the main api // does not accept - Route route = - (Request request, Response result) -> { + HttpRouteHandler route = + (request, result) -> { final AcceptHeaderParser acceptParser = - new AcceptHeaderParser(request.headers("Accept")); + new AcceptHeaderParser(request.header("Accept")); String preferred = - new AcceptHeaderParser(request.headers("Accept")) - .getPreferredType(); + new AcceptHeaderParser(request.header("Accept")).getPreferredType(); if (preferred == null || preferred.trim().isEmpty() || acceptParser.willAcceptAnything()) { @@ -83,7 +80,7 @@ public static void routeStatus( } public static void addHandler( - final String endpoint, final String matchVerb, final Route route) { + final String endpoint, final String matchVerb, final HttpRouteHandler route) { switch (matchVerb.toLowerCase()) { case "get": get(endpoint, route); diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/ThingifierAutoDocGenRouting.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/ThingifierAutoDocGenRouting.java similarity index 94% rename from thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/ThingifierAutoDocGenRouting.java rename to thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/ThingifierAutoDocGenRouting.java index 640cea5f..43320ff4 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/ThingifierAutoDocGenRouting.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/ThingifierAutoDocGenRouting.java @@ -1,6 +1,6 @@ -package uk.co.compendiumdev.thingifier.adapter.spark; +package uk.co.compendiumdev.thingifier.adapter.httpserver; -import static spark.Spark.get; +import static uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes.get; import uk.co.compendiumdev.thingifier.Thingifier; import uk.co.compendiumdev.thingifier.api.docgen.ApiRoutingDefinition; @@ -46,7 +46,7 @@ public ThingifierAutoDocGenRouting( get( "%s/docs/swagger".formatted(apiDefn.getPathPrefix()), (request, response) -> { - String permissive = request.queryParams("permissive"); + String permissive = request.queryParam("permissive"); response.type("text/html"); response.status(200); diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/ThingifierHttpApiRoutings.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/ThingifierHttpApiRoutings.java similarity index 86% rename from thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/ThingifierHttpApiRoutings.java rename to thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/ThingifierHttpApiRoutings.java index d55502b9..202e1206 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/ThingifierHttpApiRoutings.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/ThingifierHttpApiRoutings.java @@ -1,22 +1,21 @@ -package uk.co.compendiumdev.thingifier.adapter.spark; +package uk.co.compendiumdev.thingifier.adapter.httpserver; -import static spark.Spark.*; +import static uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes.*; import java.util.ArrayList; import java.util.List; -import spark.Request; import uk.co.compendiumdev.thingifier.Thingifier; import uk.co.compendiumdev.thingifier.adapter.http.messagehooks.HttpApiRequestHook; import uk.co.compendiumdev.thingifier.adapter.http.messagehooks.HttpApiResponseHook; +import uk.co.compendiumdev.thingifier.adapter.httpserver.conversion.HttpServerRequestToInternalHttpRequest; +import uk.co.compendiumdev.thingifier.adapter.httpserver.conversion.HttpServerResponseToInternalHttpResponse; +import uk.co.compendiumdev.thingifier.adapter.httpserver.conversion.InternalHttpResponseToHttpServer; +import uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks.HttpRequestResponseHook; +import uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks.InternalHttpRequestHook; +import uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks.InternalHttpResponseHook; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpRequest; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpResponse; import uk.co.compendiumdev.thingifier.adapter.internalhttp.conversion.ThingifierHttpApiBridge; -import uk.co.compendiumdev.thingifier.adapter.spark.conversion.InternalHttpResponseToSpark; -import uk.co.compendiumdev.thingifier.adapter.spark.conversion.SparkResponseToInternalHttpResponse; -import uk.co.compendiumdev.thingifier.adapter.spark.conversion.SparkToInternalHttpRequest; -import uk.co.compendiumdev.thingifier.adapter.spark.messagehooks.InternalHttpRequestHook; -import uk.co.compendiumdev.thingifier.adapter.spark.messagehooks.InternalHttpResponseHook; -import uk.co.compendiumdev.thingifier.adapter.spark.messagehooks.SparkRequestResponseHook; import uk.co.compendiumdev.thingifier.api.docgen.ApiRoutingDefinition; import uk.co.compendiumdev.thingifier.api.docgen.ApiRoutingDefinitionDocGenerator; import uk.co.compendiumdev.thingifier.api.docgen.RoutingDefinition; @@ -27,8 +26,8 @@ public class ThingifierHttpApiRoutings { private static final String INTERNAL_HTTP_REQUEST_ATTRIBUTE = "thingifier.internalHttpRequest"; // private String urlPath; - private List preSparkHttpRequestHooks; - private List postSparkHttpResponseHooks; + private List preHttpRequestHooks; + private List postHttpResponseHooks; private List preInternalHttpRequestHooks; private List postInternalHttpResponseHooks; private List httpApiRequestHooks; @@ -39,10 +38,10 @@ public class ThingifierHttpApiRoutings { public ThingifierHttpApiRoutings( final Thingifier thingifier, ThingifierApiDocumentationDefn apiDefn) { - // hooks that take Spark request and responses pre and post the http message receipt / + // hooks that take httpserver request and responses pre and post the http message receipt / // sending - preSparkHttpRequestHooks = new ArrayList<>(); - postSparkHttpResponseHooks = new ArrayList<>(); + preHttpRequestHooks = new ArrayList<>(); + postHttpResponseHooks = new ArrayList<>(); // hooks that take internal representations of HTTP pre and post preInternalHttpRequestHooks = new ArrayList<>(); @@ -71,9 +70,9 @@ public ThingifierHttpApiRoutings( // } // } - // Run any hooks at the Spark Request and Response level - if (preSparkHttpRequestHooks != null) { - for (SparkRequestResponseHook hook : preSparkHttpRequestHooks) { + // Run any hooks at the HTTP server request and response level. + if (preHttpRequestHooks != null) { + for (HttpRequestResponseHook hook : preHttpRequestHooks) { // todo: catch exceptions and `halt` hook.run(request, response); } @@ -86,7 +85,7 @@ public ThingifierHttpApiRoutings( // todo: catch exceptions and `halt` InternalHttpResponse hookResponse = hook.run(iRequest); if (hookResponse != null) { - InternalHttpResponseToSpark.convert(hookResponse, response); + InternalHttpResponseToHttpServer.convert(hookResponse, response); halt(hookResponse.getStatusCode(), hookResponse.getBody()); } } @@ -100,7 +99,7 @@ public ThingifierHttpApiRoutings( // on this iRequest and iResponse InternalHttpRequest iRequest = internalRequestFrom(request); InternalHttpResponse iResponse = - SparkResponseToInternalHttpResponse.convert(response); + HttpServerResponseToInternalHttpResponse.convert(response); // now run the HttpApiRequestHook hooks on this iRequest if (postInternalHttpResponseHooks != null) { @@ -110,11 +109,11 @@ public ThingifierHttpApiRoutings( } } - SparkResponseToInternalHttpResponse.updateResponseFromInternal( + HttpServerResponseToInternalHttpResponse.updateResponseFromInternal( response, iResponse); - if (postSparkHttpResponseHooks != null) { - for (SparkRequestResponseHook hook : postSparkHttpResponseHooks) { + if (postHttpResponseHooks != null) { + for (HttpRequestResponseHook hook : postHttpResponseHooks) { // todo: catch exceptions and let the response return hook.run(request, response); } @@ -147,7 +146,7 @@ public ThingifierHttpApiRoutings( final InternalHttpResponse theResponse = apiBridge.get(theRequest); // TODO: similarly allow amending the response from the API - return InternalHttpResponseToSpark.convert( + return InternalHttpResponseToHttpServer.convert( theResponse, response); }); } @@ -162,7 +161,7 @@ public ThingifierHttpApiRoutings( internalRequestFrom(request); final InternalHttpResponse theResponse = apiBridge.post(theRequest); - return InternalHttpResponseToSpark.convert( + return InternalHttpResponseToHttpServer.convert( theResponse, response); }); } @@ -179,7 +178,7 @@ public ThingifierHttpApiRoutings( internalRequestFrom(request); final InternalHttpResponse theResponse = apiBridge.head(theRequest); - return InternalHttpResponseToSpark.convert( + return InternalHttpResponseToHttpServer.convert( theResponse, response); }); } @@ -201,7 +200,7 @@ public ThingifierHttpApiRoutings( internalRequestFrom(request); final InternalHttpResponse theResponse = apiBridge.delete(theRequest); - return InternalHttpResponseToSpark.convert( + return InternalHttpResponseToHttpServer.convert( theResponse, response); }); } @@ -233,7 +232,7 @@ public ThingifierHttpApiRoutings( internalRequestFrom(request); final InternalHttpResponse theResponse = apiBridge.put(theRequest); - return InternalHttpResponseToSpark.convert( + return InternalHttpResponseToHttpServer.convert( theResponse, response); }); } @@ -270,8 +269,8 @@ public ThingifierHttpApiRoutings( // return apiBridge.query(request, response, request.splat()[0]); final InternalHttpRequest theRequest = internalRequestFrom(request); final InternalHttpResponse theResponse = - apiBridge.query(theRequest, request.splat()[0]); - return InternalHttpResponseToSpark.convert(theResponse, response); + apiBridge.query(theRequest, request.splat()); + return InternalHttpResponseToHttpServer.convert(theResponse, response); }); } @@ -288,7 +287,7 @@ public ThingifierHttpApiRoutings( // create an API end point level 404 handler if (apiDefn.getPathPrefix() != null && !apiDefn.getPathPrefix().isEmpty()) { - SimpleSparkRouteCreator.routeStatus( + SimpleHttpRouteCreator.routeStatus( 404, apiDefn.getPathPrefix() + "/*", true, @@ -296,14 +295,14 @@ public ThingifierHttpApiRoutings( } } - public void registerPreRequestHook(final SparkRequestResponseHook hook) { + public void registerPreRequestHook(final HttpRequestResponseHook hook) { // pre-request hooks run pre-every-request - preSparkHttpRequestHooks.add(hook); + preHttpRequestHooks.add(hook); } - public void registerPostResponseHook(final SparkRequestResponseHook hook) { + public void registerPostResponseHook(final HttpRequestResponseHook hook) { // post-request hooks run after-every-response - postSparkHttpResponseHooks.add(hook); + postHttpResponseHooks.add(hook); } /* @@ -334,14 +333,15 @@ public void registerInternalHttpRequestHook(final InternalHttpRequestHook hook) preInternalHttpRequestHooks.add(hook); } - private InternalHttpRequest internalRequestFrom(final Request request) { + private InternalHttpRequest internalRequestFrom(final HttpServerRequest request) { Object existingRequest = request.attribute(INTERNAL_HTTP_REQUEST_ATTRIBUTE); if (existingRequest instanceof InternalHttpRequest) { return (InternalHttpRequest) existingRequest; } - InternalHttpRequest internalRequest = SparkToInternalHttpRequest.convert(request); + InternalHttpRequest internalRequest = + HttpServerRequestToInternalHttpRequest.convert(request); request.attribute(INTERNAL_HTTP_REQUEST_ATTRIBUTE, internalRequest); return internalRequest; } diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/conversion/HttpServerRequestToInternalHttpRequest.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/conversion/HttpServerRequestToInternalHttpRequest.java new file mode 100644 index 00000000..e2aef990 --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/conversion/HttpServerRequestToInternalHttpRequest.java @@ -0,0 +1,40 @@ +package uk.co.compendiumdev.thingifier.adapter.httpserver.conversion; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerRequest; +import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpRequest; + +public final class HttpServerRequestToInternalHttpRequest { + + private HttpServerRequestToInternalHttpRequest() {} + + public static InternalHttpRequest convert(final HttpServerRequest request) { + InternalHttpRequest internalRequest = + new InternalHttpRequest(request.pathInfo()) + .setBody(request.body()) + .setQueryParams(queryParamsAsMap(request)) + .setRawQueryString(request.queryString()) + .setMethod(request.method()) + .setUrl(request.url()) + .setIP(request.ip()) + .setUrlParams(request.urlParams()); + + addRawHeaders(internalRequest, request); + + return internalRequest; + } + + private static void addRawHeaders( + final InternalHttpRequest internalRequest, final HttpServerRequest request) { + + for (String headerName : request.headerNames()) { + internalRequest.addHeader(headerName, request.header(headerName)); + } + } + + private static Map> queryParamsAsMap(final HttpServerRequest request) { + return new LinkedHashMap<>(request.queryParamMap()); + } +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/conversion/HttpServerResponseToInternalHttpResponse.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/conversion/HttpServerResponseToInternalHttpResponse.java new file mode 100644 index 00000000..05b755de --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/conversion/HttpServerResponseToInternalHttpResponse.java @@ -0,0 +1,26 @@ +package uk.co.compendiumdev.thingifier.adapter.httpserver.conversion; + +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerResponse; +import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpResponse; + +public class HttpServerResponseToInternalHttpResponse { + + public static InternalHttpResponse convert(HttpServerResponse response) { + InternalHttpResponse internalResponse = new InternalHttpResponse(); + + internalResponse.setStatus(response.status()); + internalResponse.setType(response.type()); // content type + internalResponse.setBody(response.body()); + + for (String headerName : response.headers().keySet()) { + internalResponse.setHeader(headerName, response.headers().get(headerName)); + } + + return internalResponse; + } + + public static void updateResponseFromInternal( + final HttpServerResponse response, final InternalHttpResponse httpResponse) { + InternalHttpResponseToHttpServer.updateResponseFromInternal(response, httpResponse); + } +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/conversion/InternalHttpResponseToSpark.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/conversion/InternalHttpResponseToHttpServer.java similarity index 55% rename from thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/conversion/InternalHttpResponseToSpark.java rename to thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/conversion/InternalHttpResponseToHttpServer.java index 43bc19ee..15684a17 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/conversion/InternalHttpResponseToSpark.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/conversion/InternalHttpResponseToHttpServer.java @@ -1,21 +1,21 @@ -package uk.co.compendiumdev.thingifier.adapter.spark.conversion; +package uk.co.compendiumdev.thingifier.adapter.httpserver.conversion; import java.util.Map; -import spark.Response; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerResponse; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpResponse; -public final class InternalHttpResponseToSpark { +public final class InternalHttpResponseToHttpServer { - private InternalHttpResponseToSpark() {} + private InternalHttpResponseToHttpServer() {} public static String convert( - final InternalHttpResponse internalResponse, final Response response) { + final InternalHttpResponse internalResponse, final HttpServerResponse response) { updateResponseFromInternal(response, internalResponse); return internalResponse.getBody(); } public static void updateResponseFromInternal( - final Response response, final InternalHttpResponse httpResponse) { + final HttpServerResponse response, final InternalHttpResponse httpResponse) { response.status(httpResponse.getStatusCode()); @@ -23,10 +23,10 @@ public static void updateResponseFromInternal( response.type(httpResponse.getType()); } + response.body(httpResponse.getBody()); + for (Map.Entry header : httpResponse.getHeaders().asMap().entrySet()) { - response.raw().setHeader(header.getKey(), header.getValue()); + response.header(header.getKey(), header.getValue()); } - - response.body(httpResponse.getBody()); } } diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/ClearDataPreSparkRequestHook.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/ClearDataPreHttpRequestHook.java similarity index 65% rename from thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/ClearDataPreSparkRequestHook.java rename to thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/ClearDataPreHttpRequestHook.java index 6a49c491..38b5a6e5 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/ClearDataPreSparkRequestHook.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/ClearDataPreHttpRequestHook.java @@ -1,23 +1,23 @@ -package uk.co.compendiumdev.thingifier.adapter.spark.messagehooks; +package uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks; -import spark.Request; -import spark.Response; import uk.co.compendiumdev.thingifier.Thingifier; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerRequest; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerResponse; import uk.co.compendiumdev.thingifier.core.EntityRelModel; -public class ClearDataPreSparkRequestHook implements SparkRequestResponseHook { +public class ClearDataPreHttpRequestHook implements HttpRequestResponseHook { private long lastReset; private final Thingifier thingifier; private final long maxgap; - public ClearDataPreSparkRequestHook(final int minutes, Thingifier thingifier) { + public ClearDataPreHttpRequestHook(final int minutes, Thingifier thingifier) { this.lastReset = System.currentTimeMillis(); this.thingifier = thingifier; this.maxgap = minutes * 60 * 1000; } @Override - public void run(final Request request, final Response response) { + public void run(final HttpServerRequest request, final HttpServerResponse response) { long currentTime = System.currentTimeMillis(); long gap = currentTime - lastReset; if (gap > maxgap) { diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/HttpRequestResponseHook.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/HttpRequestResponseHook.java new file mode 100644 index 00000000..f98bbdbf --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/HttpRequestResponseHook.java @@ -0,0 +1,13 @@ +package uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks; + +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerRequest; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerResponse; + +/** + * HttpRequestResponseHook (s) are run prior to any processing. They work directly on the httpserver + * request and httpserver responses + */ +public interface HttpRequestResponseHook { + // throw an exception if we want to 'stop' the request and return the response + void run(HttpServerRequest request, HttpServerResponse response); +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/InternalHttpRequestHook.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/InternalHttpRequestHook.java similarity index 82% rename from thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/InternalHttpRequestHook.java rename to thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/InternalHttpRequestHook.java index afe33700..73503a7a 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/InternalHttpRequestHook.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/InternalHttpRequestHook.java @@ -1,4 +1,4 @@ -package uk.co.compendiumdev.thingifier.adapter.spark.messagehooks; +package uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpRequest; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpResponse; diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/InternalHttpResponseHook.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/InternalHttpResponseHook.java similarity index 83% rename from thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/InternalHttpResponseHook.java rename to thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/InternalHttpResponseHook.java index a1aa4ec5..02eb06b0 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/InternalHttpResponseHook.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/InternalHttpResponseHook.java @@ -1,4 +1,4 @@ -package uk.co.compendiumdev.thingifier.adapter.spark.messagehooks; +package uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpRequest; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpResponse; diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/LogTheHttpRequestHook.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/LogTheHttpRequestHook.java new file mode 100644 index 00000000..87432ebd --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/LogTheHttpRequestHook.java @@ -0,0 +1,20 @@ +package uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks; + +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerRequest; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerResponse; + +public class LogTheHttpRequestHook implements HttpRequestResponseHook { + @Override + public void run(final HttpServerRequest request, final HttpServerResponse response) { + try { + + System.out.println("**REQUEST**"); + System.out.println(request.url()); + System.out.println(request.pathInfo()); + System.out.println(request.body()); + + } catch (Exception e) { + System.out.println(e); + } + } +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/LogTheResponseHook.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/LogTheResponseHook.java new file mode 100644 index 00000000..d19d7485 --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/messagehooks/LogTheResponseHook.java @@ -0,0 +1,17 @@ +package uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks; + +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerRequest; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerResponse; + +public class LogTheResponseHook implements HttpRequestResponseHook { + @Override + public void run(final HttpServerRequest request, final HttpServerResponse response) { + try { + System.out.println("**RESPONSE**"); + System.out.println(response.status()); + System.out.println(response.body()); + } catch (Exception e) { + System.out.println(e); + } + } +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/routehandlers/SparkApiRequestResponseHandler.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/routehandlers/HttpApiRequestResponseHandler.java similarity index 68% rename from thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/routehandlers/SparkApiRequestResponseHandler.java rename to thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/routehandlers/HttpApiRequestResponseHandler.java index d39816de..c46868d8 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/routehandlers/SparkApiRequestResponseHandler.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/routehandlers/HttpApiRequestResponseHandler.java @@ -1,14 +1,14 @@ -package uk.co.compendiumdev.thingifier.adapter.spark.routehandlers; +package uk.co.compendiumdev.thingifier.adapter.httpserver.routehandlers; -import spark.Request; -import spark.Response; import uk.co.compendiumdev.thingifier.Thingifier; import uk.co.compendiumdev.thingifier.adapter.http.routehandlers.HttpApiRequestHandler; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerRequest; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerResponse; +import uk.co.compendiumdev.thingifier.adapter.httpserver.conversion.HttpServerRequestToInternalHttpRequest; +import uk.co.compendiumdev.thingifier.adapter.httpserver.conversion.InternalHttpResponseToHttpServer; import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpRequest; import uk.co.compendiumdev.thingifier.adapter.internalhttp.conversion.HttpApiResponseToInternalHttpResponse; import uk.co.compendiumdev.thingifier.adapter.internalhttp.conversion.InternalHttpRequestToHttpApiRequest; -import uk.co.compendiumdev.thingifier.adapter.spark.conversion.InternalHttpResponseToSpark; -import uk.co.compendiumdev.thingifier.adapter.spark.conversion.SparkToInternalHttpRequest; import uk.co.compendiumdev.thingifier.api.ermodelconversion.JsonThing; import uk.co.compendiumdev.thingifier.api.http.HttpApiRequest; import uk.co.compendiumdev.thingifier.api.http.HttpApiResponse; @@ -16,35 +16,38 @@ import uk.co.compendiumdev.thingifier.api.http.ThingifierRequestContext; import uk.co.compendiumdev.thingifier.api.response.ApiResponse; -public class SparkApiRequestResponseHandler { - private final Request request; - private final Response response; +public class HttpApiRequestResponseHandler { + private final HttpServerRequest request; + private final HttpServerResponse response; private final Thingifier thingifier; private final ThingifierHttpApi httpApi; private HttpApiRequestHandler handler; private boolean validate = true; // validate message by default - public SparkApiRequestResponseHandler( - final Request request, final Response result, final Thingifier thingifier) { + public HttpApiRequestResponseHandler( + final HttpServerRequest request, + final HttpServerResponse result, + final Thingifier thingifier) { this.request = request; this.response = result; this.thingifier = thingifier; this.httpApi = new ThingifierHttpApi(thingifier); } - public SparkApiRequestResponseHandler usingHandler(final HttpApiRequestHandler handler) { + public HttpApiRequestResponseHandler usingHandler(final HttpApiRequestHandler handler) { this.handler = handler; return this; } - public SparkApiRequestResponseHandler validateRequestSyntax(boolean shouldValidate) { + public HttpApiRequestResponseHandler validateRequestSyntax(boolean shouldValidate) { this.validate = shouldValidate; return this; } public String handle() { - final InternalHttpRequest internalRequest = SparkToInternalHttpRequest.convert(request); + final InternalHttpRequest internalRequest = + HttpServerRequestToInternalHttpRequest.convert(request); final HttpApiRequest myRequest = InternalHttpRequestToHttpApiRequest.convert(internalRequest); @@ -68,7 +71,7 @@ public String handle() { myRequest.getHeaders(), apiResponse, jsonThing, thingifier.apiConfig()); } - return InternalHttpResponseToSpark.convert( + return InternalHttpResponseToHttpServer.convert( HttpApiResponseToInternalHttpResponse.convert(httpApiResponse), response); } } diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/routehandlers/ShutdownRouteHandler.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/routehandlers/ShutdownRouteHandler.java similarity index 89% rename from thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/routehandlers/ShutdownRouteHandler.java rename to thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/routehandlers/ShutdownRouteHandler.java index b402d180..270caa1b 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/routehandlers/ShutdownRouteHandler.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/httpserver/routehandlers/ShutdownRouteHandler.java @@ -1,6 +1,6 @@ -package uk.co.compendiumdev.thingifier.adapter.spark.routehandlers; +package uk.co.compendiumdev.thingifier.adapter.httpserver.routehandlers; -import static spark.Spark.get; +import static uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes.get; import java.util.ArrayList; import java.util.List; diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinHttpServer.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinHttpServer.java new file mode 100644 index 00000000..936c751f --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinHttpServer.java @@ -0,0 +1,163 @@ +package uk.co.compendiumdev.thingifier.adapter.javalin; + +import io.javalin.Javalin; +import io.javalin.http.Context; +import io.javalin.http.HandlerType; +import io.javalin.http.staticfiles.Location; +import java.nio.charset.StandardCharsets; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HaltRequestException; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpAfterHandler; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpBeforeHandler; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpRouteDefinition; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpRouteRegistry; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpRouteVerb; +import uk.co.compendiumdev.thingifier.api.response.ApiResponseError; + +public final class JavalinHttpServer implements AutoCloseable { + private final int port; + private final String staticFilePath; + private final HttpRouteRegistry registry; + private Javalin app; + + public JavalinHttpServer( + final int port, final String staticFilePath, final HttpRouteRegistry registry) { + this.port = port; + this.staticFilePath = staticFilePath; + this.registry = registry; + } + + public void start() { + app = + Javalin.create( + config -> { + config.router.ignoreTrailingSlashes = false; + config.staticFiles.add( + staticFiles -> { + staticFiles.hostedPath = "/"; + staticFiles.directory = staticFilePath; + staticFiles.location = Location.CLASSPATH; + }); + for (HttpBeforeHandler beforeHandler : registry.beforeHandlers()) { + config.routes.before(ctx -> runBefore(ctx, beforeHandler)); + } + for (HttpRouteDefinition route : registry.routes()) { + config.routes.addHttpHandler( + handlerType(route.verb()), + javalinPath(route.path()), + ctx -> handle(ctx, route)); + } + for (HttpAfterHandler afterHandler : registry.afterHandlers()) { + config.routes.after(ctx -> runAfter(ctx, afterHandler)); + } + config.routes.after(this::restoreExactContentType); + config.routes.exception( + HaltRequestException.class, + (e, ctx) -> { + ctx.status(e.statusCode()); + ctx.result(e.body().getBytes(StandardCharsets.UTF_8)); + }); + config.routes.exception( + RuntimeException.class, + (e, ctx) -> { + ctx.status(400); + ctx.result( + exceptionErrorResponse(e, ctx) + .getBytes(StandardCharsets.UTF_8)); + }); + config.routes.exception( + Exception.class, + (e, ctx) -> { + ctx.status(500); + ctx.result( + exceptionErrorResponse(e, ctx) + .getBytes(StandardCharsets.UTF_8)); + }); + }); + app.start(port); + } + + public void stop() { + if (app != null) { + app.stop(); + app = null; + } + } + + public int port() { + return port; + } + + private void handle(final Context ctx, final HttpRouteDefinition route) throws Exception { + ctx.attribute(JavalinServerRequest.ROUTE_PATH_ATTRIBUTE, route.path()); + JavalinServerRequest request = new JavalinServerRequest(ctx); + JavalinServerResponse response = new JavalinServerResponse(ctx); + String body = route.handler().handle(request, response); + if (body != null && !response.wasBodySet()) { + ctx.attribute(JavalinServerResponse.RESPONSE_BODY_ATTRIBUTE, body); + ctx.result(body.getBytes(StandardCharsets.UTF_8)); + } + } + + private void runBefore(final Context ctx, final HttpBeforeHandler beforeHandler) + throws Exception { + beforeHandler.handle(new JavalinServerRequest(ctx), new JavalinServerResponse(ctx)); + } + + private void runAfter(final Context ctx, final HttpAfterHandler afterHandler) throws Exception { + afterHandler.handle(new JavalinServerRequest(ctx), new JavalinServerResponse(ctx)); + } + + private void restoreExactContentType(final Context ctx) { + String contentType = ctx.res().getHeader("Content-Type"); + if (contentType != null && contentType.endsWith(";charset=utf-8")) { + String exactContentType = + contentType.substring(0, contentType.length() - ";charset=utf-8".length()); + ctx.res().setCharacterEncoding(null); + ctx.res().setContentType(exactContentType); + ctx.res().setHeader("Content-Type", exactContentType); + } + } + + private HandlerType handlerType(final HttpRouteVerb verb) { + switch (verb) { + case GET: + return HandlerType.GET; + case HEAD: + return HandlerType.HEAD; + case OPTIONS: + return HandlerType.OPTIONS; + case POST: + return HandlerType.POST; + case PUT: + return HandlerType.PUT; + case PATCH: + return HandlerType.PATCH; + case DELETE: + return HandlerType.DELETE; + case TRACE: + return HandlerType.TRACE; + default: + return HandlerType.GET; + } + } + + private String javalinPath(final String routePath) { + if (routePath == null || routePath.isBlank() || "*".equals(routePath)) { + return "/*"; + } + + String converted = routePath.trim(); + converted = converted.replaceAll(":([A-Za-z][A-Za-z0-9_]*)", "{$1}"); + return converted; + } + + private String exceptionErrorResponse(final Exception e, final Context ctx) { + String message = e.getMessage() == null ? e.toString() : e.getMessage(); + return ApiResponseError.asAppropriate(ctx.header("Accept"), message); + } + + @Override + public void close() { + stop(); + } +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinServerRequest.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinServerRequest.java new file mode 100644 index 00000000..901ac544 --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinServerRequest.java @@ -0,0 +1,149 @@ +package uk.co.compendiumdev.thingifier.adapter.javalin; + +import io.javalin.http.Context; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerRequest; + +final class JavalinServerRequest implements HttpServerRequest { + static final String ROUTE_PATH_ATTRIBUTE = "thingifier.route.path"; + + private final Context context; + + JavalinServerRequest(final Context context) { + this.context = context; + } + + @Override + public Object attribute(final String name) { + return context.attribute(name); + } + + @Override + public void attribute(final String name, final Object value) { + context.attribute(name, value); + } + + @Override + public String body() { + return context.body(); + } + + @Override + public String contentLength() { + return context.header("Content-Length"); + } + + @Override + public String cookie(final String name) { + return context.cookie(name); + } + + @Override + public String header(final String name) { + return context.header(name); + } + + @Override + public Set headerNames() { + return new LinkedHashSet<>(context.headerMap().keySet()); + } + + @Override + public String host() { + return context.host(); + } + + @Override + public String ip() { + return context.ip(); + } + + @Override + public String method() { + return context.method().name(); + } + + @Override + public String path() { + return context.path(); + } + + @Override + public String pathInfo() { + return context.path(); + } + + @Override + public String protocol() { + return context.protocol(); + } + + @Override + public String queryParam(final String name) { + return context.queryParam(name); + } + + @Override + public Set queryParamNames() { + return new LinkedHashSet<>(context.queryParamMap().keySet()); + } + + @Override + public List queryParams(final String name) { + return context.queryParams(name); + } + + @Override + public Map> queryParamMap() { + return new LinkedHashMap<>(context.queryParamMap()); + } + + @Override + public String queryString() { + return context.queryString(); + } + + @Override + public String scheme() { + return context.scheme(); + } + + @Override + public String splat() { + String routePath = context.attribute(ROUTE_PATH_ATTRIBUTE); + if (routePath == null || !routePath.endsWith("/*")) { + return ""; + } + + String prefix = routePath.substring(0, routePath.length() - 1); + String path = context.path(); + if (path.startsWith(prefix)) { + return path.substring(prefix.length()); + } + return ""; + } + + @Override + public String[] splatValues() { + return new String[] {splat()}; + } + + @Override + public String url() { + return context.url(); + } + + @Override + public Map urlParams() { + Map params = new LinkedHashMap<>(); + for (Map.Entry param : context.pathParamMap().entrySet()) { + params.put(param.getKey(), param.getValue()); + params.put(":" + param.getKey(), param.getValue()); + } + return params; + } +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinServerResponse.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinServerResponse.java new file mode 100644 index 00000000..a6409790 --- /dev/null +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinServerResponse.java @@ -0,0 +1,85 @@ +package uk.co.compendiumdev.thingifier.adapter.javalin; + +import io.javalin.http.Context; +import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; +import java.util.Map; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerResponse; + +final class JavalinServerResponse implements HttpServerResponse { + static final String RESPONSE_BODY_ATTRIBUTE = "thingifier.response.body"; + + private final Context context; + private boolean bodySet; + + JavalinServerResponse(final Context context) { + this.context = context; + } + + @Override + public String body() { + String body = context.attribute(RESPONSE_BODY_ATTRIBUTE); + return body == null ? context.result() : body; + } + + @Override + public void body(final String body) { + bodySet = true; + context.attribute(RESPONSE_BODY_ATTRIBUTE, body == null ? "" : body); + context.result((body == null ? "" : body).getBytes(StandardCharsets.UTF_8)); + } + + @Override + public boolean containsHeader(final String name) { + return context.res().containsHeader(name); + } + + @Override + public void header(final String name, final String value) { + context.header(name, value); + } + + @Override + public Map headers() { + Map headers = new LinkedHashMap<>(); + for (String name : context.res().getHeaderNames()) { + headers.put(name, context.res().getHeader(name)); + } + return headers; + } + + @Override + public void redirect(final String location) { + context.redirect(location); + } + + @Override + public void redirect(final String location, final int statusCode) { + context.status(statusCode); + context.header("Location", location); + } + + @Override + public int status() { + return context.statusCode(); + } + + @Override + public void status(final int statusCode) { + context.status(statusCode); + } + + @Override + public String type() { + return context.header("Content-Type"); + } + + @Override + public void type(final String contentType) { + context.header("Content-Type", contentType); + } + + boolean wasBodySet() { + return bodySet; + } +} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/SparkHttpGenericExceptionRoutings.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/SparkHttpGenericExceptionRoutings.java deleted file mode 100644 index b987f102..00000000 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/SparkHttpGenericExceptionRoutings.java +++ /dev/null @@ -1,46 +0,0 @@ -package uk.co.compendiumdev.thingifier.adapter.spark; - -import static spark.Spark.exception; - -import java.util.List; -import spark.Request; -import uk.co.compendiumdev.thingifier.api.response.ApiResponseError; - -public class SparkHttpGenericExceptionRoutings { - - public SparkHttpGenericExceptionRoutings() { - - // TODO: this is too permissive since it creates an HTTP end point that would also cover GUI - // it should only be "*" if the api config root is missing - // TODO : allow this to be overwritten by config - // nothing else is supported - - SimpleSparkRouteCreator.routeStatus( - 404, - "*", - true, - List.of("head", "get", "options", "put", "post", "patch", "delete")); - - exception( - RuntimeException.class, - (e, request, response) -> { - response.status(400); - response.body(getExceptionErrorResponse(e, request)); - }); - - exception( - Exception.class, - (e, request, response) -> { - response.status(500); - response.body(getExceptionErrorResponse(e, request)); - }); - } - - private String getExceptionErrorResponse(final Exception e, final Request request) { - if (e.getMessage() == null) { - return ApiResponseError.asAppropriate(request.headers("Accept"), e.toString()); - } else { - return ApiResponseError.asAppropriate(request.headers("Accept"), e.getMessage()); - } - } -} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/conversion/SparkResponseToInternalHttpResponse.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/conversion/SparkResponseToInternalHttpResponse.java deleted file mode 100644 index 11866fee..00000000 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/conversion/SparkResponseToInternalHttpResponse.java +++ /dev/null @@ -1,26 +0,0 @@ -package uk.co.compendiumdev.thingifier.adapter.spark.conversion; - -import spark.Response; -import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpResponse; - -public class SparkResponseToInternalHttpResponse { - - public static InternalHttpResponse convert(Response response) { - InternalHttpResponse internalResponse = new InternalHttpResponse(); - - internalResponse.setStatus(response.status()); - internalResponse.setType(response.type()); // content type - internalResponse.setBody(response.body()); - - for (String headerName : response.raw().getHeaderNames()) { - internalResponse.setHeader(headerName, response.raw().getHeader(headerName)); - } - - return internalResponse; - } - - public static void updateResponseFromInternal( - final Response response, final InternalHttpResponse httpResponse) { - InternalHttpResponseToSpark.updateResponseFromInternal(response, httpResponse); - } -} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/conversion/SparkToInternalHttpRequest.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/conversion/SparkToInternalHttpRequest.java deleted file mode 100644 index b1f6b6f4..00000000 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/conversion/SparkToInternalHttpRequest.java +++ /dev/null @@ -1,64 +0,0 @@ -package uk.co.compendiumdev.thingifier.adapter.spark.conversion; - -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import javax.servlet.http.HttpServletRequest; -import spark.Request; -import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpRequest; - -public final class SparkToInternalHttpRequest { - - private SparkToInternalHttpRequest() {} - - public static InternalHttpRequest convert(final Request request) { - InternalHttpRequest internalRequest = - new InternalHttpRequest(request.pathInfo()) - .setBody(request.body()) - .setQueryParams(queryParamsAsMap(request)) - .setRawQueryString(request.queryString()) - .setMethod(request.requestMethod()) - .setUrl(request.url()) - .setIP(request.ip()) - .setUrlParams(request.params()); - - addRawHeaders(internalRequest, request.raw()); - - return internalRequest; - } - - private static void addRawHeaders( - final InternalHttpRequest internalRequest, final HttpServletRequest raw) { - - for (Enumeration headerNames = raw.getHeaderNames(); - headerNames.hasMoreElements(); ) { - String headerName = headerNames.nextElement(); - for (Enumeration headerValues = raw.getHeaders(headerName); - headerValues.hasMoreElements(); ) { - internalRequest.addHeader(headerName, headerValues.nextElement()); - } - } - } - - private static Map> queryParamsAsMap(final Request request) { - - Map> params = new LinkedHashMap<>(); - - for (String paramName : request.queryParams()) { - List paramValues = new ArrayList<>(); - String[] values = request.queryParamsValues(paramName); - if (values == null || values.length == 0) { - paramValues.add(""); - } else { - for (String value : values) { - paramValues.add(value == null ? "" : value); - } - } - params.put(paramName, paramValues); - } - - return params; - } -} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/LogTheResponseHook.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/LogTheResponseHook.java deleted file mode 100644 index 690bffa8..00000000 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/LogTheResponseHook.java +++ /dev/null @@ -1,17 +0,0 @@ -package uk.co.compendiumdev.thingifier.adapter.spark.messagehooks; - -import spark.Request; -import spark.Response; - -public class LogTheResponseHook implements SparkRequestResponseHook { - @Override - public void run(final Request request, final Response response) { - try { - System.out.println("**RESPONSE**"); - System.out.println(response.status()); - System.out.println(response.body()); - } catch (Exception e) { - System.out.println(e); - } - } -} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/LogTheSparkRequestHook.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/LogTheSparkRequestHook.java deleted file mode 100644 index 091dadf7..00000000 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/LogTheSparkRequestHook.java +++ /dev/null @@ -1,20 +0,0 @@ -package uk.co.compendiumdev.thingifier.adapter.spark.messagehooks; - -import spark.Request; -import spark.Response; - -public class LogTheSparkRequestHook implements SparkRequestResponseHook { - @Override - public void run(final Request request, final Response response) { - try { - - System.out.println("**REQUEST**"); - System.out.println(request.url()); - System.out.println(request.pathInfo()); - System.out.println(request.body()); - - } catch (Exception e) { - System.out.println(e); - } - } -} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/SparkRequestResponseHook.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/SparkRequestResponseHook.java deleted file mode 100644 index 6d8c3498..00000000 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/spark/messagehooks/SparkRequestResponseHook.java +++ /dev/null @@ -1,13 +0,0 @@ -package uk.co.compendiumdev.thingifier.adapter.spark.messagehooks; - -import spark.Request; -import spark.Response; - -/** - * SparkRequestResponseHook (s) are run prior to any processing. They work directly on the Spark - * request and Spark responses - */ -public interface SparkRequestResponseHook { - // throw an exception if we want to 'stop' the request and return the response - void run(Request request, Response response); -} diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/api/http/HttpApiRequestValidator.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/api/http/HttpApiRequestValidator.java index 0feaa8e1..9519b986 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/api/http/HttpApiRequestValidator.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/api/http/HttpApiRequestValidator.java @@ -35,7 +35,7 @@ public boolean validateSyntax( ApiResponse.error( 413, String.format( - "Error: Request body too large, max allowed is %d bytes", + "Error: request body too large, max allowed is %d bytes", maxLengthBytesAllowed)); } } diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/api/http/ThingifierHttpApi.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/api/http/ThingifierHttpApi.java index 523faba2..41a5206b 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/api/http/ThingifierHttpApi.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/api/http/ThingifierHttpApi.java @@ -1,5 +1,6 @@ package uk.co.compendiumdev.thingifier.api.http; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import uk.co.compendiumdev.thingifier.Thingifier; @@ -91,6 +92,19 @@ private HttpApiResponse handleRequest(final HttpApiRequest request, HttpVerb ver httpResponse = new HttpApiResponse( request.getHeaders(), apiResponse, jsonThing, thingifier.apiConfig()); + + if (effectiveVerb == HttpVerb.HEAD) { + final int bodyLength = + httpResponse.getBody().getBytes(StandardCharsets.UTF_8).length; + apiResponse.clearBody(); + apiResponse.setHeader("Content-Length", Integer.toString(bodyLength)); + httpResponse = + new HttpApiResponse( + request.getHeaders(), + apiResponse, + jsonThing, + thingifier.apiConfig()); + } } // run any post processing response hooks @@ -130,7 +144,7 @@ public ApiResponse routeAndProcessRequest(final HttpApiRequest request, HttpVerb apiResponse = thingifier.api().get(envelope); break; case HEAD: - apiResponse = thingifier.api().head(envelope); + apiResponse = thingifier.api().get(envelope); break; case DELETE: apiResponse = thingifier.api().delete(envelope); diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/htmlgui/routing/DefaultGuiRoutings.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/htmlgui/routing/DefaultGuiRoutings.java index 7418f300..519b7b78 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/htmlgui/routing/DefaultGuiRoutings.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/htmlgui/routing/DefaultGuiRoutings.java @@ -1,11 +1,11 @@ package uk.co.compendiumdev.thingifier.htmlgui.routing; -import static spark.Spark.get; +import static uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes.get; import java.util.HashMap; import java.util.Map; -import spark.Request; import uk.co.compendiumdev.thingifier.Thingifier; +import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpServerRequest; import uk.co.compendiumdev.thingifier.core.EntityRelModel; import uk.co.compendiumdev.thingifier.htmlgui.htmlgen.DefaultGUIHTML; import uk.co.compendiumdev.thingifier.htmlgui.htmlgen.DefaultGuiHtmlPages; @@ -62,7 +62,7 @@ public DefaultGuiRoutings configureRoutes(String urlPrefixPath) { String database = getDatabaseNameFromRequest(request); - String entityName = request.queryParams("entity"); + String entityName = request.queryParam("entity"); return htmlPages.getInstancesListPage(database, entityName); }); @@ -76,17 +76,17 @@ public DefaultGuiRoutings configureRoutes(String urlPrefixPath) { String database = getDatabaseNameFromRequest(request); String entityName = ""; - for (String queryParam : request.queryParams()) { + for (String queryParam : request.queryParamNames()) { if (queryParam.contentEquals("entity")) { - entityName = request.queryParams("entity"); + entityName = request.queryParam("entity"); } } Map instanceQueryParams = new HashMap<>(); - for (String queryParam : request.queryParams()) { + for (String queryParam : request.queryParamNames()) { if (!queryParam.equals("entity")) { - instanceQueryParams.put(queryParam, request.queryParams(queryParam)); + instanceQueryParams.put(queryParam, request.queryParam(queryParam)); } } @@ -102,7 +102,7 @@ public DefaultGuiRoutings configureRoutes(String urlPrefixPath) { // TODO: multiple thingifiers would require different cookie names - give Thingifier a name and // include in cookie // e.g. X-APICHALLENGES-THINGIFIER-DATABASE-NAME, X-SIMPLEAPI-THINGIFIER-DATABASE-NAME - private String getDatabaseNameFromRequest(Request request) { + private String getDatabaseNameFromRequest(HttpServerRequest request) { if (!thingifier.apiConfig().supportsMultipleDatabases()) { return EntityRelModel.DEFAULT_DATABASE_NAME; @@ -114,8 +114,8 @@ private String getDatabaseNameFromRequest(Request request) { xdatabasename = request.cookie("X-THINGIFIER-DATABASE-NAME"); } - if (request.queryParams("database") != null) { - xdatabasename = request.queryParams("database"); + if (request.queryParam("database") != null) { + xdatabasename = request.queryParam("database"); } if (xdatabasename.equals("")) { diff --git a/thingifier/src/test/java/uk/co/compendiumdev/thingifier/api/http/UrlQueryParamParserTest.java b/thingifier/src/test/java/uk/co/compendiumdev/thingifier/api/http/UrlQueryParamParserTest.java index 3a58458b..7355ff95 100644 --- a/thingifier/src/test/java/uk/co/compendiumdev/thingifier/api/http/UrlQueryParamParserTest.java +++ b/thingifier/src/test/java/uk/co/compendiumdev/thingifier/api/http/UrlQueryParamParserTest.java @@ -10,7 +10,7 @@ public class UrlQueryParamParserTest { /* - The default Spark parsing for url params is a split by & and then a split by = + The default HTTP edge parsing for url params is a split by & and then a split by = We want to be able to filter and sort e.g. ?id>=2&sortBy=-id&id<=16 diff --git a/thingifier/src/test/java/uk/co/compendiumdev/thingifier/api/http/requests/ThingifierHttpApiRequestStatusCodeTest.java b/thingifier/src/test/java/uk/co/compendiumdev/thingifier/api/http/requests/ThingifierHttpApiRequestStatusCodeTest.java index 4736b69f..63f4f0ea 100644 --- a/thingifier/src/test/java/uk/co/compendiumdev/thingifier/api/http/requests/ThingifierHttpApiRequestStatusCodeTest.java +++ b/thingifier/src/test/java/uk/co/compendiumdev/thingifier/api/http/requests/ThingifierHttpApiRequestStatusCodeTest.java @@ -48,7 +48,7 @@ public void a413GeneratedWhenRequestTooLong() { Assertions.assertTrue( response413 .getBody() - .contains("Error: Request body too large, max allowed is 1000 bytes")); + .contains("Error: request body too large, max allowed is 1000 bytes")); } private String stringOfLength(int length) { diff --git a/thingifier/src/test/java/uk/co/compendiumdev/thingifier/architecture/ArchitectureBoundaryTest.java b/thingifier/src/test/java/uk/co/compendiumdev/thingifier/architecture/ArchitectureBoundaryTest.java index 2f4447e5..f057f2dd 100644 --- a/thingifier/src/test/java/uk/co/compendiumdev/thingifier/architecture/ArchitectureBoundaryTest.java +++ b/thingifier/src/test/java/uk/co/compendiumdev/thingifier/architecture/ArchitectureBoundaryTest.java @@ -21,7 +21,7 @@ public void applicationPackageDoesNotImportTransportOrApiResponseTypes() throws .resolve( "src/main/java/uk/co/compendiumdev/thingifier/application")); - Assertions.assertFalse(applicationSources.contains("import spark.")); + Assertions.assertFalse(applicationSources.contains("import HTTP server.")); Assertions.assertFalse( applicationSources.contains("uk.co.compendiumdev.thingifier.adapter.")); Assertions.assertFalse( diff --git a/thingifierapp/src/main/java/uk/co/compendiumdev/thingifier/application/Main.java b/thingifierapp/src/main/java/uk/co/compendiumdev/thingifier/application/Main.java index c9376e8a..89e8d58c 100644 --- a/thingifierapp/src/main/java/uk/co/compendiumdev/thingifier/application/Main.java +++ b/thingifierapp/src/main/java/uk/co/compendiumdev/thingifier/application/Main.java @@ -1,8 +1,8 @@ package uk.co.compendiumdev.thingifier.application; import uk.co.compendiumdev.thingifier.Thingifier; -import uk.co.compendiumdev.thingifier.adapter.spark.MainImplementation; -import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierHttpApiRoutings; +import uk.co.compendiumdev.thingifier.adapter.httpserver.MainImplementation; +import uk.co.compendiumdev.thingifier.adapter.httpserver.ThingifierHttpApiRoutings; import uk.co.compendiumdev.thingifier.application.examples.TodoListThingifier; import uk.co.compendiumdev.thingifier.application.examples.TodoManagerThingifier; @@ -114,7 +114,7 @@ public static void main(String[] args) { // code header // todo : add some other admin endpoints e.g. show version details of the app etc. - // allows thingifier to be used in additional custom route configuration + // allows thingifier to be used in additional custom HttpRouteHandler configuration // or apiConfig() // setup the thingifier Thingifier thingifier = app.chooseThingifier(); diff --git a/todoManagerRestAuto/pom.xml b/todoManagerRestAuto/pom.xml index 40debfc3..559926ce 100644 --- a/todoManagerRestAuto/pom.xml +++ b/todoManagerRestAuto/pom.xml @@ -42,7 +42,7 @@ ${rest-assured-version} test - + uk.co.compendiumdev thingifier diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/Port.java b/todoManagerRestAuto/src/test/java/uk/co/compendiumdev/serverstart/Port.java similarity index 97% rename from challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/Port.java rename to todoManagerRestAuto/src/test/java/uk/co/compendiumdev/serverstart/Port.java index 1e74ccee..81797bf7 100644 --- a/challengerAuto/src/test/java/uk/co/compendiumdev/sparkstart/Port.java +++ b/todoManagerRestAuto/src/test/java/uk/co/compendiumdev/serverstart/Port.java @@ -1,4 +1,4 @@ -package uk.co.compendiumdev.sparkstart; +package uk.co.compendiumdev.serverstart; import java.io.IOException; import java.net.InetSocketAddress; diff --git a/todoManagerRestAuto/src/test/java/uk/co/compendiumdev/thingifier/tactical/postmanreplication/Environment.java b/todoManagerRestAuto/src/test/java/uk/co/compendiumdev/thingifier/tactical/postmanreplication/Environment.java index 97817c7c..f99ec063 100644 --- a/todoManagerRestAuto/src/test/java/uk/co/compendiumdev/thingifier/tactical/postmanreplication/Environment.java +++ b/todoManagerRestAuto/src/test/java/uk/co/compendiumdev/thingifier/tactical/postmanreplication/Environment.java @@ -3,17 +3,15 @@ import io.restassured.RestAssured; import io.restassured.filter.log.RequestLoggingFilter; import io.restassured.filter.log.ResponseLoggingFilter; -import spark.Spark; -import uk.co.compendiumdev.sparkstart.Port; +import uk.co.compendiumdev.serverstart.Port; import uk.co.compendiumdev.thingifier.Thingifier; -import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierAutoDocGenRouting; -import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierHttpApiRoutings; -import uk.co.compendiumdev.thingifier.api.docgen.ThingifierApiDocumentationDefn; +import uk.co.compendiumdev.thingifier.adapter.httpserver.MainImplementation; import uk.co.compendiumdev.thingifier.application.examples.TodoManagerThingifier; -import uk.co.compendiumdev.thingifier.htmlgui.htmlgen.DefaultGUIHTML; public class Environment { + private static MainImplementation app; + /** could just use `RestAssured.baseURI = Environment.getBaseUri();` instead */ public static String getEnv(String urlPath) { return getBaseUri() + urlPath; @@ -27,12 +25,11 @@ public static String getBaseUri() { // setup rest assured logging RestAssured.filters(new RequestLoggingFilter(), new ResponseLoggingFilter()); - // if not running then start the spark + // if not running then start the server if (Port.inUse("localhost", 4567)) { return "http://localhost:4567"; } else { // start it up - Spark.port(4567); final Thingifier thingifier = new TodoManagerThingifier().get(); thingifier.apiConfig().adminConfig().enableAdminDataClear(); thingifier.apiConfig().adminConfig().enableAdminSearch(); @@ -41,10 +38,17 @@ public static String getBaseUri() { thingifier.apiConfig().jsonOutput().setShowPrimaryKeyInResponse(true); thingifier.apiConfig().jsonOutput().setConvertFieldsToDefinedTypes(false); - ThingifierApiDocumentationDefn apiDefn = - new ThingifierApiDocumentationDefn().setThingifier(thingifier); - new ThingifierAutoDocGenRouting(thingifier, apiDefn, new DefaultGUIHTML()); - new ThingifierHttpApiRoutings(thingifier, apiDefn); + app = new MainImplementation(); + app.registerModel("todoManager", thingifier); + app.setDefaultsFromArgs(new String[0]); + app.configurePortAndDefaultRoutes(); + app.setupBuiltInConfigurableRoutes(); + app.chooseThingifier(); + app.configureThingifierWithProfile(); + app.setupDefaultGui(); + app.startRestServer(); + waitTillRunningStatus(true); + return "http://localhost:4567"; } @@ -69,8 +73,10 @@ public static void waitTillRunningStatus(final boolean running) { } public static void stop() { - Spark.stop(); - Spark.awaitStop(); + if (app != null) { + app.close(); + app = null; + } waitTillRunningStatus(false); } } From 716cc47943a12eca70732843ccb6a00ca03d1451 Mon Sep 17 00:00:00 2001 From: Alan Richardson Date: Thu, 16 Jul 2026 18:40:59 +0100 Subject: [PATCH 2/2] Fix duplicate path params for Javalin routes --- .../adapter/javalin/JavalinHttpServer.java | 18 +++++++++-- .../adapter/javalin/JavalinServerRequest.java | 30 +++++++++++++++++++ .../javalin/JavalinHttpServerTest.java | 20 +++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 thingifier/src/test/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinHttpServerTest.java diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinHttpServer.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinHttpServer.java index 936c751f..a4f670c9 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinHttpServer.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinHttpServer.java @@ -5,6 +5,8 @@ import io.javalin.http.HandlerType; import io.javalin.http.staticfiles.Location; import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; import uk.co.compendiumdev.thingifier.adapter.httpserver.HaltRequestException; import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpAfterHandler; import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpBeforeHandler; @@ -141,14 +143,24 @@ private HandlerType handlerType(final HttpRouteVerb verb) { } } - private String javalinPath(final String routePath) { + static String javalinPath(final String routePath) { if (routePath == null || routePath.isBlank() || "*".equals(routePath)) { return "/*"; } String converted = routePath.trim(); - converted = converted.replaceAll(":([A-Za-z][A-Za-z0-9_]*)", "{$1}"); - return converted; + String[] parts = converted.split("/", -1); + Map nameCounts = new HashMap<>(); + for (int index = 0; index < parts.length; index++) { + String part = parts[index]; + if (part.matches(":[A-Za-z][A-Za-z0-9_]*")) { + String name = part.substring(1); + int count = nameCounts.merge(name, 1, Integer::sum); + String javalinName = count == 1 ? name : name + "__" + count; + parts[index] = "{" + javalinName + "}"; + } + } + return String.join("/", parts); } private String exceptionErrorResponse(final Exception e, final Context ctx) { diff --git a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinServerRequest.java b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinServerRequest.java index 901ac544..364fd25b 100644 --- a/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinServerRequest.java +++ b/thingifier/src/main/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinServerRequest.java @@ -139,6 +139,11 @@ public String url() { @Override public Map urlParams() { + String routePath = context.attribute(ROUTE_PATH_ATTRIBUTE); + if (routePath != null) { + return urlParamsFromRoute(routePath, context.path()); + } + Map params = new LinkedHashMap<>(); for (Map.Entry param : context.pathParamMap().entrySet()) { params.put(param.getKey(), param.getValue()); @@ -146,4 +151,29 @@ public Map urlParams() { } return params; } + + private Map urlParamsFromRoute(final String routePath, final String path) { + Map params = new LinkedHashMap<>(); + String[] routeParts = stripLeadingSlash(routePath).split("/", -1); + String[] pathParts = stripLeadingSlash(path).split("/", -1); + int max = Math.min(routeParts.length, pathParts.length); + + for (int index = 0; index < max; index++) { + String routePart = routeParts[index]; + if (routePart.matches(":[A-Za-z][A-Za-z0-9_]*")) { + String name = routePart.substring(1); + params.put(name, pathParts[index]); + params.put(":" + name, pathParts[index]); + } + } + + return params; + } + + private String stripLeadingSlash(final String value) { + if (value == null || value.isEmpty()) { + return ""; + } + return value.startsWith("/") ? value.substring(1) : value; + } } diff --git a/thingifier/src/test/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinHttpServerTest.java b/thingifier/src/test/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinHttpServerTest.java new file mode 100644 index 00000000..9c7bb28f --- /dev/null +++ b/thingifier/src/test/java/uk/co/compendiumdev/thingifier/adapter/javalin/JavalinHttpServerTest.java @@ -0,0 +1,20 @@ +package uk.co.compendiumdev.thingifier.adapter.javalin; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class JavalinHttpServerTest { + + @Test + void duplicateLegacyPathParamNamesAreMadeUniqueForJavalin() { + Assertions.assertEquals( + "todos/{id}/tasksof/{id__2}", + JavalinHttpServer.javalinPath("todos/:id/tasksof/:id")); + } + + @Test + void keepsSingleLegacyPathParamNamesReadable() { + Assertions.assertEquals( + "/challenger/{id}", JavalinHttpServer.javalinPath("/challenger/:id")); + } +}