From dd8edea5b2e5c91280d53a3d02c2d99d383654f8 Mon Sep 17 00:00:00 2001 From: alfanse Date: Sun, 18 May 2025 21:28:49 +0100 Subject: [PATCH 01/12] upgraded from 5 to 8 - build fail --- build.gradle | 74 +++++++++++------------- embers-acceptance-tests/build.gradle | 16 ++--- embers-services/build.gradle | 10 ++-- embers-spring/build.gradle | 8 +-- gradle/wrapper/gradle-wrapper.properties | 2 +- 5 files changed, 53 insertions(+), 57 deletions(-) diff --git a/build.gradle b/build.gradle index c09f047..ace3392 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } } dependencies { - classpath "com.adarshr:gradle-test-logger-plugin:1.7.0" + classpath "com.adarshr:gradle-test-logger-plugin:4.0.0" } } @@ -19,7 +19,8 @@ allprojects { apply plugin: 'jacoco' apply plugin: 'com.adarshr.test-logger' - sourceCompatibility = 1.8 + sourceCompatibility = 17 + targetCompatibility = 17 repositories { mavenCentral() @@ -47,9 +48,11 @@ task codeCoverageReport(type: JacocoReport) { } reports { - html.enabled true - html.destination file("${buildDir}/reports/jacoco") - println "code coverage reports: " + html.destination + html { + setEnabled(true) + outputLocation = file("${buildDir}/reports/jacoco") +// println "code coverage reports: " + html.destination + } } } @@ -65,8 +68,8 @@ subprojects { def jaxb = '2.3.0' def junitJupiter = '5.7.1' - extensions.add("libs", [ - core: [ + ext { + core = [ //the only libraries the production jar depends on 'javax.ws.rs:javax.ws.rs-api:2.1', 'javax.inject:javax.inject:1', @@ -75,41 +78,34 @@ subprojects { "com.sun.xml.bind:jaxb-core:$jaxb", "com.sun.xml.bind:jaxb-impl:$jaxb", 'org.jdbi:jdbi:2.78' - ], - unit_tests: [ + ] + unit_tests = [ "org.junit.jupiter:junit-jupiter:$junitJupiter", 'org.easytesting:fest-assert-core:2.0M10', 'org.mockito:mockito-core:3.8.0', 'org.mockito:mockito-junit-jupiter:3.8.0' - ], - acceptance_tests: [ -// the bdd framework, makes pretty html reports from Junit tests - 'com.github.nickmcdowall:yatspec:2021.1.1' - ], - jersey: [ -// implements javax.ws.rs - 'org.glassfish.jersey.core:jersey-server:2.2', - 'org.glassfish.jersey.containers:jersey-container-servlet:2.2' - ], - jaxson: [ -// handles json serialisation - 'com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.5.2' - ], - gson: [ + ] + acceptance_tests = [ + // The bdd framework, makes pretty html reports from Junit tests + 'com.github.nickmcdowall:yatspec:2021.1.1'] + jersey = [ + // implements javax.ws.rs + 'org.glassfish.jersey.core:jersey-server:2.2', + 'org.glassfish.jersey.containers:jersey-container-servlet:2.2'] + jaxson = [ + //handles json serialisation + 'com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.5.2'] + gson = [ //serialise java to json - 'com.google.code.gson:gson:2.8.2' - ], - json_assert: [ - 'org.skyscreamer:jsonassert:1.2.3' - ], - jetty: [ -// beloved server - 'org.eclipse.jetty:jetty-server:9.3.0.M1', - 'org.eclipse.jetty:jetty-servlet:9.3.0.M1' - ], - database: [ -// beloved in-memory DB for testing. - 'org.hsqldb:hsqldb:2.3.2' - ] - ]) + 'com.google.code.gson:gson:2.8.2'] + json_assert = ['org.skyscreamer:jsonassert:1.2.3'] + jetty = [ + // beloved server + 'org.eclipse.jetty:jetty-server:9.3.0.M1', + 'org.eclipse.jetty:jetty-servlet:9.3.0.M1' + ] + database = [ + // beloved in-memory DB for testing. + 'org.hsqldb:hsqldb:2.3.2'] + } } diff --git a/embers-acceptance-tests/build.gradle b/embers-acceptance-tests/build.gradle index 6af6fb5..2b0fc90 100644 --- a/embers-acceptance-tests/build.gradle +++ b/embers-acceptance-tests/build.gradle @@ -12,13 +12,13 @@ test { test.mustRunAfter ":embers-services:build" dependencies { - compile project(":embers-services") - compile libs.acceptance_tests - compile libs.database + implementation project(":embers-services") + implementation ext.get('acceptance_tests') + implementation ext.get('database') - testCompile libs.unit_tests - testCompile libs.acceptance_tests - testCompile libs.jersey - testCompile libs.jaxson - testCompile libs.jetty + testImplementation unit_tests + testImplementation acceptance_tests + testImplementation jersey + testImplementation jaxson + testImplementation jetty } diff --git a/embers-services/build.gradle b/embers-services/build.gradle index 59d4c4a..23b44be 100644 --- a/embers-services/build.gradle +++ b/embers-services/build.gradle @@ -1,11 +1,11 @@ description = "Build jar for the embers sql reporting services." dependencies { - compile libs.core - compile libs.gson - testCompile libs.unit_tests - testCompile libs.jersey - testCompile libs.json_assert + implementation core + implementation gson + testImplementation unit_tests + testImplementation jersey + testImplementation json_assert } test { diff --git a/embers-spring/build.gradle b/embers-spring/build.gradle index 4f8e4ea..85ae36a 100644 --- a/embers-spring/build.gradle +++ b/embers-spring/build.gradle @@ -1,6 +1,6 @@ plugins { - id 'org.springframework.boot' version '2.1.8.RELEASE' - id 'io.spring.dependency-management' version '1.0.8.RELEASE' + id 'org.springframework.boot' version '2.7.18' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' } description = """Example project showing how to mix embers into a spring-boot application.""" @@ -12,8 +12,8 @@ dependencies { implementation "org.springframework.boot:spring-boot-starter-web" testImplementation project(":embers-acceptance-tests") - testImplementation libs.database - testImplementation libs.unit_tests + testImplementation database + testImplementation unit_tests testImplementation 'io.rest-assured:rest-assured:3.3.0' testImplementation "org.springframework.boot:spring-boot-starter-test" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2da474f..dbb84f5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https://services.gradle.org/distributions/gradle-5.3.1-bin.zip +distributionUrl=https://services.gradle.org/distributions/gradle-8.0-bin.zip From 1e0843c5f7e4b22bce909d8921a15346d2f31017 Mon Sep 17 00:00:00 2001 From: alfanse Date: Sun, 18 May 2025 22:48:17 +0100 Subject: [PATCH 02/12] using libs.versions.toml, bdd compile fail --- build.gradle | 47 -------------------- embers-acceptance-tests/build.gradle | 14 +++--- embers-services/build.gradle | 10 ++--- embers-spring/build.gradle | 6 +-- gradle/libs.versions.toml | 65 ++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 62 deletions(-) create mode 100644 gradle/libs.versions.toml diff --git a/build.gradle b/build.gradle index ace3392..73f8618 100644 --- a/build.gradle +++ b/build.gradle @@ -62,50 +62,3 @@ codeCoverageReport.dependsOn { } check.dependsOn jacocoTestReport - -subprojects { - - def jaxb = '2.3.0' - def junitJupiter = '5.7.1' - - ext { - core = [ - //the only libraries the production jar depends on - 'javax.ws.rs:javax.ws.rs-api:2.1', - 'javax.inject:javax.inject:1', - 'javax.activation:activation:1.1.1', - "javax.xml.bind:jaxb-api:$jaxb", - "com.sun.xml.bind:jaxb-core:$jaxb", - "com.sun.xml.bind:jaxb-impl:$jaxb", - 'org.jdbi:jdbi:2.78' - ] - unit_tests = [ - "org.junit.jupiter:junit-jupiter:$junitJupiter", - 'org.easytesting:fest-assert-core:2.0M10', - 'org.mockito:mockito-core:3.8.0', - 'org.mockito:mockito-junit-jupiter:3.8.0' - ] - acceptance_tests = [ - // The bdd framework, makes pretty html reports from Junit tests - 'com.github.nickmcdowall:yatspec:2021.1.1'] - jersey = [ - // implements javax.ws.rs - 'org.glassfish.jersey.core:jersey-server:2.2', - 'org.glassfish.jersey.containers:jersey-container-servlet:2.2'] - jaxson = [ - //handles json serialisation - 'com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.5.2'] - gson = [ - //serialise java to json - 'com.google.code.gson:gson:2.8.2'] - json_assert = ['org.skyscreamer:jsonassert:1.2.3'] - jetty = [ - // beloved server - 'org.eclipse.jetty:jetty-server:9.3.0.M1', - 'org.eclipse.jetty:jetty-servlet:9.3.0.M1' - ] - database = [ - // beloved in-memory DB for testing. - 'org.hsqldb:hsqldb:2.3.2'] - } -} diff --git a/embers-acceptance-tests/build.gradle b/embers-acceptance-tests/build.gradle index 2b0fc90..e710932 100644 --- a/embers-acceptance-tests/build.gradle +++ b/embers-acceptance-tests/build.gradle @@ -13,12 +13,12 @@ test.mustRunAfter ":embers-services:build" dependencies { implementation project(":embers-services") - implementation ext.get('acceptance_tests') - implementation ext.get('database') + implementation libs.bundles.acceptance.tests + implementation libs.bundles.database - testImplementation unit_tests - testImplementation acceptance_tests - testImplementation jersey - testImplementation jaxson - testImplementation jetty + testImplementation libs.bundles.unit.tests + testImplementation libs.bundles.acceptance.tests + testImplementation libs.bundles.jersey + testImplementation libs.jaxson + testImplementation libs.bundles.jetty } diff --git a/embers-services/build.gradle b/embers-services/build.gradle index 23b44be..81c3adb 100644 --- a/embers-services/build.gradle +++ b/embers-services/build.gradle @@ -1,11 +1,11 @@ description = "Build jar for the embers sql reporting services." dependencies { - implementation core - implementation gson - testImplementation unit_tests - testImplementation jersey - testImplementation json_assert + implementation libs.bundles.core + implementation libs.gson + testImplementation libs.bundles.unit.tests + testImplementation libs.bundles.jersey + testImplementation libs.json.assert } test { diff --git a/embers-spring/build.gradle b/embers-spring/build.gradle index 85ae36a..6c914d4 100644 --- a/embers-spring/build.gradle +++ b/embers-spring/build.gradle @@ -12,9 +12,9 @@ dependencies { implementation "org.springframework.boot:spring-boot-starter-web" testImplementation project(":embers-acceptance-tests") - testImplementation database - testImplementation unit_tests - testImplementation 'io.rest-assured:rest-assured:3.3.0' + testImplementation libs.bundles.database + testImplementation libs.bundles.unit.tests + testImplementation "io.rest-assured:rest-assured:3.3.0" testImplementation "org.springframework.boot:spring-boot-starter-test" } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..00243cd --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,65 @@ +[versions] +jaxb = "2.3.0" +mockito = "3.8.0" + +[libraries] + +gson = { module = "com.google.code.gson:gson", version = "2.8.2" } +json_assert = { module = "org.skyscreamer:jsonassert", version = "1.2.3" } + +javax_ws_rs = { module = "javax.ws.rs:javax.ws.rs-api", version = "2.1" } +javax_inject = { module = "javax.inject:javax.inject", version = "1" } +javax_activation = { module = "javax.activation:activation", version = "1.1.1" } +javax_xml_bind = { module = "javax.xml.bind:jaxb-api", version.ref = "jaxb" } +jaxb_core = { module = "com.sun.xml.bind:jaxb-core", version.ref = "jaxb" } +jaxb_impl = { module = "com.sun.xml.bind:jaxb-impl", version.ref = "jaxb" } +jdbi = { module = "org.jdbi:jdbi", version = "2.78" } + +jaxson = { module = "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider", version = "2.5.2"} + +jersey_server = { module = "org.glassfish.jersey.core:jersey-server", version = "2.2" } +jersey_container = { module = "org.glassfish.jersey.containers:jersey-container-servlet", version = "2.2" } + +jetty_server = { module = "org.eclipse.jetty:jetty-server", version = "9.3.0.M1" } +jetty_servlet = { module = "org.eclipse.jetty:jetty-servlet", version = "9.3.0.M1" } + +hsqldb = { module = "org.hsqldb:hsqldb", version = "2.7.4" } + +junit_jupiter = { module = "org.junit.jupiter:junit-jupiter", version = "5.7.1" } +fest_assert = { module = "org.easytesting:fest-assert-core", version = "2.0M10" } +mockito_core = { module = "org.mockito:mockito-core", version.ref = "mockito" } +mockito_junit_jupiter = { module = "org.mockito:mockito-junit-jupiter", version.ref = "mockito" } + +yatspec = { module = "com.github.nickmcdowall:yatspec", version = "2021.1.1" } + +[bundles] +core = [ + # the only libraries the production jar depends on + "javax_ws_rs", "javax_inject", "javax_activation", "javax_xml_bind", "jaxb_core", "jaxb_impl", "jdbi" +] + +unit_tests = [ + "junit_jupiter", "fest_assert", "mockito_core", "mockito_junit_jupiter" +] + +acceptance_tests = [ + # The bdd framework, makes pretty html reports from Junit tests + "yatspec" +] + +jersey = [ + # implements javax.ws.rs + "jersey_server", "jersey_container" +] + +jetty = [ + # beloved server + "jetty_server", "jetty_servlet" +] + +database = [ + # beloved in-memory DB for testing. + "hsqldb" +] + +[plugins] From ce176d5482e8d5c0d53250734e31054cff8eb04e Mon Sep 17 00:00:00 2001 From: alfanse Date: Sun, 18 May 2025 23:00:53 +0100 Subject: [PATCH 03/12] gradle 8 build working, test failures --- embers-acceptance-tests/build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embers-acceptance-tests/build.gradle b/embers-acceptance-tests/build.gradle index e710932..5b69c57 100644 --- a/embers-acceptance-tests/build.gradle +++ b/embers-acceptance-tests/build.gradle @@ -13,6 +13,8 @@ test.mustRunAfter ":embers-services:build" dependencies { implementation project(":embers-services") + implementation libs.bundles.core + implementation libs.gson implementation libs.bundles.acceptance.tests implementation libs.bundles.database From ccb49605efb87ac4f602947bef94c438146137b3 Mon Sep 17 00:00:00 2001 From: alfanse Date: Tue, 20 May 2025 22:08:27 +0100 Subject: [PATCH 04/12] --add-opens to fix reflection in unittesting embers-services --- embers-services/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/embers-services/build.gradle b/embers-services/build.gradle index 81c3adb..29a2cbb 100644 --- a/embers-services/build.gradle +++ b/embers-services/build.gradle @@ -9,6 +9,7 @@ dependencies { } test { + jvmArgs '--add-opens', 'java.base/java.util=ALL-UNNAMED' useJUnitPlatform() } From 2d0beda89c3926347bb0fc895ed787e6c3deff31 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 1 Jun 2025 09:34:40 +0100 Subject: [PATCH 05/12] bruno collection added --- .../adf/embers/tools/EmbersJettyServer.java | 2 ++ .../POST Admin - create query.bru | 24 +++++++++++++++++++ embers-request-collection/bruno.json | 9 +++++++ .../EmbersRepositoryConfiguration.java | 2 +- 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 embers-request-collection/POST Admin - create query.bru create mode 100644 embers-request-collection/bruno.json diff --git a/embers-acceptance-tests/src/test/java/adf/embers/tools/EmbersJettyServer.java b/embers-acceptance-tests/src/test/java/adf/embers/tools/EmbersJettyServer.java index 23347a8..ed20d50 100644 --- a/embers-acceptance-tests/src/test/java/adf/embers/tools/EmbersJettyServer.java +++ b/embers-acceptance-tests/src/test/java/adf/embers/tools/EmbersJettyServer.java @@ -32,12 +32,14 @@ public void startHttpServer(DataSource dataSource) throws Exception { server.setHandler(createEmbersHandler(jerseyServlet)); server.start(); + System.out.println("Started the Embers Server"); } public void stopHttpServer() { System.out.println("Stopping the Embers server"); try { server.stop(); + System.out.println("Stopped the Embers server"); } catch (Exception e) { System.err.println("Exception stopping jetty server: "+e.getMessage()); } diff --git a/embers-request-collection/POST Admin - create query.bru b/embers-request-collection/POST Admin - create query.bru new file mode 100644 index 0000000..efc41d6 --- /dev/null +++ b/embers-request-collection/POST Admin - create query.bru @@ -0,0 +1,24 @@ +meta { + name: POST Admin - create query + type: http + seq: 1 +} + +post { + url: http://localhost:8001/embers/admin + body: json + auth: inherit +} + +headers { + Accept-Charset: UTF-8 + Content-Type: application/json +} + +body:json { + { + "name":"new Query", + "sql":"SELECT CURRENT_DATE AS today, CURRENT_TIME AS now FROM (VALUES(0))", + "description":"this query returns the date,time" + } +} diff --git a/embers-request-collection/bruno.json b/embers-request-collection/bruno.json new file mode 100644 index 0000000..2f085b7 --- /dev/null +++ b/embers-request-collection/bruno.json @@ -0,0 +1,9 @@ +{ + "version": "1", + "name": "embers-request-collection", + "type": "collection", + "ignore": [ + "node_modules", + ".git" + ] +} \ No newline at end of file diff --git a/embers-services/src/main/java/adf/embers/configuration/EmbersRepositoryConfiguration.java b/embers-services/src/main/java/adf/embers/configuration/EmbersRepositoryConfiguration.java index 66dfe4d..282a742 100644 --- a/embers-services/src/main/java/adf/embers/configuration/EmbersRepositoryConfiguration.java +++ b/embers-services/src/main/java/adf/embers/configuration/EmbersRepositoryConfiguration.java @@ -12,7 +12,7 @@ public class EmbersRepositoryConfiguration { private final DBI dbi; - private DataSource dataSource; + private final DataSource dataSource; public EmbersRepositoryConfiguration(DataSource dataSource) { this.dataSource = dataSource; From fc6a45af431cc9e9b14830c376bb083cced28a1a Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 1 Jun 2025 21:55:08 +0100 Subject: [PATCH 06/12] A/T passing, Spring failing --- embers-acceptance-tests/build.gradle | 6 +- .../adf/embers/tools/EmbersJettyServer.java | 90 +++++++++++++---- .../java/adf/embers/tools/EmbersServer.java | 20 +++- .../src/test/resources/META-INF/beans.xml | 13 +++ .../adf/embers/admin/AdminQueryHandler.java | 8 +- .../main/java/adf/embers/cache/Caching.java | 2 +- .../embers/cache/QueryResultCacheHandler.java | 12 +-- .../cache/QueryResultCacheProcessor.java | 2 + .../java/adf/embers/query/QueryHandler.java | 12 +-- .../embers/admin/AdminQueryHandlerTest.java | 3 +- .../cache/QueryResultCacheHandlerTest.java | 3 +- embers-spring/build.gradle | 25 +++-- embers-spring/jdbc:h2:mem:testdb.properties | 5 + embers-spring/jdbc:h2:mem:testdb.script | 52 ++++++++++ .../spring/EmbersSpringConfiguration.java | 66 +++++++++---- .../examples/spring/ApplicationTest.java | 41 +++++--- .../spring/SpringDataSourceConfiguration.java | 96 +++++++++++++++++-- gradle/libs.versions.toml | 50 +++++++--- 18 files changed, 403 insertions(+), 103 deletions(-) create mode 100644 embers-acceptance-tests/src/test/resources/META-INF/beans.xml create mode 100644 embers-spring/jdbc:h2:mem:testdb.properties create mode 100644 embers-spring/jdbc:h2:mem:testdb.script diff --git a/embers-acceptance-tests/build.gradle b/embers-acceptance-tests/build.gradle index 5b69c57..3b21313 100644 --- a/embers-acceptance-tests/build.gradle +++ b/embers-acceptance-tests/build.gradle @@ -20,7 +20,11 @@ dependencies { testImplementation libs.bundles.unit.tests testImplementation libs.bundles.acceptance.tests + testImplementation libs.bundles.jakarta.web.server testImplementation libs.bundles.jersey - testImplementation libs.jaxson testImplementation libs.bundles.jetty + testImplementation libs.jaxson + + // Platform BOMs for dependency management + testImplementation platform('org.eclipse.jetty:jetty-bom:12.0.7') } diff --git a/embers-acceptance-tests/src/test/java/adf/embers/tools/EmbersJettyServer.java b/embers-acceptance-tests/src/test/java/adf/embers/tools/EmbersJettyServer.java index ed20d50..297a49d 100644 --- a/embers-acceptance-tests/src/test/java/adf/embers/tools/EmbersJettyServer.java +++ b/embers-acceptance-tests/src/test/java/adf/embers/tools/EmbersJettyServer.java @@ -3,15 +3,22 @@ import adf.embers.configuration.EmbersHandlerConfiguration; import adf.embers.configuration.EmbersProcessorConfiguration; import adf.embers.configuration.EmbersRepositoryConfiguration; + +import jakarta.servlet.Servlet; +import org.eclipse.jetty.ee10.servlet.ServletContextHandler; +import org.eclipse.jetty.ee10.servlet.ServletHolder; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.component.LifeCycle; +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.hk2.utilities.ServiceLocatorUtilities; +import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.servlet.ServletContainer; -import javax.servlet.Servlet; import javax.sql.DataSource; +import java.util.logging.Level; +import java.util.logging.Logger; public class EmbersJettyServer { @@ -22,17 +29,60 @@ public EmbersJettyServer(int port) { } public void startHttpServer(DataSource dataSource) throws Exception { - System.out.println("Starting the Embers Server"); - - EmbersRepositoryConfiguration embersRepositoryConfiguration = new EmbersRepositoryConfiguration(dataSource); - EmbersProcessorConfiguration embersProcessorConfiguration = new EmbersProcessorConfiguration(embersRepositoryConfiguration); - EmbersHandlerConfiguration embersConfiguration = new EmbersHandlerConfiguration(embersProcessorConfiguration); - - Servlet jerseyServlet = createJerseyServletWithEmbersHandlers(embersConfiguration); - - server.setHandler(createEmbersHandler(jerseyServlet)); - server.start(); - System.out.println("Started the Embers Server"); + System.out.println("Starting the Embers Server on port: " + server.getURI()); + + // Disable Weld logging to avoid unnecessary warnings + Logger.getLogger("org.jboss.weld").setLevel(Level.SEVERE); + + // Set HK2 as the injection manager + System.setProperty("jersey.config.server.disableAutoDiscovery", "true"); + System.setProperty("jersey.config.server.disableMetainfServicesLookup", "true"); + System.setProperty("jersey.config.server.disableMoxyJson", "true"); + + try { + // Create HK2 service locator + ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator("EmbersServiceLocator"); + + // Manually register services + EmbersRepositoryConfiguration embersRepositoryConfiguration = new EmbersRepositoryConfiguration(dataSource); + ServiceLocatorUtilities.addOneConstant(locator, embersRepositoryConfiguration); + + EmbersProcessorConfiguration embersProcessorConfiguration = new EmbersProcessorConfiguration(embersRepositoryConfiguration); + ServiceLocatorUtilities.addOneConstant(locator, embersProcessorConfiguration); + + EmbersHandlerConfiguration embersConfiguration = new EmbersHandlerConfiguration(embersProcessorConfiguration); + ServiceLocatorUtilities.addOneConstant(locator, embersConfiguration); + + // Create Jersey resource config with HK2 + ResourceConfig resourceConfig = new ResourceConfig(); + resourceConfig.property("jersey.config.server.provider.classnames", + "org.glassfish.jersey.media.multipart.MultiPartFeature"); + + // Register resources + resourceConfig.register(embersConfiguration.getQueryHandler()); + resourceConfig.register(embersConfiguration.getAdminQueryHandler()); + resourceConfig.register(embersConfiguration.getQueryResultCacheHandler()); + + // Create servlet container with HK2 + ServletContainer servletContainer = new ServletContainer(resourceConfig); + + // Set up the handler + ServletContextHandler handler = new ServletContextHandler(ServletContextHandler.SESSIONS); + handler.setContextPath("/" + EmbersServer.CONTEXT_PATH_ROOT); + ServletHolder servletHolder = new ServletHolder("jersey-servlet", servletContainer); + handler.addServlet(servletHolder, "/*"); + + System.out.println("Created handler: " + handler); + server.setHandler(handler); + + System.out.println("Starting Jetty server..."); + server.start(); + System.out.println("Started the Embers Server at: http://localhost:" + server.getURI().getPort() + "/" + EmbersServer.CONTEXT_PATH_ROOT); + } catch (Exception e) { + System.err.println("Error starting Embers server: " + e.getMessage()); + e.printStackTrace(); + throw e; + } } public void stopHttpServer() { @@ -41,7 +91,9 @@ public void stopHttpServer() { server.stop(); System.out.println("Stopped the Embers server"); } catch (Exception e) { - System.err.println("Exception stopping jetty server: "+e.getMessage()); + System.err.println("Exception stopping jetty server: " + e.getMessage() + "/n"); + } finally { + LifeCycle.stop(server); } } @@ -55,10 +107,12 @@ private Servlet createJerseyServletWithEmbersHandlers(EmbersHandlerConfiguration private Handler createEmbersHandler(Servlet embersServlet) { ServletContextHandler handler = new ServletContextHandler(); - handler.addServlet(new ServletHolder(embersServlet), "/"); - //setting context path separately works handler.setContextPath("/" + EmbersServer.CONTEXT_PATH_ROOT); - + + // Add the servlet + ServletHolder servletHolder = new ServletHolder("embers", embersServlet); + handler.addServlet(servletHolder, "/*"); + return handler; } } diff --git a/embers-acceptance-tests/src/test/java/adf/embers/tools/EmbersServer.java b/embers-acceptance-tests/src/test/java/adf/embers/tools/EmbersServer.java index f8dbdc6..2082330 100644 --- a/embers-acceptance-tests/src/test/java/adf/embers/tools/EmbersServer.java +++ b/embers-acceptance-tests/src/test/java/adf/embers/tools/EmbersServer.java @@ -18,8 +18,24 @@ public class EmbersServer { private EmbersJettyServer embersJettyServer; public void before() throws Throwable { - startDatabase(); - startJettyServer(embersDatabase.getDataSource()); + System.out.println("Starting Embers server..."); + try { + startDatabase(); + System.out.println("Database started successfully"); + + System.out.println("Starting Jetty server with data source: " + embersDatabase.getDataSource()); + startJettyServer(embersDatabase.getDataSource()); + + // Add a small delay to ensure server is fully started + Thread.sleep(1000); + System.out.println("Embers server started successfully on port " + PORT); + System.out.println("Query path: " + embersQueryPath()); + System.out.println("Admin path: " + embersAdminPath()); + } catch (Throwable t) { + System.err.println("Error starting Embers server: " + t.getMessage()); + t.printStackTrace(); + throw t; + } } @SuppressWarnings("unused") //Keeping it as a might be needed to fix re-using server bugs diff --git a/embers-acceptance-tests/src/test/resources/META-INF/beans.xml b/embers-acceptance-tests/src/test/resources/META-INF/beans.xml new file mode 100644 index 0000000..36ce1f4 --- /dev/null +++ b/embers-acceptance-tests/src/test/resources/META-INF/beans.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/embers-services/src/main/java/adf/embers/admin/AdminQueryHandler.java b/embers-services/src/main/java/adf/embers/admin/AdminQueryHandler.java index 25144d4..b8a1e96 100644 --- a/embers-services/src/main/java/adf/embers/admin/AdminQueryHandler.java +++ b/embers-services/src/main/java/adf/embers/admin/AdminQueryHandler.java @@ -3,10 +3,10 @@ import adf.embers.query.persistence.Query; import adf.embers.query.persistence.QueryDao; -import javax.inject.Inject; -import javax.ws.rs.*; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import jakarta.inject.Inject; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import static adf.embers.statics.UrlTools.decodeString; diff --git a/embers-services/src/main/java/adf/embers/cache/Caching.java b/embers-services/src/main/java/adf/embers/cache/Caching.java index acc843f..19d2221 100644 --- a/embers-services/src/main/java/adf/embers/cache/Caching.java +++ b/embers-services/src/main/java/adf/embers/cache/Caching.java @@ -1,6 +1,6 @@ package adf.embers.cache; -import javax.inject.Qualifier; +import jakarta.inject.Qualifier; import java.lang.annotation.Retention; import java.lang.annotation.Target; diff --git a/embers-services/src/main/java/adf/embers/cache/QueryResultCacheHandler.java b/embers-services/src/main/java/adf/embers/cache/QueryResultCacheHandler.java index 755b43b..ad07b24 100644 --- a/embers-services/src/main/java/adf/embers/cache/QueryResultCacheHandler.java +++ b/embers-services/src/main/java/adf/embers/cache/QueryResultCacheHandler.java @@ -3,12 +3,12 @@ import adf.embers.query.QueryProcessor; import adf.embers.query.QueryResult; -import javax.inject.Inject; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import static adf.embers.statics.UrlTools.decodeString; diff --git a/embers-services/src/main/java/adf/embers/cache/QueryResultCacheProcessor.java b/embers-services/src/main/java/adf/embers/cache/QueryResultCacheProcessor.java index 3c90067..8e8d1a8 100644 --- a/embers-services/src/main/java/adf/embers/cache/QueryResultCacheProcessor.java +++ b/embers-services/src/main/java/adf/embers/cache/QueryResultCacheProcessor.java @@ -11,6 +11,7 @@ import adf.embers.query.persistence.Query; import adf.embers.query.persistence.QueryDao; +import jakarta.inject.Inject; import java.util.Date; import java.util.List; import java.util.Map; @@ -21,6 +22,7 @@ public class QueryResultCacheProcessor implements QueryProcessor { private QueryDao queryDao; private QueryExecutor queryExecutor; + @Inject public QueryResultCacheProcessor(QueryResultCacheDao queryResultCacheDao, QueryDao queryDao, QueryExecutor queryExecutor) { this.queryResultCacheDao = queryResultCacheDao; this.queryDao = queryDao; diff --git a/embers-services/src/main/java/adf/embers/query/QueryHandler.java b/embers-services/src/main/java/adf/embers/query/QueryHandler.java index 54808ef..5867a78 100644 --- a/embers-services/src/main/java/adf/embers/query/QueryHandler.java +++ b/embers-services/src/main/java/adf/embers/query/QueryHandler.java @@ -1,11 +1,11 @@ package adf.embers.query; -import javax.inject.Inject; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import java.net.HttpURLConnection; import static adf.embers.statics.UrlTools.decodeString; diff --git a/embers-services/src/test/java/adf/embers/admin/AdminQueryHandlerTest.java b/embers-services/src/test/java/adf/embers/admin/AdminQueryHandlerTest.java index 0cbdbec..a1b8c6f 100644 --- a/embers-services/src/test/java/adf/embers/admin/AdminQueryHandlerTest.java +++ b/embers-services/src/test/java/adf/embers/admin/AdminQueryHandlerTest.java @@ -2,11 +2,10 @@ import adf.embers.query.persistence.Query; import adf.embers.query.persistence.QueryDao; +import jakarta.ws.rs.core.Response; import org.fest.assertions.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; - -import javax.ws.rs.core.Response; import java.net.HttpURLConnection; import static org.fest.assertions.api.Assertions.assertThat; diff --git a/embers-services/src/test/java/adf/embers/cache/QueryResultCacheHandlerTest.java b/embers-services/src/test/java/adf/embers/cache/QueryResultCacheHandlerTest.java index 56b2d1b..cdf0bc9 100644 --- a/embers-services/src/test/java/adf/embers/cache/QueryResultCacheHandlerTest.java +++ b/embers-services/src/test/java/adf/embers/cache/QueryResultCacheHandlerTest.java @@ -3,14 +3,13 @@ import adf.embers.query.QueryProcessor; import adf.embers.query.QueryRequest; import adf.embers.query.QueryResult; +import jakarta.ws.rs.core.Response; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import javax.ws.rs.core.Response; - import static java.net.HttpURLConnection.HTTP_NOT_FOUND; import static org.fest.assertions.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; diff --git a/embers-spring/build.gradle b/embers-spring/build.gradle index 6c914d4..b8bd1bb 100644 --- a/embers-spring/build.gradle +++ b/embers-spring/build.gradle @@ -1,22 +1,33 @@ plugins { - id 'org.springframework.boot' version '2.7.18' - id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id 'org.springframework.boot' version '3.2.0' + id 'io.spring.dependency-management' version '1.1.4' + id 'java' } description = """Example project showing how to mix embers into a spring-boot application.""" dependencies { - implementation project(":embers-services") implementation 'org.springframework.boot:spring-boot-starter-jersey' - implementation "org.springframework.boot:spring-boot-starter-web" + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-jdbc' + + // Jackson for JSON processing + implementation 'com.fasterxml.jackson.core:jackson-databind' + implementation 'com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-json-provider' + + // Jakarta EE API dependencies - using versions compatible with Spring Boot 3.x + implementation 'jakarta.ws.rs:jakarta.ws.rs-api:3.1.0' + implementation 'jakarta.annotation:jakarta.annotation-api:2.1.1' + + // H2 Database for testing + runtimeOnly 'com.h2database:h2' testImplementation project(":embers-acceptance-tests") testImplementation libs.bundles.database testImplementation libs.bundles.unit.tests - testImplementation "io.rest-assured:rest-assured:3.3.0" - testImplementation "org.springframework.boot:spring-boot-starter-test" - + testImplementation 'io.rest-assured:rest-assured:5.3.0' // For Jakarta EE 9+ compatibility + testImplementation 'org.springframework.boot:spring-boot-starter-test' } test { diff --git a/embers-spring/jdbc:h2:mem:testdb.properties b/embers-spring/jdbc:h2:mem:testdb.properties new file mode 100644 index 0000000..54f6819 --- /dev/null +++ b/embers-spring/jdbc:h2:mem:testdb.properties @@ -0,0 +1,5 @@ +#HSQL Database Engine 2.7.4 +#Sun Jun 01 21:53:07 BST 2025 +tx_timestamp=10 +modified=no +version=2.7.4 diff --git a/embers-spring/jdbc:h2:mem:testdb.script b/embers-spring/jdbc:h2:mem:testdb.script new file mode 100644 index 0000000..07d9ce7 --- /dev/null +++ b/embers-spring/jdbc:h2:mem:testdb.script @@ -0,0 +1,52 @@ +SET DATABASE UNIQUE NAME HSQLDB972D44F328 +SET DATABASE DEFAULT RESULT MEMORY ROWS 0 +SET DATABASE EVENT LOG LEVEL 0 +SET DATABASE TRANSACTION CONTROL LOCKS +SET DATABASE DEFAULT ISOLATION LEVEL READ COMMITTED +SET DATABASE TRANSACTION ROLLBACK ON CONFLICT TRUE +SET DATABASE TEXT TABLE DEFAULTS '' +SET DATABASE SQL NAMES FALSE +SET DATABASE SQL RESTRICT EXEC FALSE +SET DATABASE SQL REFERENCES FALSE +SET DATABASE SQL SIZE TRUE +SET DATABASE SQL TYPES FALSE +SET DATABASE SQL TDC DELETE TRUE +SET DATABASE SQL TDC UPDATE TRUE +SET DATABASE SQL SYS INDEX NAMES TRUE +SET DATABASE SQL CONCAT NULLS TRUE +SET DATABASE SQL UNIQUE NULLS TRUE +SET DATABASE SQL CONVERT TRUNCATE TRUE +SET DATABASE SQL AVG SCALE 0 +SET DATABASE SQL DOUBLE NAN TRUE +SET FILES WRITE DELAY 500 MILLIS +SET FILES BACKUP INCREMENT TRUE +SET FILES CACHE SIZE 10000 +SET FILES CACHE ROWS 50000 +SET FILES SCALE 32 +SET FILES LOB SCALE 32 +SET FILES DEFRAG 0 +SET FILES NIO TRUE +SET FILES NIO SIZE 256 +SET FILES LOG TRUE +SET FILES LOG SIZE 50 +SET FILES CHECK 10 +SET DATABASE COLLATION SQL_TEXT PAD SPACE +CREATE USER SA PASSWORD DIGEST 'd41d8cd98f00b204e9800998ecf8427e' +ALTER USER SA SET LOCAL TRUE +CREATE SCHEMA PUBLIC AUTHORIZATION DBA +CREATE MEMORY TABLE PUBLIC.QUERIES(ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY,NAME VARCHAR(50) NOT NULL,SQL VARCHAR(2000) NOT NULL,DESCRIPTION VARCHAR(1000),CACHEABLE_DURATION INTEGER) +ALTER TABLE PUBLIC.QUERIES ALTER COLUMN ID RESTART WITH 1 +CREATE MEMORY TABLE PUBLIC.QUERIES_STATISTICS(ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY,QUERY_NAME VARCHAR(50),DATE_EXECUTED TIMESTAMP,DURATION BIGINT,RESULT VARCHAR(100)) +ALTER TABLE PUBLIC.QUERIES_STATISTICS ALTER COLUMN ID RESTART WITH 1 +CREATE MEMORY TABLE PUBLIC.QUERY_RESULT_CACHE(QUERY_RESULT_CACHE_ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY,QUERY_NAME VARCHAR(50) NOT NULL,LIVE_DURATION_MS INTEGER NOT NULL,DATE_CACHED TIMESTAMP,RESULT CLOB(1G)) +ALTER TABLE PUBLIC.QUERY_RESULT_CACHE ALTER COLUMN QUERY_RESULT_CACHE_ID RESTART WITH 1 +ALTER SEQUENCE SYSTEM_LOBS.LOB_ID RESTART WITH 1 +SET DATABASE DEFAULT INITIAL SCHEMA PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CARDINAL_NUMBER TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.YES_OR_NO TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CHARACTER_DATA TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.SQL_IDENTIFIER TO PUBLIC +GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.TIME_STAMP TO PUBLIC +GRANT DBA TO SA +SET SCHEMA SYSTEM_LOBS +INSERT INTO BLOCKS VALUES(0,2147483647,0) diff --git a/embers-spring/src/main/java/adf/embers/examples/spring/EmbersSpringConfiguration.java b/embers-spring/src/main/java/adf/embers/examples/spring/EmbersSpringConfiguration.java index ba47104..03f307c 100644 --- a/embers-spring/src/main/java/adf/embers/examples/spring/EmbersSpringConfiguration.java +++ b/embers-spring/src/main/java/adf/embers/examples/spring/EmbersSpringConfiguration.java @@ -4,9 +4,8 @@ import adf.embers.configuration.EmbersProcessorConfiguration; import adf.embers.configuration.EmbersRepositoryConfiguration; import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.ServerProperties; import org.glassfish.jersey.servlet.ServletContainer; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -15,39 +14,64 @@ @Configuration public class EmbersSpringConfiguration { - public static final String EMBERS = "embers"; - @Autowired - DataSource dataSource; + @Bean + public EmbersRepositoryConfiguration embersRepositoryConfiguration(DataSource dataSource) { + return new EmbersRepositoryConfiguration(dataSource); + } + + @Bean + public EmbersProcessorConfiguration embersProcessorConfiguration(EmbersRepositoryConfiguration embersRepositoryConfiguration) { + return new EmbersProcessorConfiguration(embersRepositoryConfiguration); + } @Bean - EmbersHandlerConfiguration embersHandlerConfiguration() { - EmbersRepositoryConfiguration embersRepositoryConfiguration = new EmbersRepositoryConfiguration(dataSource); - EmbersProcessorConfiguration embersProcessorConfiguration = new EmbersProcessorConfiguration(embersRepositoryConfiguration); - return new EmbersHandlerConfiguration(embersProcessorConfiguration); + public EmbersHandlerConfiguration embersHandlerConfiguration(EmbersProcessorConfiguration embersProcessorConfiguration) { + return new EmbersHandlerConfiguration( + embersProcessorConfiguration.queryDao(), + embersProcessorConfiguration.queryProcessor(), + embersProcessorConfiguration.cachedQueryProcessor() + ); } @Bean - @Qualifier(EMBERS) - public ResourceConfig resourceConfig( - @Autowired EmbersHandlerConfiguration handlerConfiguration - ) { + @org.springframework.beans.factory.annotation.Qualifier(EMBERS) + public ResourceConfig resourceConfig(EmbersHandlerConfiguration handlerConfiguration) { ResourceConfig resourceConfig = new ResourceConfig(); + + // Register the handlers resourceConfig.register(handlerConfiguration.getQueryHandler()); resourceConfig.register(handlerConfiguration.getAdminQueryHandler()); resourceConfig.register(handlerConfiguration.getQueryResultCacheHandler()); + + // Configure Jersey + resourceConfig.packages("adf.embers"); + resourceConfig.property(ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, true); + resourceConfig.property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true); + + // Enable Jackson JSON processing + resourceConfig.register(org.glassfish.jersey.jackson.JacksonFeature.class); + resourceConfig.register(com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider.class); + return resourceConfig; } - /** - * Registers the ResourceConfig to path /embers/* - */ @Bean - public ServletRegistrationBean servletRegistrationBean( - @Autowired @Qualifier(EMBERS) ResourceConfig resourceConfig - ) { - ServletContainer servletContainer = new ServletContainer(resourceConfig); - return new ServletRegistrationBean(servletContainer, "/embers/*"); + public ServletRegistrationBean servletRegistrationBean( + @org.springframework.beans.factory.annotation.Qualifier(EMBERS) ResourceConfig resourceConfig) { + // Create a new ResourceConfig that wraps our existing one + ResourceConfig config = new ResourceConfig() + .registerResources(resourceConfig.getConfiguration()) + .property(ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, true) + .property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true); + + // Create and configure the servlet + ServletContainer servletContainer = new ServletContainer(config); + ServletRegistrationBean registration = new ServletRegistrationBean<>( + servletContainer, "/" + EMBERS + "/*"); + registration.setName("jersey-servlet"); + registration.setLoadOnStartup(1); + return registration; } } diff --git a/embers-spring/src/test/java/adf/embers/examples/spring/ApplicationTest.java b/embers-spring/src/test/java/adf/embers/examples/spring/ApplicationTest.java index 8991dc1..8d024a2 100644 --- a/embers-spring/src/test/java/adf/embers/examples/spring/ApplicationTest.java +++ b/embers-spring/src/test/java/adf/embers/examples/spring/ApplicationTest.java @@ -4,30 +4,42 @@ import adf.embers.cache.QueryResultCacheHandler; import adf.embers.query.QueryHandler; import io.restassured.RestAssured; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.test.context.ActiveProfiles; import java.io.IOException; import java.net.URI; +import java.util.logging.Logger; import static org.assertj.core.api.Assertions.assertThat; -@RunWith(SpringRunner.class) @SpringBootTest( - classes = {SpringDataSourceConfiguration.class, Application.class}, - webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, - properties = {"server.port=8080"}) + classes = {Application.class, SpringDataSourceConfiguration.class}, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") public class ApplicationTest { + private static final Logger log = Logger.getLogger(ApplicationTest.class.getName()); + + @LocalServerPort + private int port; + + @BeforeEach + public void setUp() { + RestAssured.port = port; + log.info("Using port: " + port); + } @Test public void query_accessible() throws IOException, InterruptedException { String responseBody = - RestAssured.when() - .get(embersUri(QueryHandler.PATH + "/unknownQuery")). - then().statusCode(404) - .extract().response().body().asString(); + RestAssured.when() + .get(embersUri(QueryHandler.PATH + "/unknownQuery")) + .then() + .statusCode(404) + .extract().response().body().asString(); assertThat(responseBody).isEqualTo("Query not found: unknownQuery"); } @@ -52,8 +64,11 @@ public void cached_accessible() throws IOException, InterruptedException { assertThat(responseBody).isEqualTo("Query not found: unknownQuery"); } - private URI embersUri(String endpoint) { - return URI.create("http://localhost:8080/embers" + endpoint); + private URI embersUri(String path) { + String uri = String.format("http://localhost:%d/embers%s", + port, path.startsWith("/") ? path : "/" + path); + log.info("Calling URI: " + uri); + return URI.create(uri); } -} \ No newline at end of file +} diff --git a/embers-spring/src/test/java/adf/embers/examples/spring/SpringDataSourceConfiguration.java b/embers-spring/src/test/java/adf/embers/examples/spring/SpringDataSourceConfiguration.java index 6a89d13..56d02a5 100644 --- a/embers-spring/src/test/java/adf/embers/examples/spring/SpringDataSourceConfiguration.java +++ b/embers-spring/src/test/java/adf/embers/examples/spring/SpringDataSourceConfiguration.java @@ -1,26 +1,106 @@ package adf.embers.examples.spring; import adf.embers.tools.EmbersDatabase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; import javax.sql.DataSource; +/** + * Configuration for setting up the test data source using H2 in-memory database. + * This configuration is only active when the 'test' profile is active. + */ @Configuration -public class SpringDataSourceConfiguration { +@Profile("test") +public class SpringDataSourceConfiguration implements DisposableBean { + private static final Logger log = LoggerFactory.getLogger(SpringDataSourceConfiguration.class); + private final EmbersDatabase embersDatabase; + private final String jdbcUrl; + private final String username; + private final String password; - public SpringDataSourceConfiguration() throws Exception { - embersDatabase = new EmbersDatabase(EmbersDatabase.JDBC_URL); - embersDatabase.startInMemoryDatabase(); - embersDatabase.createTableQueries(); - embersDatabase.createTableQueriesStatistics(); - embersDatabase.createTableQueryResultCache(); + /** + * Constructor with configurable properties. + * Default values are provided for test environment. + */ + public SpringDataSourceConfiguration( + @Value("${spring.datasource.url:jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE}") String jdbcUrl, + @Value("${spring.datasource.username:sa}") String username, + @Value("${spring.datasource.password:}") String password) { + this.jdbcUrl = jdbcUrl; + this.username = username; + this.password = password; + this.embersDatabase = new EmbersDatabase(jdbcUrl); } + /** + * Initialize the in-memory database and create necessary tables. + */ + @PostConstruct + public void initialize() { + try { + log.info("Initializing in-memory H2 database at: {}", jdbcUrl); + this.embersDatabase.startInMemoryDatabase(); + this.embersDatabase.createTableQueries(); + this.embersDatabase.createTableQueriesStatistics(); + this.embersDatabase.createTableQueryResultCache(); + log.info("Successfully initialized in-memory H2 database"); + } catch (Exception e) { + log.error("Failed to initialize in-memory H2 database", e); + throw new IllegalStateException("Failed to initialize in-memory H2 database", e); + } + } + + /** + * Configures and provides a DataSource bean. + * @return Configured DataSource + */ @Bean public DataSource dataSource() { - return embersDatabase.getDataSource(); + log.info("Configuring DataSource with URL: {}", jdbcUrl); + try { + // Load the H2 driver class + Class.forName("org.h2.Driver"); + + // Create and configure the DataSource + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName("org.h2.Driver"); + dataSource.setUrl(jdbcUrl); + dataSource.setUsername(username); + dataSource.setPassword(password); + + log.info("Successfully configured DataSource"); + return dataSource; + } catch (ClassNotFoundException e) { + log.error("Failed to load H2 JDBC Driver", e); + throw new IllegalStateException("H2 JDBC Driver not found. Make sure it's included in the classpath.", e); + } catch (Exception e) { + log.error("Failed to configure DataSource", e); + throw new RuntimeException("Failed to configure DataSource", e); + } + } + + /** + * Clean up resources when the application context is destroyed. + */ + @Override + @PreDestroy + public void destroy() { + log.info("Shutting down in-memory H2 database"); + try { + this.embersDatabase.shutdownInMemoryDatabase(); + } catch (Exception e) { + log.warn("Error while shutting down in-memory H2 database", e); + } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 00243cd..edfe4db 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,21 +7,24 @@ mockito = "3.8.0" gson = { module = "com.google.code.gson:gson", version = "2.8.2" } json_assert = { module = "org.skyscreamer:jsonassert", version = "1.2.3" } -javax_ws_rs = { module = "javax.ws.rs:javax.ws.rs-api", version = "2.1" } -javax_inject = { module = "javax.inject:javax.inject", version = "1" } -javax_activation = { module = "javax.activation:activation", version = "1.1.1" } +jakarta_ws_rs = { module = "jakarta.ws.rs:jakarta.ws.rs-api", version = "3.1.0" } +jakarta_servlet = { module = "jakarta.servlet:jakarta.servlet-api", version = "6.0.0" } +jakarta_inject = { module = "jakarta.inject:jakarta.inject-api", version = "2.0.1" } javax_xml_bind = { module = "javax.xml.bind:jaxb-api", version.ref = "jaxb" } jaxb_core = { module = "com.sun.xml.bind:jaxb-core", version.ref = "jaxb" } jaxb_impl = { module = "com.sun.xml.bind:jaxb-impl", version.ref = "jaxb" } jdbi = { module = "org.jdbi:jdbi", version = "2.78" } -jaxson = { module = "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider", version = "2.5.2"} +jaxson = { module = "com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-json-provider", version = "2.16.1" } -jersey_server = { module = "org.glassfish.jersey.core:jersey-server", version = "2.2" } -jersey_container = { module = "org.glassfish.jersey.containers:jersey-container-servlet", version = "2.2" } +jersey_server = { module = "org.glassfish.jersey.core:jersey-server", version = "3.1.3" } +jersey_container = { module = "org.glassfish.jersey.containers:jersey-container-servlet", version = "3.1.3" } +jersey_media_json = { module = "org.glassfish.jersey.media:jersey-media-json-jackson", version = "3.1.3" } -jetty_server = { module = "org.eclipse.jetty:jetty-server", version = "9.3.0.M1" } -jetty_servlet = { module = "org.eclipse.jetty:jetty-servlet", version = "9.3.0.M1" } +jetty_server = { module = "org.eclipse.jetty.ee10:jetty-ee10-servlet", version = "12.0.7" } +jetty_http = { module = "org.eclipse.jetty:jetty-http", version = "12.0.7" } +jetty_io = { module = "org.eclipse.jetty:jetty-io", version = "12.0.7" } +jetty_util = { module = "org.eclipse.jetty:jetty-util", version = "12.0.7" } hsqldb = { module = "org.hsqldb:hsqldb", version = "2.7.4" } @@ -32,10 +35,26 @@ mockito_junit_jupiter = { module = "org.mockito:mockito-junit-jupiter", version. yatspec = { module = "com.github.nickmcdowall:yatspec", version = "2021.1.1" } +# Jakarta EE 10 dependencies +jakarta_websocket_api = { module = "jakarta.websocket:jakarta.websocket-api", version = "2.1.1" } +jakarta_websocket_client_api = { module = "jakarta.websocket:jakarta.websocket-client-api", version = "2.1.1" } +# Using an older version of JSTL that's more stable with our setup +jstl = { module = "org.glassfish.web:jakarta.servlet.jsp.jstl", version = "2.0.0" } + +# Jersey and HK2 integration +jersey_container_servlet = { module = "org.glassfish.jersey.containers:jersey-container-servlet", version = "3.1.3" } +jersey_hk2 = { module = "org.glassfish.jersey.inject:jersey-hk2", version = "3.1.3" } + +# HK2 (Hundred-Kilobyte Kernel) dependencies +hk2_api = { module = "org.glassfish.hk2:hk2-api", version = "3.0.5" } +hk2_locator = { module = "org.glassfish.hk2:hk2-locator", version = "3.0.5" } +hk2_utils = { module = "org.glassfish.hk2:hk2-utils", version = "3.0.5" } +hk2_runlevel = { module = "org.glassfish.hk2:hk2-runlevel", version = "3.0.5" } + [bundles] core = [ # the only libraries the production jar depends on - "javax_ws_rs", "javax_inject", "javax_activation", "javax_xml_bind", "jaxb_core", "jaxb_impl", "jdbi" + "jakarta_ws_rs", "jakarta_servlet", "jakarta_inject", "javax_xml_bind", "jaxb_core", "jaxb_impl", "jdbi" ] unit_tests = [ @@ -47,14 +66,21 @@ acceptance_tests = [ "yatspec" ] +jakarta_web_server = [ + "jakarta_websocket_api", "jakarta_websocket_client_api", "jstl" +] + jersey = [ - # implements javax.ws.rs - "jersey_server", "jersey_container" + # implements jakarta.ws.rs with HK2 + "jersey_server", "jersey_container_servlet", "jersey_media_json", "jersey_hk2", + + # HK2 (Hundred-Kilobyte Kernel) dependencies + "hk2_api", "hk2_locator", "hk2_utils", "hk2_runlevel" ] jetty = [ # beloved server - "jetty_server", "jetty_servlet" + "jetty_server", "jetty_http", "jetty_io", "jetty_util" ] database = [ From 15ccafd422ec80ceb05c12acac0e4af94785acfb Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 1 Jun 2025 22:32:44 +0100 Subject: [PATCH 07/12] upgraded to spring 3 --- .../java/adf/embers/tools/EmbersDatabase.java | 1 + embers-spring/build.gradle | 13 ++-- embers-spring/jdbc:h2:mem:testdb.properties | 5 -- embers-spring/jdbc:h2:mem:testdb.script | 52 -------------- .../spring/EmbersSpringConfiguration.java | 7 +- .../examples/spring/ApplicationTest.java | 7 +- .../spring/SpringDataSourceConfiguration.java | 71 ++++--------------- 7 files changed, 26 insertions(+), 130 deletions(-) delete mode 100644 embers-spring/jdbc:h2:mem:testdb.properties delete mode 100644 embers-spring/jdbc:h2:mem:testdb.script diff --git a/embers-acceptance-tests/src/main/java/adf/embers/tools/EmbersDatabase.java b/embers-acceptance-tests/src/main/java/adf/embers/tools/EmbersDatabase.java index 0efa14c..d1da7b3 100644 --- a/embers-acceptance-tests/src/main/java/adf/embers/tools/EmbersDatabase.java +++ b/embers-acceptance-tests/src/main/java/adf/embers/tools/EmbersDatabase.java @@ -29,6 +29,7 @@ public EmbersDatabase(String jdbcUrl) { this.jdbcUrl = jdbcUrl; } + public void startInMemoryDatabase() throws Exception { System.out.println("Starting the Embers database"); DriverManager.registerDriver(jdbcDriver.driverInstance); diff --git a/embers-spring/build.gradle b/embers-spring/build.gradle index b8bd1bb..0c8d0de 100644 --- a/embers-spring/build.gradle +++ b/embers-spring/build.gradle @@ -6,6 +6,11 @@ plugins { description = """Example project showing how to mix embers into a spring-boot application.""" +configurations.all { + // Exclude commons-logging as we're using spring-jcl + exclude group: 'commons-logging', module: 'commons-logging' +} + dependencies { implementation project(":embers-services") implementation 'org.springframework.boot:spring-boot-starter-jersey' @@ -19,15 +24,15 @@ dependencies { // Jakarta EE API dependencies - using versions compatible with Spring Boot 3.x implementation 'jakarta.ws.rs:jakarta.ws.rs-api:3.1.0' implementation 'jakarta.annotation:jakarta.annotation-api:2.1.1' - - // H2 Database for testing - runtimeOnly 'com.h2database:h2' + // Testing testImplementation project(":embers-acceptance-tests") testImplementation libs.bundles.database testImplementation libs.bundles.unit.tests testImplementation 'io.rest-assured:rest-assured:5.3.0' // For Jakarta EE 9+ compatibility - testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation('org.springframework.boot:spring-boot-starter-test') { + exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' + } } test { diff --git a/embers-spring/jdbc:h2:mem:testdb.properties b/embers-spring/jdbc:h2:mem:testdb.properties deleted file mode 100644 index 54f6819..0000000 --- a/embers-spring/jdbc:h2:mem:testdb.properties +++ /dev/null @@ -1,5 +0,0 @@ -#HSQL Database Engine 2.7.4 -#Sun Jun 01 21:53:07 BST 2025 -tx_timestamp=10 -modified=no -version=2.7.4 diff --git a/embers-spring/jdbc:h2:mem:testdb.script b/embers-spring/jdbc:h2:mem:testdb.script deleted file mode 100644 index 07d9ce7..0000000 --- a/embers-spring/jdbc:h2:mem:testdb.script +++ /dev/null @@ -1,52 +0,0 @@ -SET DATABASE UNIQUE NAME HSQLDB972D44F328 -SET DATABASE DEFAULT RESULT MEMORY ROWS 0 -SET DATABASE EVENT LOG LEVEL 0 -SET DATABASE TRANSACTION CONTROL LOCKS -SET DATABASE DEFAULT ISOLATION LEVEL READ COMMITTED -SET DATABASE TRANSACTION ROLLBACK ON CONFLICT TRUE -SET DATABASE TEXT TABLE DEFAULTS '' -SET DATABASE SQL NAMES FALSE -SET DATABASE SQL RESTRICT EXEC FALSE -SET DATABASE SQL REFERENCES FALSE -SET DATABASE SQL SIZE TRUE -SET DATABASE SQL TYPES FALSE -SET DATABASE SQL TDC DELETE TRUE -SET DATABASE SQL TDC UPDATE TRUE -SET DATABASE SQL SYS INDEX NAMES TRUE -SET DATABASE SQL CONCAT NULLS TRUE -SET DATABASE SQL UNIQUE NULLS TRUE -SET DATABASE SQL CONVERT TRUNCATE TRUE -SET DATABASE SQL AVG SCALE 0 -SET DATABASE SQL DOUBLE NAN TRUE -SET FILES WRITE DELAY 500 MILLIS -SET FILES BACKUP INCREMENT TRUE -SET FILES CACHE SIZE 10000 -SET FILES CACHE ROWS 50000 -SET FILES SCALE 32 -SET FILES LOB SCALE 32 -SET FILES DEFRAG 0 -SET FILES NIO TRUE -SET FILES NIO SIZE 256 -SET FILES LOG TRUE -SET FILES LOG SIZE 50 -SET FILES CHECK 10 -SET DATABASE COLLATION SQL_TEXT PAD SPACE -CREATE USER SA PASSWORD DIGEST 'd41d8cd98f00b204e9800998ecf8427e' -ALTER USER SA SET LOCAL TRUE -CREATE SCHEMA PUBLIC AUTHORIZATION DBA -CREATE MEMORY TABLE PUBLIC.QUERIES(ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY,NAME VARCHAR(50) NOT NULL,SQL VARCHAR(2000) NOT NULL,DESCRIPTION VARCHAR(1000),CACHEABLE_DURATION INTEGER) -ALTER TABLE PUBLIC.QUERIES ALTER COLUMN ID RESTART WITH 1 -CREATE MEMORY TABLE PUBLIC.QUERIES_STATISTICS(ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY,QUERY_NAME VARCHAR(50),DATE_EXECUTED TIMESTAMP,DURATION BIGINT,RESULT VARCHAR(100)) -ALTER TABLE PUBLIC.QUERIES_STATISTICS ALTER COLUMN ID RESTART WITH 1 -CREATE MEMORY TABLE PUBLIC.QUERY_RESULT_CACHE(QUERY_RESULT_CACHE_ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY,QUERY_NAME VARCHAR(50) NOT NULL,LIVE_DURATION_MS INTEGER NOT NULL,DATE_CACHED TIMESTAMP,RESULT CLOB(1G)) -ALTER TABLE PUBLIC.QUERY_RESULT_CACHE ALTER COLUMN QUERY_RESULT_CACHE_ID RESTART WITH 1 -ALTER SEQUENCE SYSTEM_LOBS.LOB_ID RESTART WITH 1 -SET DATABASE DEFAULT INITIAL SCHEMA PUBLIC -GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CARDINAL_NUMBER TO PUBLIC -GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.YES_OR_NO TO PUBLIC -GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CHARACTER_DATA TO PUBLIC -GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.SQL_IDENTIFIER TO PUBLIC -GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.TIME_STAMP TO PUBLIC -GRANT DBA TO SA -SET SCHEMA SYSTEM_LOBS -INSERT INTO BLOCKS VALUES(0,2147483647,0) diff --git a/embers-spring/src/main/java/adf/embers/examples/spring/EmbersSpringConfiguration.java b/embers-spring/src/main/java/adf/embers/examples/spring/EmbersSpringConfiguration.java index 03f307c..4bf28cf 100644 --- a/embers-spring/src/main/java/adf/embers/examples/spring/EmbersSpringConfiguration.java +++ b/embers-spring/src/main/java/adf/embers/examples/spring/EmbersSpringConfiguration.java @@ -60,14 +60,9 @@ public ResourceConfig resourceConfig(EmbersHandlerConfiguration handlerConfigura @Bean public ServletRegistrationBean servletRegistrationBean( @org.springframework.beans.factory.annotation.Qualifier(EMBERS) ResourceConfig resourceConfig) { - // Create a new ResourceConfig that wraps our existing one - ResourceConfig config = new ResourceConfig() - .registerResources(resourceConfig.getConfiguration()) - .property(ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, true) - .property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true); // Create and configure the servlet - ServletContainer servletContainer = new ServletContainer(config); + ServletContainer servletContainer = new ServletContainer(resourceConfig); ServletRegistrationBean registration = new ServletRegistrationBean<>( servletContainer, "/" + EMBERS + "/*"); registration.setName("jersey-servlet"); diff --git a/embers-spring/src/test/java/adf/embers/examples/spring/ApplicationTest.java b/embers-spring/src/test/java/adf/embers/examples/spring/ApplicationTest.java index 8d024a2..c09cab3 100644 --- a/embers-spring/src/test/java/adf/embers/examples/spring/ApplicationTest.java +++ b/embers-spring/src/test/java/adf/embers/examples/spring/ApplicationTest.java @@ -10,7 +10,6 @@ import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.ActiveProfiles; -import java.io.IOException; import java.net.URI; import java.util.logging.Logger; @@ -33,7 +32,7 @@ public void setUp() { } @Test - public void query_accessible() throws IOException, InterruptedException { + public void query_accessible() { String responseBody = RestAssured.when() .get(embersUri(QueryHandler.PATH + "/unknownQuery")) @@ -45,7 +44,7 @@ public void query_accessible() throws IOException, InterruptedException { } @Test - public void admin_accessible() throws IOException, InterruptedException { + public void admin_accessible() { String responseBody = RestAssured.when() .delete(embersUri(AdminQueryHandler.PATH + "/unknownQuery")) .then().statusCode(200) @@ -55,7 +54,7 @@ public void admin_accessible() throws IOException, InterruptedException { } @Test - public void cached_accessible() throws IOException, InterruptedException { + public void cached_accessible() { String responseBody = RestAssured.when() .get(embersUri(QueryResultCacheHandler.PATH + "/unknownQuery")) .then().statusCode(404) diff --git a/embers-spring/src/test/java/adf/embers/examples/spring/SpringDataSourceConfiguration.java b/embers-spring/src/test/java/adf/embers/examples/spring/SpringDataSourceConfiguration.java index 56d02a5..c2e864e 100644 --- a/embers-spring/src/test/java/adf/embers/examples/spring/SpringDataSourceConfiguration.java +++ b/embers-spring/src/test/java/adf/embers/examples/spring/SpringDataSourceConfiguration.java @@ -1,17 +1,15 @@ package adf.embers.examples.spring; import adf.embers.tools.EmbersDatabase; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; -import org.springframework.jdbc.datasource.DriverManagerDataSource; -import jakarta.annotation.PostConstruct; -import jakarta.annotation.PreDestroy; import javax.sql.DataSource; /** @@ -23,80 +21,35 @@ public class SpringDataSourceConfiguration implements DisposableBean { private static final Logger log = LoggerFactory.getLogger(SpringDataSourceConfiguration.class); - + private final EmbersDatabase embersDatabase; - private final String jdbcUrl; - private final String username; - private final String password; - /** - * Constructor with configurable properties. - * Default values are provided for test environment. - */ - public SpringDataSourceConfiguration( - @Value("${spring.datasource.url:jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE}") String jdbcUrl, - @Value("${spring.datasource.username:sa}") String username, - @Value("${spring.datasource.password:}") String password) { - this.jdbcUrl = jdbcUrl; - this.username = username; - this.password = password; - this.embersDatabase = new EmbersDatabase(jdbcUrl); + public SpringDataSourceConfiguration() { + this.embersDatabase = new EmbersDatabase(EmbersDatabase.JDBC_URL); } /** * Initialize the in-memory database and create necessary tables. */ @PostConstruct - public void initialize() { - try { - log.info("Initializing in-memory H2 database at: {}", jdbcUrl); - this.embersDatabase.startInMemoryDatabase(); - this.embersDatabase.createTableQueries(); - this.embersDatabase.createTableQueriesStatistics(); - this.embersDatabase.createTableQueryResultCache(); - log.info("Successfully initialized in-memory H2 database"); - } catch (Exception e) { - log.error("Failed to initialize in-memory H2 database", e); - throw new IllegalStateException("Failed to initialize in-memory H2 database", e); - } + public void initialize() throws Exception { + this.embersDatabase.startInMemoryDatabase(); + this.embersDatabase.createTableQueries(); + this.embersDatabase.createTableQueriesStatistics(); + this.embersDatabase.createTableQueryResultCache(); } /** - * Configures and provides a DataSource bean. * @return Configured DataSource */ @Bean public DataSource dataSource() { - log.info("Configuring DataSource with URL: {}", jdbcUrl); - try { - // Load the H2 driver class - Class.forName("org.h2.Driver"); - - // Create and configure the DataSource - DriverManagerDataSource dataSource = new DriverManagerDataSource(); - dataSource.setDriverClassName("org.h2.Driver"); - dataSource.setUrl(jdbcUrl); - dataSource.setUsername(username); - dataSource.setPassword(password); - - log.info("Successfully configured DataSource"); - return dataSource; - } catch (ClassNotFoundException e) { - log.error("Failed to load H2 JDBC Driver", e); - throw new IllegalStateException("H2 JDBC Driver not found. Make sure it's included in the classpath.", e); - } catch (Exception e) { - log.error("Failed to configure DataSource", e); - throw new RuntimeException("Failed to configure DataSource", e); - } + return this.embersDatabase.getDataSource(); } - - /** - * Clean up resources when the application context is destroyed. - */ + @Override @PreDestroy public void destroy() { - log.info("Shutting down in-memory H2 database"); try { this.embersDatabase.shutdownInMemoryDatabase(); } catch (Exception e) { From fde25fc62c877c91429320c44815d0e5f1a414a8 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 1 Jun 2025 22:38:14 +0100 Subject: [PATCH 08/12] moved libs to toml --- embers-spring/build.gradle | 6 +++--- gradle/libs.versions.toml | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/embers-spring/build.gradle b/embers-spring/build.gradle index 0c8d0de..8475a0e 100644 --- a/embers-spring/build.gradle +++ b/embers-spring/build.gradle @@ -21,9 +21,9 @@ dependencies { implementation 'com.fasterxml.jackson.core:jackson-databind' implementation 'com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-json-provider' - // Jakarta EE API dependencies - using versions compatible with Spring Boot 3.x - implementation 'jakarta.ws.rs:jakarta.ws.rs-api:3.1.0' - implementation 'jakarta.annotation:jakarta.annotation-api:2.1.1' + // Jakarta EE API dependencies - using versions from version catalog + implementation libs.jakarta.ws.rs + implementation libs.jakarta.annotation.api // Testing testImplementation project(":embers-acceptance-tests") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index edfe4db..5217153 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,9 +4,13 @@ mockito = "3.8.0" [libraries] +# Core Libraries gson = { module = "com.google.code.gson:gson", version = "2.8.2" } + +# Jakarta EE json_assert = { module = "org.skyscreamer:jsonassert", version = "1.2.3" } +jakarta_annotation_api = { module = "jakarta.annotation:jakarta.annotation-api", version = "2.1.1" } jakarta_ws_rs = { module = "jakarta.ws.rs:jakarta.ws.rs-api", version = "3.1.0" } jakarta_servlet = { module = "jakarta.servlet:jakarta.servlet-api", version = "6.0.0" } jakarta_inject = { module = "jakarta.inject:jakarta.inject-api", version = "2.0.1" } From 7cde53471ea542268b341817df2d1dc5d3349671 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 1 Jun 2025 22:42:33 +0100 Subject: [PATCH 09/12] toml version tweaks --- embers-spring/build.gradle | 2 +- gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embers-spring/build.gradle b/embers-spring/build.gradle index 8475a0e..2c729cf 100644 --- a/embers-spring/build.gradle +++ b/embers-spring/build.gradle @@ -6,7 +6,7 @@ plugins { description = """Example project showing how to mix embers into a spring-boot application.""" -configurations.all { +configurations.configureEach { // Exclude commons-logging as we're using spring-jcl exclude group: 'commons-logging', module: 'commons-logging' } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5217153..690f581 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,7 @@ gson = { module = "com.google.code.gson:gson", version = "2.8.2" } # Jakarta EE json_assert = { module = "org.skyscreamer:jsonassert", version = "1.2.3" } -jakarta_annotation_api = { module = "jakarta.annotation:jakarta.annotation-api", version = "2.1.1" } +jakarta_annotation_api = { module = "jakarta.annotation:jakarta.annotation-api", version = "3.0.0" } jakarta_ws_rs = { module = "jakarta.ws.rs:jakarta.ws.rs-api", version = "3.1.0" } jakarta_servlet = { module = "jakarta.servlet:jakarta.servlet-api", version = "6.0.0" } jakarta_inject = { module = "jakarta.inject:jakarta.inject-api", version = "2.0.1" } From 5f54d9ffcbad2216fa67e1823829fe5276e15c71 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 1 Jun 2025 22:50:19 +0100 Subject: [PATCH 10/12] spring removed unused --- embers-spring/build.gradle | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/embers-spring/build.gradle b/embers-spring/build.gradle index 2c729cf..91edc96 100644 --- a/embers-spring/build.gradle +++ b/embers-spring/build.gradle @@ -6,11 +6,6 @@ plugins { description = """Example project showing how to mix embers into a spring-boot application.""" -configurations.configureEach { - // Exclude commons-logging as we're using spring-jcl - exclude group: 'commons-logging', module: 'commons-logging' -} - dependencies { implementation project(":embers-services") implementation 'org.springframework.boot:spring-boot-starter-jersey' @@ -18,7 +13,6 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-jdbc' // Jackson for JSON processing - implementation 'com.fasterxml.jackson.core:jackson-databind' implementation 'com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-json-provider' // Jakarta EE API dependencies - using versions from version catalog @@ -30,9 +24,7 @@ dependencies { testImplementation libs.bundles.database testImplementation libs.bundles.unit.tests testImplementation 'io.rest-assured:rest-assured:5.3.0' // For Jakarta EE 9+ compatibility - testImplementation('org.springframework.boot:spring-boot-starter-test') { - exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' - } + testImplementation 'org.springframework.boot:spring-boot-starter-test' } test { From d3b582bf0600bed9276f228159c77d0075b2bd65 Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 2 Jun 2025 20:40:13 +0100 Subject: [PATCH 11/12] fix jacoco for root --- build.gradle | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/build.gradle b/build.gradle index 73f8618..5500897 100644 --- a/build.gradle +++ b/build.gradle @@ -36,29 +36,36 @@ allprojects { } task codeCoverageReport(type: JacocoReport) { -//swiped from http://csiebler.github.io/blog/2014/02/09/multi-project-code-coverage-using-gradle-and-jacoco/ + //swiped from http://csiebler.github.io/blog/2014/02/09/multi-project-code-coverage-using-gradle-and-jacoco/ - // Gather execution data from all subprojects - // (change this if you e.g. want to calculate unit test/integration test coverage separately) - executionData fileTree(project.rootDir.absolutePath).include("**/build/jacoco/*.exec") + // Enable the report to be generated + dependsOn subprojects*.test - // Add all relevant sourcesets from the subprojects - subprojects.each { - sourceSets it.sourceSets.main - } + // Gather execution data from all subprojects + executionData fileTree(project.rootDir).include("**/build/jacoco/*.exec") + + // Configure source and class directories from all subprojects + sourceDirectories.setFrom(files(subprojects.sourceSets.main.allSource.srcDirs)) + classDirectories.setFrom(files(subprojects.sourceSets.main.output)) + + // Enable XML report for CI tools if needed reports { - html { - setEnabled(true) - outputLocation = file("${buildDir}/reports/jacoco") -// println "code coverage reports: " + html.destination - } + html.required = true + xml.required = false + csv.required = false + + html.outputLocation = layout.buildDirectory.dir('reports/jacoco') + println "Code coverage reports will be generated at: ${html.outputLocation.get()}" +// xml.outputLocation = layout.buildDirectory.file('reports/jacoco/jacocoTestReport.xml') + } } -// always run the tests before generating the report -codeCoverageReport.dependsOn { - subprojects*.test +// Configure the test task to generate execution data +tasks.withType(Test).configureEach { + finalizedBy codeCoverageReport + doLast { + logger.lifecycle("Test execution completed. Generating JaCoCo report...") + } } - -check.dependsOn jacocoTestReport From 85a5e08a8b24fd00b906b558cf173683fb9bc8d4 Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 2 Jun 2025 21:01:39 +0100 Subject: [PATCH 12/12] update circleci to jdk17++ --- .circleci/config.yml | 80 +++++++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 73f2141..004f789 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,29 +1,63 @@ -version: 2 +version: 2.1 + +orbs: + # Using the gradle orb for better caching and setup + gradle: circleci/gradle@2.2.0 + jobs: build: working_directory: ~/alfanse/embers parallelism: 1 docker: - - image: circleci/openjdk:11-jdk + - image: cimg/openjdk:17.0.10 steps: - - checkout - - run: - working_directory: ~/alfanse/embers - # for diagnostics, show me the version, includes JVM, and Gradle. - command: ./gradlew --version - # Build - - run: make build - - store_test_results: - path: embers-services/build/test-results - - store_test_results: - path: embers-acceptance-tests/build/test-results - - store_test_results: - path: embers-spring/build/test-results - - store_artifacts: - name: store embers-acceptance-tests reports - path: embers-acceptance-tests/build/yatspec - destination: yatspec - - store_artifacts: - name: store jacoco reports - path: build/reports/jacoco - destination: jacoco + - checkout + + # Restore Gradle dependencies cache + - restore_cache: + keys: + - v1-dependencies-{{ checksum "build.gradle" }} + - v1-dependencies- + + # Show versions for diagnostics + - run: + name: Show versions + command: | + java -version + ./gradlew --version + + # Build with Gradle + - run: + name: Build and test + command: ./gradlew build --no-daemon --stacktrace + environment: + # Configure Gradle to use more memory + GRADLE_OPTS: '-Dorg.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8' + + # Save Gradle dependencies cache + - save_cache: + paths: + - ~/.gradle + key: v1-dependencies-{{ checksum "build.gradle" }} + + # Store test results for CircleCI test insights + - store_test_results: + path: embers-services/build/test-results + - store_test_results: + path: embers-acceptance-tests/build/test-results + - store_test_results: + path: embers-spring/build/test-results + + # Store artifacts for later inspection + - store_artifacts: + name: Store acceptance test reports + path: embers-acceptance-tests/build/yatspec + destination: yatspec + - store_artifacts: + name: Store JaCoCo reports + path: build/reports/jacoco + destination: jacoco + - store_artifacts: + name: Store test results + path: build/reports/tests + destination: test-reports