chore(cleanup): remove unused FallbackController and outdated GatewayDependencies.txt
- Deleted `FallbackController` as it is no longer required, with alternatives already in place. - Removed `GatewayDependencies.txt` to clean up outdated and redundant dependency tracking files.
This commit is contained in:
parent
a2faf2166a
commit
6e58af1b5b
5
.gemini/settings.json
Normal file
5
.gemini/settings.json
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"general": {
|
||||||
|
"previewFeatures": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,687 +0,0 @@
|
||||||
stefan-mo@Li-Desk-Mo:~/WsMeldestelle/Meldestelle$ ./gradlew :backend:infrastructure:gateway:dependencies --configuration compileClasspath
|
|
||||||
Type-safe project accessors is an incubating feature.
|
|
||||||
|
|
||||||
> Task :backend:infrastructure:gateway:dependencies
|
|
||||||
|
|
||||||
------------------------------------------------------------
|
|
||||||
Project ':backend:infrastructure:gateway'
|
|
||||||
------------------------------------------------------------
|
|
||||||
|
|
||||||
compileClasspath - Compile classpath for 'main'.
|
|
||||||
+--- org.jetbrains.kotlin:kotlin-stdlib:2.3.0
|
|
||||||
| +--- org.jetbrains:annotations:13.0 -> 23.0.0
|
|
||||||
| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0 -> 2.3.0 (c)
|
|
||||||
| \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0 -> 2.3.0 (c)
|
|
||||||
+--- org.springframework.boot:spring-boot-dependencies:4.0.1
|
|
||||||
| +--- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.20.1 (c)
|
|
||||||
| +--- com.fasterxml.jackson.module:jackson-module-kotlin:2.20.1 (c)
|
|
||||||
| +--- org.jetbrains.kotlin:kotlin-stdlib:2.2.21 -> 2.3.0 (c)
|
|
||||||
| +--- org.springframework.security:spring-security-oauth2-jose:7.0.2 (c)
|
|
||||||
| +--- ch.qos.logback:logback-classic:1.5.22 (c)
|
|
||||||
| +--- ch.qos.logback:logback-core:1.5.22 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter-actuator:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter-data-redis:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter-oauth2-resource-server:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter-security:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter-webflux:4.0.1 (c)
|
|
||||||
| +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0 -> 1.7.3 (c)
|
|
||||||
| +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2 (c)
|
|
||||||
| +--- org.flywaydb:flyway-core:11.14.1 -> 11.19.1 (c)
|
|
||||||
| +--- org.flywaydb:flyway-database-postgresql:11.14.1 -> 11.19.1 (c)
|
|
||||||
| +--- com.zaxxer:HikariCP:7.0.2 (c)
|
|
||||||
| +--- jakarta.annotation:jakarta.annotation-api:3.0.0 (c)
|
|
||||||
| +--- org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.10.2 (c)
|
|
||||||
| +--- org.slf4j:slf4j-api:2.0.17 (c)
|
|
||||||
| +--- com.fasterxml.jackson.core:jackson-annotations:2.20 (c)
|
|
||||||
| +--- com.fasterxml.jackson.core:jackson-core:2.20.1 (c)
|
|
||||||
| +--- com.fasterxml.jackson.core:jackson-databind:2.20.1 (c)
|
|
||||||
| +--- org.jetbrains.kotlin:kotlin-reflect:2.2.21 -> 2.3.0 (c)
|
|
||||||
| +--- org.springframework.security:spring-security-core:7.0.2 (c)
|
|
||||||
| +--- org.springframework.security:spring-security-oauth2-core:7.0.2 (c)
|
|
||||||
| +--- org.springframework:spring-core:7.0.2 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter-micrometer-metrics:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-actuator-autoconfigure:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-health:4.0.1 (c)
|
|
||||||
| +--- io.micrometer:micrometer-observation:1.16.1 (c)
|
|
||||||
| +--- io.micrometer:micrometer-jakarta9:1.16.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-data-redis:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-security-oauth2-resource-server:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-security:4.0.1 (c)
|
|
||||||
| +--- org.springframework:spring-aop:7.0.2 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter-jackson:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter-reactor-netty:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-webflux:4.0.1 (c)
|
|
||||||
| +--- org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.9.0 (c)
|
|
||||||
| +--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2 (c)
|
|
||||||
| +--- io.projectreactor:reactor-core:3.8.1 (c)
|
|
||||||
| +--- org.jetbrains.kotlinx:kotlinx-coroutines-reactive:1.10.2 (c)
|
|
||||||
| +--- org.springframework.security:spring-security-crypto:7.0.2 (c)
|
|
||||||
| +--- org.springframework:spring-beans:7.0.2 (c)
|
|
||||||
| +--- org.springframework:spring-context:7.0.2 (c)
|
|
||||||
| +--- org.springframework:spring-expression:7.0.2 (c)
|
|
||||||
| +--- org.springframework:spring-web:7.0.2 (c)
|
|
||||||
| +--- commons-logging:commons-logging:1.3.5 (c)
|
|
||||||
| +--- org.jspecify:jspecify:1.0.0 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter-logging:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-autoconfigure:4.0.1 (c)
|
|
||||||
| +--- org.yaml:snakeyaml:2.5 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-micrometer-metrics:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-actuator:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot:4.0.1 (c)
|
|
||||||
| +--- io.micrometer:micrometer-commons:1.16.1 (c)
|
|
||||||
| +--- io.micrometer:micrometer-core:1.16.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-data-commons:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-transaction:4.0.1 (c)
|
|
||||||
| +--- io.lettuce:lettuce-core:6.8.1.RELEASE -> 7.2.1.RELEASE (c)
|
|
||||||
| +--- org.springframework.data:spring-data-redis:4.0.1 (c)
|
|
||||||
| +--- org.springframework.security:spring-security-oauth2-resource-server:7.0.2 (c)
|
|
||||||
| +--- org.springframework.security:spring-security-config:7.0.2 (c)
|
|
||||||
| +--- org.springframework.security:spring-security-web:7.0.2 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-jackson:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-reactor:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-reactor-netty:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-http-codec:4.0.1 (c)
|
|
||||||
| +--- org.springframework:spring-webflux:7.0.2 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-configuration-processor:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter-validation:4.0.1 (c)
|
|
||||||
| +--- io.projectreactor.addons:reactor-extra:3.6.0 (c)
|
|
||||||
| +--- com.google.code.gson:gson:2.13.2 (c)
|
|
||||||
| +--- org.apache.httpcomponents:httpcore:4.4.16 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter-cache:4.0.1 (c)
|
|
||||||
| +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.9.0 (c)
|
|
||||||
| +--- io.netty:netty-common:4.2.9.Final (c)
|
|
||||||
| +--- io.netty:netty-handler:4.2.9.Final (c)
|
|
||||||
| +--- io.netty:netty-transport:4.2.9.Final (c)
|
|
||||||
| +--- io.netty:netty-resolver-dns:4.2.9.Final (c)
|
|
||||||
| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.21 -> 2.3.0 (c)
|
|
||||||
| +--- commons-codec:commons-codec:1.19.0 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-restclient:4.0.1 (c)
|
|
||||||
| +--- org.reactivestreams:reactive-streams:1.0.4 (c)
|
|
||||||
| +--- org.apache.logging.log4j:log4j-to-slf4j:2.25.3 (c)
|
|
||||||
| +--- org.slf4j:jul-to-slf4j:2.0.17 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-micrometer-observation:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-persistence:4.0.1 (c)
|
|
||||||
| +--- org.springframework.data:spring-data-commons:4.0.1 (c)
|
|
||||||
| +--- org.springframework:spring-tx:7.0.2 (c)
|
|
||||||
| +--- org.springframework.data:spring-data-keyvalue:4.0.1 (c)
|
|
||||||
| +--- org.springframework:spring-oxm:7.0.2 (c)
|
|
||||||
| +--- org.springframework:spring-context-support:7.0.2 (c)
|
|
||||||
| +--- tools.jackson.core:jackson-databind:3.0.3 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-web-server:4.0.1 (c)
|
|
||||||
| +--- io.projectreactor.netty:reactor-netty-http:1.3.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-validation:4.0.1 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-cache:4.0.1 (c)
|
|
||||||
| +--- org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.9.0 (c)
|
|
||||||
| +--- io.netty:netty-resolver:4.2.9.Final (c)
|
|
||||||
| +--- io.netty:netty-buffer:4.2.9.Final (c)
|
|
||||||
| +--- io.netty:netty-transport-native-unix-common:4.2.9.Final (c)
|
|
||||||
| +--- io.netty:netty-codec-base:4.2.9.Final (c)
|
|
||||||
| +--- io.netty:netty-codec-dns:4.2.9.Final (c)
|
|
||||||
| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.21 -> 2.3.0 (c)
|
|
||||||
| +--- org.springframework.boot:spring-boot-http-client:4.0.1 (c)
|
|
||||||
| +--- org.apache.logging.log4j:log4j-api:2.25.3 (c)
|
|
||||||
| +--- tools.jackson.core:jackson-core:3.0.3 (c)
|
|
||||||
| +--- io.netty:netty-codec-http:4.2.9.Final (c)
|
|
||||||
| +--- io.netty:netty-codec-http2:4.2.9.Final (c)
|
|
||||||
| +--- io.netty:netty-codec-http3:4.2.9.Final (c)
|
|
||||||
| +--- io.netty:netty-resolver-dns-native-macos:4.2.9.Final (c)
|
|
||||||
| +--- io.netty:netty-transport-native-epoll:4.2.9.Final (c)
|
|
||||||
| +--- io.projectreactor.netty:reactor-netty-core:1.3.1 (c)
|
|
||||||
| +--- org.apache.tomcat.embed:tomcat-embed-el:11.0.15 (c)
|
|
||||||
| +--- org.hibernate.validator:hibernate-validator:9.0.1.Final (c)
|
|
||||||
| +--- io.netty:netty-codec-compression:4.2.9.Final (c)
|
|
||||||
| +--- io.netty:netty-codec-classes-quic:4.2.9.Final (c)
|
|
||||||
| +--- io.netty:netty-resolver-dns-classes-macos:4.2.9.Final (c)
|
|
||||||
| +--- io.netty:netty-transport-classes-epoll:4.2.9.Final (c)
|
|
||||||
| +--- io.netty:netty-handler-proxy:4.2.9.Final (c)
|
|
||||||
| +--- jakarta.validation:jakarta.validation-api:3.1.1 (c)
|
|
||||||
| +--- org.jboss.logging:jboss-logging:3.6.1.Final (c)
|
|
||||||
| +--- com.fasterxml:classmate:1.7.1 (c)
|
|
||||||
| \--- io.netty:netty-codec-socks:4.2.9.Final (c)
|
|
||||||
+--- org.springframework.cloud:spring-cloud-dependencies:2025.1.0
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j:5.0.0 (c)
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-starter-gateway-server-webflux:5.0.0 (c)
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-starter-consul-discovery:5.0.0 (c)
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-starter:5.0.0 (c)
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-circuitbreaker-resilience4j:5.0.0 (c)
|
|
||||||
| +--- io.github.resilience4j:resilience4j-circuitbreaker:2.3.0 (c)
|
|
||||||
| +--- io.github.resilience4j:resilience4j-timelimiter:2.3.0 (c)
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-gateway-server-webflux:5.0.0 (c)
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-starter-consul:5.0.0 (c)
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-consul-discovery:5.0.0 (c)
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-starter-loadbalancer:5.0.0 (c)
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-context:5.0.0 (c)
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-commons:5.0.0 (c)
|
|
||||||
| +--- io.github.resilience4j:resilience4j-spring-boot3:2.3.0 (c)
|
|
||||||
| +--- io.github.resilience4j:resilience4j-core:2.3.0 (c)
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-consul-core:5.0.0 (c)
|
|
||||||
| +--- com.ecwid.consul:consul-api:1.4.5 (c)
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-loadbalancer:5.0.0 (c)
|
|
||||||
| +--- io.github.resilience4j:resilience4j-spring6:2.3.0 (c)
|
|
||||||
| +--- io.github.resilience4j:resilience4j-annotations:2.3.0 (c)
|
|
||||||
| +--- io.github.resilience4j:resilience4j-consumer:2.3.0 (c)
|
|
||||||
| +--- io.github.resilience4j:resilience4j-ratelimiter:2.3.0 (c)
|
|
||||||
| +--- io.github.resilience4j:resilience4j-retry:2.3.0 (c)
|
|
||||||
| \--- io.github.resilience4j:resilience4j-micrometer:2.3.0 (c)
|
|
||||||
+--- project :core:core-utils
|
|
||||||
| +--- project :core:core-domain
|
|
||||||
| | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0 -> 1.7.3
|
|
||||||
| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.3 -> 1.9.0
|
|
||||||
| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-bom:1.9.0
|
|
||||||
| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.9.0 (c)
|
|
||||||
| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.9.0 (c)
|
|
||||||
| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0 -> 1.7.3 (c)
|
|
||||||
| | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.9.0 (c)
|
|
||||||
| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.2.0 -> 2.3.0 (*)
|
|
||||||
| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.9.0
|
|
||||||
| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.9.0
|
|
||||||
| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-bom:1.9.0 (*)
|
|
||||||
| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.2.0 -> 2.3.0 (*)
|
|
||||||
| | +--- org.jetbrains.kotlinx:kotlinx-datetime:0.7.1
|
|
||||||
| | | \--- org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.7.1
|
|
||||||
| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.1.20 -> 2.3.0 (*)
|
|
||||||
| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.3.0 (*)
|
|
||||||
| +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0 -> 1.7.3 (*)
|
|
||||||
| +--- org.jetbrains.kotlinx:kotlinx-datetime:0.7.1 (*)
|
|
||||||
| +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2
|
|
||||||
| | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2
|
|
||||||
| | +--- org.jetbrains:annotations:23.0.0
|
|
||||||
| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2
|
|
||||||
| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2 (c)
|
|
||||||
| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2 (c)
|
|
||||||
| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-reactive:1.10.2 (c)
|
|
||||||
| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.10.2 (c)
|
|
||||||
| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.1.0 -> 2.3.0 (*)
|
|
||||||
| +--- com.ionspin.kotlin:bignum:0.3.10
|
|
||||||
| | \--- com.ionspin.kotlin:bignum-jvm:0.3.10
|
|
||||||
| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.3.0 (*)
|
|
||||||
| +--- org.jetbrains.kotlin:kotlin-stdlib:2.3.0 (*)
|
|
||||||
| +--- project :platform:platform-dependencies
|
|
||||||
| | +--- project :platform:platform-bom
|
|
||||||
| | | +--- org.springframework.boot:spring-boot-dependencies:4.0.1 (*)
|
|
||||||
| | | +--- org.springframework.cloud:spring-cloud-dependencies:2025.1.0 (*)
|
|
||||||
| | | +--- org.jetbrains.kotlin:kotlin-bom:2.3.0
|
|
||||||
| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.3.0 (c)
|
|
||||||
| | | | +--- org.jetbrains.kotlin:kotlin-reflect:2.3.0 (c)
|
|
||||||
| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.3.0 (c)
|
|
||||||
| | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.3.0 (c)
|
|
||||||
| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2 (*)
|
|
||||||
| | | +--- com.ionspin.kotlin:bignum:0.3.10 (c)
|
|
||||||
| | | +--- org.springframework.cloud:spring-cloud-starter-consul-discovery -> 5.0.0 (c)
|
|
||||||
| | | +--- io.github.oshai:kotlin-logging-jvm:7.0.13 (c)
|
|
||||||
| | | +--- jakarta.annotation:jakarta.annotation-api:3.0.0 (c)
|
|
||||||
| | | +--- ch.qos.logback:logback-classic:1.5.22 (c)
|
|
||||||
| | | +--- org.jetbrains.exposed:exposed-core:0.61.0 (c)
|
|
||||||
| | | +--- org.jetbrains.exposed:exposed-dao:0.61.0 (c)
|
|
||||||
| | | +--- org.jetbrains.exposed:exposed-jdbc:0.61.0 (c)
|
|
||||||
| | | +--- org.jetbrains.exposed:exposed-kotlin-datetime:0.61.0 (c)
|
|
||||||
| | | +--- org.flywaydb:flyway-core:11.19.1 (c)
|
|
||||||
| | | +--- org.flywaydb:flyway-database-postgresql:11.19.1 (c)
|
|
||||||
| | | +--- com.zaxxer:HikariCP:7.0.2 (c)
|
|
||||||
| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0 -> 1.7.3 (c)
|
|
||||||
| | | +--- org.jetbrains.kotlinx:kotlinx-datetime:0.7.1 (c)
|
|
||||||
| | | +--- com.fasterxml.jackson.module:jackson-module-kotlin -> 2.20.1 (c)
|
|
||||||
| | | +--- com.fasterxml.jackson.datatype:jackson-datatype-jsr310 -> 2.20.1 (c)
|
|
||||||
| | | \--- io.lettuce:lettuce-core:7.2.1.RELEASE (c)
|
|
||||||
| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2 (*)
|
|
||||||
| | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0 -> 1.7.3 (*)
|
|
||||||
| | +--- org.jetbrains.kotlinx:kotlinx-datetime:0.7.1 (*)
|
|
||||||
| | +--- io.github.oshai:kotlin-logging-jvm:7.0.13
|
|
||||||
| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.1.21 -> 2.3.0 (*)
|
|
||||||
| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.10.2
|
|
||||||
| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2 (*)
|
|
||||||
| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2 (*)
|
|
||||||
| | | +--- io.projectreactor:reactor-core:3.4.1 -> 3.8.1
|
|
||||||
| | | | +--- org.reactivestreams:reactive-streams:1.0.4
|
|
||||||
| | | | \--- org.jspecify:jspecify:1.0.0
|
|
||||||
| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-reactive:1.10.2
|
|
||||||
| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2 (*)
|
|
||||||
| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2 (*)
|
|
||||||
| | | | +--- org.reactivestreams:reactive-streams:1.0.3 -> 1.0.4
|
|
||||||
| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.1.0 -> 2.3.0 (*)
|
|
||||||
| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.1.0 -> 2.3.0 (*)
|
|
||||||
| | +--- ch.qos.logback:logback-classic:1.5.22
|
|
||||||
| | | +--- ch.qos.logback:logback-core:1.5.22
|
|
||||||
| | | \--- org.slf4j:slf4j-api:2.0.17
|
|
||||||
| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.3.0 (*)
|
|
||||||
| +--- org.jetbrains.exposed:exposed-core:0.61.0
|
|
||||||
| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.3.0 (*)
|
|
||||||
| | +--- org.jetbrains.kotlin:kotlin-reflect:2.0.0 -> 2.3.0
|
|
||||||
| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.3.0 (*)
|
|
||||||
| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1 -> 1.10.2 (*)
|
|
||||||
| | \--- org.slf4j:slf4j-api:2.0.9 -> 2.0.17
|
|
||||||
| +--- org.jetbrains.exposed:exposed-dao:0.61.0
|
|
||||||
| | +--- org.jetbrains.exposed:exposed-core:0.61.0 (*)
|
|
||||||
| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.3.0 (*)
|
|
||||||
| +--- org.jetbrains.exposed:exposed-jdbc:0.61.0
|
|
||||||
| | +--- org.jetbrains.exposed:exposed-core:0.61.0 (*)
|
|
||||||
| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.3.0 (*)
|
|
||||||
| +--- org.jetbrains.exposed:exposed-kotlin-datetime:0.61.0
|
|
||||||
| | +--- org.jetbrains.exposed:exposed-core:0.61.0 (*)
|
|
||||||
| | +--- org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.2 -> 0.7.1 (*)
|
|
||||||
| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.3.0 (*)
|
|
||||||
| +--- org.flywaydb:flyway-core:11.19.1
|
|
||||||
| | \--- com.fasterxml.jackson.core:jackson-databind:2.19.1 -> 2.20.1
|
|
||||||
| | +--- com.fasterxml.jackson.core:jackson-annotations:2.20
|
|
||||||
| | +--- com.fasterxml.jackson.core:jackson-core:2.20.1
|
|
||||||
| | | \--- com.fasterxml.jackson:jackson-bom:2.20.1
|
|
||||||
| | | +--- com.fasterxml.jackson.core:jackson-annotations:2.20 (c)
|
|
||||||
| | | +--- com.fasterxml.jackson.core:jackson-core:2.20.1 (c)
|
|
||||||
| | | +--- com.fasterxml.jackson.core:jackson-databind:2.20.1 (c)
|
|
||||||
| | | +--- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.20.1 (c)
|
|
||||||
| | | \--- com.fasterxml.jackson.module:jackson-module-kotlin:2.20.1 (c)
|
|
||||||
| | \--- com.fasterxml.jackson:jackson-bom:2.20.1 (*)
|
|
||||||
| +--- org.flywaydb:flyway-database-postgresql:11.19.1
|
|
||||||
| | \--- org.flywaydb:flyway-core:11.19.1 (*)
|
|
||||||
| +--- com.zaxxer:HikariCP:7.0.2
|
|
||||||
| | \--- org.slf4j:slf4j-api:2.0.17
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-starter-consul-discovery -> 5.0.0
|
|
||||||
| | +--- org.springframework.cloud:spring-cloud-starter-consul:5.0.0
|
|
||||||
| | | +--- org.springframework.cloud:spring-cloud-starter:5.0.0
|
|
||||||
| | | | +--- org.springframework.boot:spring-boot-starter:4.0.0 -> 4.0.1
|
|
||||||
| | | | | +--- org.springframework.boot:spring-boot-starter-logging:4.0.1
|
|
||||||
| | | | | | +--- ch.qos.logback:logback-classic:1.5.22 (*)
|
|
||||||
| | | | | | +--- org.apache.logging.log4j:log4j-to-slf4j:2.25.3
|
|
||||||
| | | | | | | +--- org.apache.logging.log4j:log4j-api:2.25.3
|
|
||||||
| | | | | | | | +--- org.jspecify:jspecify:1.0.0
|
|
||||||
| | | | | | | | +--- biz.aQute.bnd:biz.aQute.bnd.annotation:7.1.0
|
|
||||||
| | | | | | | | | +--- org.osgi:org.osgi.resource:1.0.0
|
|
||||||
| | | | | | | | | \--- org.osgi:org.osgi.service.serviceloader:1.0.0
|
|
||||||
| | | | | | | | +--- com.google.errorprone:error_prone_annotations:2.38.0 -> 2.41.0
|
|
||||||
| | | | | | | | +--- org.osgi:org.osgi.annotation.bundle:2.0.0
|
|
||||||
| | | | | | | | | \--- org.osgi:org.osgi.annotation.versioning:1.1.2
|
|
||||||
| | | | | | | | \--- org.osgi:org.osgi.annotation.versioning:1.1.2
|
|
||||||
| | | | | | | +--- org.slf4j:slf4j-api:2.0.17
|
|
||||||
| | | | | | | +--- org.jspecify:jspecify:1.0.0
|
|
||||||
| | | | | | | +--- biz.aQute.bnd:biz.aQute.bnd.annotation:7.1.0 (*)
|
|
||||||
| | | | | | | +--- com.google.errorprone:error_prone_annotations:2.38.0 -> 2.41.0
|
|
||||||
| | | | | | | +--- org.osgi:org.osgi.annotation.bundle:2.0.0 (*)
|
|
||||||
| | | | | | | \--- org.osgi:org.osgi.annotation.versioning:1.1.2
|
|
||||||
| | | | | | \--- org.slf4j:jul-to-slf4j:2.0.17
|
|
||||||
| | | | | | \--- org.slf4j:slf4j-api:2.0.17
|
|
||||||
| | | | | +--- org.springframework.boot:spring-boot-autoconfigure:4.0.1
|
|
||||||
| | | | | | \--- org.springframework.boot:spring-boot:4.0.1
|
|
||||||
| | | | | | +--- org.springframework:spring-core:7.0.2
|
|
||||||
| | | | | | | +--- commons-logging:commons-logging:1.3.5
|
|
||||||
| | | | | | | \--- org.jspecify:jspecify:1.0.0
|
|
||||||
| | | | | | \--- org.springframework:spring-context:7.0.2
|
|
||||||
| | | | | | +--- org.springframework:spring-aop:7.0.2
|
|
||||||
| | | | | | | +--- org.springframework:spring-beans:7.0.2
|
|
||||||
| | | | | | | | \--- org.springframework:spring-core:7.0.2 (*)
|
|
||||||
| | | | | | | \--- org.springframework:spring-core:7.0.2 (*)
|
|
||||||
| | | | | | +--- org.springframework:spring-beans:7.0.2 (*)
|
|
||||||
| | | | | | +--- org.springframework:spring-core:7.0.2 (*)
|
|
||||||
| | | | | | +--- org.springframework:spring-expression:7.0.2
|
|
||||||
| | | | | | | \--- org.springframework:spring-core:7.0.2 (*)
|
|
||||||
| | | | | | \--- io.micrometer:micrometer-observation:1.16.1
|
|
||||||
| | | | | | +--- org.jspecify:jspecify:1.0.0
|
|
||||||
| | | | | | \--- io.micrometer:micrometer-commons:1.16.1
|
|
||||||
| | | | | | \--- org.jspecify:jspecify:1.0.0
|
|
||||||
| | | | | +--- jakarta.annotation:jakarta.annotation-api:3.0.0
|
|
||||||
| | | | | \--- org.yaml:snakeyaml:2.5
|
|
||||||
| | | | +--- org.springframework.cloud:spring-cloud-context:5.0.0
|
|
||||||
| | | | | \--- org.springframework.security:spring-security-crypto:7.0.0 -> 7.0.2
|
|
||||||
| | | | +--- org.springframework.cloud:spring-cloud-commons:5.0.0
|
|
||||||
| | | | | \--- org.springframework.security:spring-security-crypto:7.0.0 -> 7.0.2
|
|
||||||
| | | | \--- org.bouncycastle:bcprov-jdk18on:1.81
|
|
||||||
| | | +--- org.springframework.cloud:spring-cloud-consul-core:5.0.0
|
|
||||||
| | | | +--- org.springframework.boot:spring-boot-starter-validation:4.0.0 -> 4.0.1
|
|
||||||
| | | | | +--- org.springframework.boot:spring-boot-starter:4.0.1 (*)
|
|
||||||
| | | | | \--- org.springframework.boot:spring-boot-validation:4.0.1
|
|
||||||
| | | | | +--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| | | | | +--- org.apache.tomcat.embed:tomcat-embed-el:11.0.15
|
|
||||||
| | | | | \--- org.hibernate.validator:hibernate-validator:9.0.1.Final
|
|
||||||
| | | | | +--- jakarta.validation:jakarta.validation-api:3.1.1
|
|
||||||
| | | | | +--- org.jboss.logging:jboss-logging:3.6.1.Final
|
|
||||||
| | | | | \--- com.fasterxml:classmate:1.7.0 -> 1.7.1
|
|
||||||
| | | | \--- org.springframework.boot:spring-boot-restclient:4.0.0 -> 4.0.1
|
|
||||||
| | | | +--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| | | | \--- org.springframework.boot:spring-boot-http-client:4.0.1
|
|
||||||
| | | | +--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| | | | \--- org.springframework:spring-web:7.0.2
|
|
||||||
| | | | +--- org.springframework:spring-beans:7.0.2 (*)
|
|
||||||
| | | | +--- org.springframework:spring-core:7.0.2 (*)
|
|
||||||
| | | | \--- io.micrometer:micrometer-observation:1.16.1 (*)
|
|
||||||
| | | +--- com.ecwid.consul:consul-api:1.4.5
|
|
||||||
| | | +--- com.google.code.gson:gson:2.13.2
|
|
||||||
| | | | \--- com.google.errorprone:error_prone_annotations:2.41.0
|
|
||||||
| | | +--- org.apache.httpcomponents:httpclient:4.5.14
|
|
||||||
| | | | +--- org.apache.httpcomponents:httpcore:4.4.16
|
|
||||||
| | | | +--- commons-logging:commons-logging:1.2 -> 1.3.5
|
|
||||||
| | | | \--- commons-codec:commons-codec:1.11 -> 1.19.0
|
|
||||||
| | | \--- org.apache.httpcomponents:httpcore:4.4.16
|
|
||||||
| | +--- org.springframework.cloud:spring-cloud-consul-discovery:5.0.0
|
|
||||||
| | | \--- org.springframework.cloud:spring-cloud-consul-core:5.0.0 (*)
|
|
||||||
| | \--- org.springframework.cloud:spring-cloud-starter-loadbalancer:5.0.0
|
|
||||||
| | +--- org.springframework.cloud:spring-cloud-starter:5.0.0 (*)
|
|
||||||
| | +--- org.springframework.cloud:spring-cloud-loadbalancer:5.0.0
|
|
||||||
| | | +--- org.springframework.cloud:spring-cloud-commons:5.0.0 (*)
|
|
||||||
| | | +--- org.springframework.cloud:spring-cloud-context:5.0.0 (*)
|
|
||||||
| | | +--- io.projectreactor:reactor-core:3.8.0 -> 3.8.1 (*)
|
|
||||||
| | | \--- io.projectreactor.addons:reactor-extra:3.6.0
|
|
||||||
| | | \--- io.projectreactor:reactor-core:3.8.0 -> 3.8.1 (*)
|
|
||||||
| | +--- org.springframework.boot:spring-boot-starter-cache:4.0.0 -> 4.0.1
|
|
||||||
| | | +--- org.springframework.boot:spring-boot-starter:4.0.1 (*)
|
|
||||||
| | | \--- org.springframework.boot:spring-boot-cache:4.0.1
|
|
||||||
| | | +--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| | | \--- org.springframework:spring-context-support:7.0.2
|
|
||||||
| | | +--- org.springframework:spring-beans:7.0.2 (*)
|
|
||||||
| | | +--- org.springframework:spring-context:7.0.2 (*)
|
|
||||||
| | | \--- org.springframework:spring-core:7.0.2 (*)
|
|
||||||
| | \--- com.stoyanr:evictor:1.0.0
|
|
||||||
| +--- io.github.oshai:kotlin-logging-jvm:7.0.13 (*)
|
|
||||||
| +--- jakarta.annotation:jakarta.annotation-api:3.0.0
|
|
||||||
| +--- com.fasterxml.jackson.module:jackson-module-kotlin -> 2.20.1
|
|
||||||
| | +--- com.fasterxml.jackson.core:jackson-databind:2.20.1 (*)
|
|
||||||
| | +--- com.fasterxml.jackson.core:jackson-annotations:2.20
|
|
||||||
| | +--- org.jetbrains.kotlin:kotlin-reflect:2.0.21 -> 2.3.0 (*)
|
|
||||||
| | \--- com.fasterxml.jackson:jackson-bom:2.20.1 (*)
|
|
||||||
| \--- com.fasterxml.jackson.datatype:jackson-datatype-jsr310 -> 2.20.1
|
|
||||||
| +--- com.fasterxml.jackson.core:jackson-annotations:2.20
|
|
||||||
| +--- com.fasterxml.jackson.core:jackson-core:2.20.1 (*)
|
|
||||||
| +--- com.fasterxml.jackson.core:jackson-databind:2.20.1 (*)
|
|
||||||
| \--- com.fasterxml.jackson:jackson-bom:2.20.1 (*)
|
|
||||||
+--- project :platform:platform-dependencies (*)
|
|
||||||
+--- project :backend:infrastructure:monitoring:monitoring-client
|
|
||||||
| \--- org.jetbrains.kotlin:kotlin-stdlib:2.3.0 (*)
|
|
||||||
+--- org.springframework.boot:spring-boot-starter-webflux -> 4.0.1
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter:4.0.1 (*)
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter-jackson:4.0.1
|
|
||||||
| | +--- org.springframework.boot:spring-boot-starter:4.0.1 (*)
|
|
||||||
| | \--- org.springframework.boot:spring-boot-jackson:4.0.1
|
|
||||||
| | +--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| | \--- tools.jackson.core:jackson-databind:3.0.3
|
|
||||||
| | +--- com.fasterxml.jackson.core:jackson-annotations:2.20
|
|
||||||
| | +--- tools.jackson.core:jackson-core:3.0.3
|
|
||||||
| | | \--- tools.jackson:jackson-bom:3.0.3
|
|
||||||
| | | +--- com.fasterxml.jackson.core:jackson-annotations:2.20 (c)
|
|
||||||
| | | +--- tools.jackson.core:jackson-core:3.0.3 (c)
|
|
||||||
| | | \--- tools.jackson.core:jackson-databind:3.0.3 (c)
|
|
||||||
| | \--- tools.jackson:jackson-bom:3.0.3 (*)
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter-reactor-netty:4.0.1
|
|
||||||
| | +--- org.springframework.boot:spring-boot-starter:4.0.1 (*)
|
|
||||||
| | +--- org.springframework.boot:spring-boot-reactor:4.0.1
|
|
||||||
| | | +--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| | | \--- io.projectreactor:reactor-core:3.8.1 (*)
|
|
||||||
| | \--- org.springframework.boot:spring-boot-reactor-netty:4.0.1
|
|
||||||
| | +--- org.springframework.boot:spring-boot-web-server:4.0.1
|
|
||||||
| | | +--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| | | \--- org.springframework:spring-web:7.0.2 (*)
|
|
||||||
| | +--- io.projectreactor.netty:reactor-netty-http:1.3.1
|
|
||||||
| | | +--- io.netty:netty-codec-http:4.2.7.Final -> 4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-buffer:4.2.9.Final
|
|
||||||
| | | | | \--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-transport:4.2.9.Final
|
|
||||||
| | | | | +--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | | +--- io.netty:netty-buffer:4.2.9.Final (*)
|
|
||||||
| | | | | \--- io.netty:netty-resolver:4.2.9.Final
|
|
||||||
| | | | | \--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-codec-base:4.2.9.Final
|
|
||||||
| | | | | +--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | | +--- io.netty:netty-buffer:4.2.9.Final (*)
|
|
||||||
| | | | | \--- io.netty:netty-transport:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-codec-compression:4.2.9.Final
|
|
||||||
| | | | | +--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | | +--- io.netty:netty-buffer:4.2.9.Final (*)
|
|
||||||
| | | | | +--- io.netty:netty-transport:4.2.9.Final (*)
|
|
||||||
| | | | | \--- io.netty:netty-codec-base:4.2.9.Final (*)
|
|
||||||
| | | | \--- io.netty:netty-handler:4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-resolver:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-buffer:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-transport:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-transport-native-unix-common:4.2.9.Final
|
|
||||||
| | | | | +--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | | +--- io.netty:netty-buffer:4.2.9.Final (*)
|
|
||||||
| | | | | \--- io.netty:netty-transport:4.2.9.Final (*)
|
|
||||||
| | | | \--- io.netty:netty-codec-base:4.2.9.Final (*)
|
|
||||||
| | | +--- io.netty:netty-codec-http2:4.2.7.Final -> 4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-buffer:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-transport:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-codec-base:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-handler:4.2.9.Final (*)
|
|
||||||
| | | | \--- io.netty:netty-codec-http:4.2.9.Final (*)
|
|
||||||
| | | +--- io.netty:netty-codec-http3:4.2.7.Final -> 4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-buffer:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-codec-base:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-codec-http:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-codec-compression:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-handler:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-transport-native-unix-common:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-transport:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-resolver:4.2.9.Final (*)
|
|
||||||
| | | | \--- io.netty:netty-codec-classes-quic:4.2.9.Final
|
|
||||||
| | | +--- io.netty:netty-resolver-dns:4.2.7.Final -> 4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-buffer:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-resolver:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-transport:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-codec-base:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-codec-dns:4.2.9.Final
|
|
||||||
| | | | | +--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | | +--- io.netty:netty-buffer:4.2.9.Final (*)
|
|
||||||
| | | | | +--- io.netty:netty-transport:4.2.9.Final (*)
|
|
||||||
| | | | | \--- io.netty:netty-codec-base:4.2.9.Final (*)
|
|
||||||
| | | | \--- io.netty:netty-handler:4.2.9.Final (*)
|
|
||||||
| | | +--- io.netty:netty-resolver-dns-native-macos:4.2.7.Final -> 4.2.9.Final
|
|
||||||
| | | | \--- io.netty:netty-resolver-dns-classes-macos:4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-resolver-dns:4.2.9.Final (*)
|
|
||||||
| | | | \--- io.netty:netty-transport-native-unix-common:4.2.9.Final (*)
|
|
||||||
| | | +--- io.netty:netty-transport-native-epoll:4.2.7.Final -> 4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-buffer:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-transport:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-transport-native-unix-common:4.2.9.Final (*)
|
|
||||||
| | | | \--- io.netty:netty-transport-classes-epoll:4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | +--- io.netty:netty-buffer:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-transport:4.2.9.Final (*)
|
|
||||||
| | | | \--- io.netty:netty-transport-native-unix-common:4.2.9.Final (*)
|
|
||||||
| | | +--- io.projectreactor.netty:reactor-netty-core:1.3.1
|
|
||||||
| | | | +--- io.netty:netty-handler:4.2.7.Final -> 4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-handler-proxy:4.2.7.Final -> 4.2.9.Final
|
|
||||||
| | | | | +--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | | +--- io.netty:netty-buffer:4.2.9.Final (*)
|
|
||||||
| | | | | +--- io.netty:netty-transport:4.2.9.Final (*)
|
|
||||||
| | | | | +--- io.netty:netty-codec-base:4.2.9.Final (*)
|
|
||||||
| | | | | +--- io.netty:netty-codec-socks:4.2.9.Final
|
|
||||||
| | | | | | +--- io.netty:netty-common:4.2.9.Final
|
|
||||||
| | | | | | +--- io.netty:netty-buffer:4.2.9.Final (*)
|
|
||||||
| | | | | | +--- io.netty:netty-transport:4.2.9.Final (*)
|
|
||||||
| | | | | | \--- io.netty:netty-codec-base:4.2.9.Final (*)
|
|
||||||
| | | | | +--- io.netty:netty-codec-http:4.2.9.Final (*)
|
|
||||||
| | | | | \--- io.netty:netty-handler:4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-resolver-dns:4.2.7.Final -> 4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-resolver-dns-native-macos:4.2.7.Final -> 4.2.9.Final (*)
|
|
||||||
| | | | +--- io.netty:netty-transport-native-epoll:4.2.7.Final -> 4.2.9.Final (*)
|
|
||||||
| | | | +--- io.projectreactor:reactor-core:3.8.1 (*)
|
|
||||||
| | | | \--- org.jspecify:jspecify:1.0.0
|
|
||||||
| | | +--- io.projectreactor:reactor-core:3.8.1 (*)
|
|
||||||
| | | \--- org.jspecify:jspecify:1.0.0
|
|
||||||
| | \--- org.springframework:spring-web:7.0.2 (*)
|
|
||||||
| \--- org.springframework.boot:spring-boot-webflux:4.0.1
|
|
||||||
| +--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| +--- org.springframework.boot:spring-boot-http-codec:4.0.1
|
|
||||||
| | +--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| | \--- org.springframework:spring-web:7.0.2 (*)
|
|
||||||
| \--- org.springframework:spring-webflux:7.0.2
|
|
||||||
| +--- org.springframework:spring-beans:7.0.2 (*)
|
|
||||||
| +--- org.springframework:spring-core:7.0.2 (*)
|
|
||||||
| +--- org.springframework:spring-web:7.0.2 (*)
|
|
||||||
| \--- io.projectreactor:reactor-core:3.8.1 (*)
|
|
||||||
+--- org.springframework.cloud:spring-cloud-starter-gateway-server-webflux -> 5.0.0
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-starter:5.0.0 (*)
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-gateway-server-webflux:5.0.0
|
|
||||||
| | +--- org.springframework.boot:spring-boot-starter:4.0.0 -> 4.0.1 (*)
|
|
||||||
| | +--- org.springframework.boot:spring-boot-starter-validation:4.0.0 -> 4.0.1 (*)
|
|
||||||
| | \--- io.projectreactor.addons:reactor-extra:3.6.0 (*)
|
|
||||||
| \--- org.springframework.boot:spring-boot-starter-webflux:4.0.0 -> 4.0.1 (*)
|
|
||||||
+--- org.springframework.cloud:spring-cloud-starter-consul-discovery -> 5.0.0 (*)
|
|
||||||
+--- org.springframework.boot:spring-boot-starter-actuator -> 4.0.1
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter:4.0.1 (*)
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter-micrometer-metrics:4.0.1
|
|
||||||
| | +--- org.springframework.boot:spring-boot-starter:4.0.1 (*)
|
|
||||||
| | \--- org.springframework.boot:spring-boot-micrometer-metrics:4.0.1
|
|
||||||
| | +--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| | +--- org.springframework.boot:spring-boot-micrometer-observation:4.0.1
|
|
||||||
| | | +--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| | | \--- io.micrometer:micrometer-observation:1.16.1 (*)
|
|
||||||
| | \--- io.micrometer:micrometer-core:1.16.1
|
|
||||||
| | +--- org.jspecify:jspecify:1.0.0
|
|
||||||
| | +--- io.micrometer:micrometer-commons:1.16.1 (*)
|
|
||||||
| | \--- io.micrometer:micrometer-observation:1.16.1 (*)
|
|
||||||
| +--- org.springframework.boot:spring-boot-actuator-autoconfigure:4.0.1
|
|
||||||
| | +--- org.springframework.boot:spring-boot-autoconfigure:4.0.1 (*)
|
|
||||||
| | \--- org.springframework.boot:spring-boot-actuator:4.0.1
|
|
||||||
| | \--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| +--- org.springframework.boot:spring-boot-health:4.0.1
|
|
||||||
| | \--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| +--- io.micrometer:micrometer-observation:1.16.1 (*)
|
|
||||||
| \--- io.micrometer:micrometer-jakarta9:1.16.1
|
|
||||||
| +--- org.jspecify:jspecify:1.0.0
|
|
||||||
| +--- io.micrometer:micrometer-core:1.16.1 (*)
|
|
||||||
| +--- io.micrometer:micrometer-commons:1.16.1 (*)
|
|
||||||
| \--- io.micrometer:micrometer-observation:1.16.1 (*)
|
|
||||||
+--- org.springframework.boot:spring-boot-starter-security -> 4.0.1
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter:4.0.1 (*)
|
|
||||||
| +--- org.springframework.boot:spring-boot-security:4.0.1
|
|
||||||
| | +--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| | +--- org.springframework.security:spring-security-config:7.0.2
|
|
||||||
| | | +--- org.springframework.security:spring-security-core:7.0.2
|
|
||||||
| | | | +--- org.springframework.security:spring-security-crypto:7.0.2
|
|
||||||
| | | | +--- org.springframework:spring-aop:7.0.2 (*)
|
|
||||||
| | | | +--- org.springframework:spring-beans:7.0.2 (*)
|
|
||||||
| | | | +--- org.springframework:spring-context:7.0.2 (*)
|
|
||||||
| | | | +--- org.springframework:spring-core:7.0.2 (*)
|
|
||||||
| | | | +--- org.springframework:spring-expression:7.0.2 (*)
|
|
||||||
| | | | \--- io.micrometer:micrometer-observation:1.16.1 (*)
|
|
||||||
| | | +--- org.springframework:spring-aop:7.0.2 (*)
|
|
||||||
| | | +--- org.springframework:spring-beans:7.0.2 (*)
|
|
||||||
| | | +--- org.springframework:spring-context:7.0.2 (*)
|
|
||||||
| | | \--- org.springframework:spring-core:7.0.2 (*)
|
|
||||||
| | \--- org.springframework.security:spring-security-web:7.0.2
|
|
||||||
| | +--- org.springframework.security:spring-security-core:7.0.2 (*)
|
|
||||||
| | +--- org.springframework:spring-core:7.0.2 (*)
|
|
||||||
| | +--- org.springframework:spring-aop:7.0.2 (*)
|
|
||||||
| | +--- org.springframework:spring-beans:7.0.2 (*)
|
|
||||||
| | +--- org.springframework:spring-context:7.0.2 (*)
|
|
||||||
| | +--- org.springframework:spring-expression:7.0.2 (*)
|
|
||||||
| | \--- org.springframework:spring-web:7.0.2 (*)
|
|
||||||
| \--- org.springframework:spring-aop:7.0.2 (*)
|
|
||||||
+--- org.springframework.boot:spring-boot-starter-oauth2-resource-server -> 4.0.1
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter:4.0.1 (*)
|
|
||||||
| +--- org.springframework.boot:spring-boot-starter-security:4.0.1 (*)
|
|
||||||
| \--- org.springframework.boot:spring-boot-security-oauth2-resource-server:4.0.1
|
|
||||||
| +--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| +--- org.springframework.security:spring-security-oauth2-jose:7.0.2
|
|
||||||
| | +--- org.springframework.security:spring-security-core:7.0.2 (*)
|
|
||||||
| | +--- org.springframework.security:spring-security-oauth2-core:7.0.2
|
|
||||||
| | | +--- org.springframework.security:spring-security-core:7.0.2 (*)
|
|
||||||
| | | +--- org.springframework:spring-core:7.0.2 (*)
|
|
||||||
| | | \--- org.springframework:spring-web:7.0.2 (*)
|
|
||||||
| | +--- org.springframework:spring-core:7.0.2 (*)
|
|
||||||
| | \--- com.nimbusds:nimbus-jose-jwt:10.4
|
|
||||||
| \--- org.springframework.security:spring-security-oauth2-resource-server:7.0.2
|
|
||||||
| +--- org.springframework.security:spring-security-core:7.0.2 (*)
|
|
||||||
| +--- org.springframework.security:spring-security-oauth2-core:7.0.2 (*)
|
|
||||||
| +--- org.springframework.security:spring-security-web:7.0.2 (*)
|
|
||||||
| \--- org.springframework:spring-core:7.0.2 (*)
|
|
||||||
+--- org.springframework.security:spring-security-oauth2-jose -> 7.0.2 (*)
|
|
||||||
+--- org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j -> 5.0.0
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-starter:5.0.0 (*)
|
|
||||||
| +--- org.springframework.cloud:spring-cloud-circuitbreaker-resilience4j:5.0.0
|
|
||||||
| | +--- com.fasterxml.jackson.core:jackson-core:2.20.1 (*)
|
|
||||||
| | +--- com.fasterxml.jackson.core:jackson-databind:2.20.1 (*)
|
|
||||||
| | +--- org.springframework.cloud:spring-cloud-commons:5.0.0 (*)
|
|
||||||
| | +--- io.micrometer:micrometer-observation:1.16.0 -> 1.16.1 (*)
|
|
||||||
| | +--- io.github.resilience4j:resilience4j-circuitbreaker:2.3.0
|
|
||||||
| | | \--- io.github.resilience4j:resilience4j-core:2.3.0
|
|
||||||
| | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0 -> 2.3.0
|
|
||||||
| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.3.0 (*)
|
|
||||||
| | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.3.0
|
|
||||||
| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.3.0 (*)
|
|
||||||
| | +--- io.github.resilience4j:resilience4j-timelimiter:2.3.0
|
|
||||||
| | | \--- io.github.resilience4j:resilience4j-core:2.3.0 (*)
|
|
||||||
| | +--- io.github.resilience4j:resilience4j-spring-boot3:2.3.0
|
|
||||||
| | | \--- io.github.resilience4j:resilience4j-spring6:2.3.0
|
|
||||||
| | | +--- io.github.resilience4j:resilience4j-annotations:2.3.0
|
|
||||||
| | | +--- io.github.resilience4j:resilience4j-consumer:2.3.0
|
|
||||||
| | | \--- io.github.resilience4j:resilience4j-framework-common:2.3.0
|
|
||||||
| | | +--- io.github.resilience4j:resilience4j-circuitbreaker:2.3.0 (*)
|
|
||||||
| | | +--- io.github.resilience4j:resilience4j-ratelimiter:2.3.0
|
|
||||||
| | | | \--- io.github.resilience4j:resilience4j-core:2.3.0 (*)
|
|
||||||
| | | +--- io.github.resilience4j:resilience4j-retry:2.3.0
|
|
||||||
| | | | \--- io.github.resilience4j:resilience4j-core:2.3.0 (*)
|
|
||||||
| | | +--- io.github.resilience4j:resilience4j-timelimiter:2.3.0 (*)
|
|
||||||
| | | \--- io.github.resilience4j:resilience4j-micrometer:2.3.0
|
|
||||||
| | | +--- io.micrometer:micrometer-core:1.10.0 -> 1.16.1 (*)
|
|
||||||
| | | \--- io.micrometer:micrometer-observation:1.10.0 -> 1.16.1 (*)
|
|
||||||
| | \--- org.springframework.boot:spring-boot-configuration-processor:4.0.0 -> 4.0.1
|
|
||||||
| +--- io.github.resilience4j:resilience4j-circuitbreaker:2.3.0 (*)
|
|
||||||
| \--- io.github.resilience4j:resilience4j-timelimiter:2.3.0 (*)
|
|
||||||
+--- io.github.oshai:kotlin-logging-jvm:7.0.13 (*)
|
|
||||||
+--- ch.qos.logback:logback-classic:1.5.22 (*)
|
|
||||||
+--- ch.qos.logback:logback-core:1.5.22
|
|
||||||
+--- com.fasterxml.jackson.module:jackson-module-kotlin -> 2.20.1 (*)
|
|
||||||
+--- com.fasterxml.jackson.datatype:jackson-datatype-jsr310 -> 2.20.1 (*)
|
|
||||||
\--- org.springframework.boot:spring-boot-starter-data-redis -> 4.0.1
|
|
||||||
+--- org.springframework.boot:spring-boot-starter:4.0.1 (*)
|
|
||||||
\--- org.springframework.boot:spring-boot-data-redis:4.0.1
|
|
||||||
+--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
+--- org.springframework.boot:spring-boot-data-commons:4.0.1
|
|
||||||
| +--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| +--- org.springframework.boot:spring-boot-persistence:4.0.1
|
|
||||||
| | +--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| | \--- org.springframework:spring-tx:7.0.2
|
|
||||||
| | +--- org.springframework:spring-beans:7.0.2 (*)
|
|
||||||
| | \--- org.springframework:spring-core:7.0.2 (*)
|
|
||||||
| \--- org.springframework.data:spring-data-commons:4.0.1
|
|
||||||
| +--- org.springframework:spring-core:7.0.2 (*)
|
|
||||||
| +--- org.springframework:spring-beans:7.0.2 (*)
|
|
||||||
| \--- org.slf4j:slf4j-api:2.0.17
|
|
||||||
+--- org.springframework.boot:spring-boot-transaction:4.0.1
|
|
||||||
| +--- org.springframework.boot:spring-boot:4.0.1 (*)
|
|
||||||
| +--- org.springframework.boot:spring-boot-persistence:4.0.1 (*)
|
|
||||||
| \--- org.springframework:spring-tx:7.0.2 (*)
|
|
||||||
+--- io.lettuce:lettuce-core:6.8.1.RELEASE -> 7.2.1.RELEASE
|
|
||||||
| +--- redis.clients.authentication:redis-authx-core:0.1.1-beta2
|
|
||||||
| | \--- org.slf4j:slf4j-api:1.7.36 -> 2.0.17
|
|
||||||
| +--- io.netty:netty-common:4.2.5.Final -> 4.2.9.Final
|
|
||||||
| +--- io.netty:netty-handler:4.2.5.Final -> 4.2.9.Final (*)
|
|
||||||
| +--- io.netty:netty-transport:4.2.5.Final -> 4.2.9.Final (*)
|
|
||||||
| +--- io.projectreactor:reactor-core:3.6.6 -> 3.8.1 (*)
|
|
||||||
| \--- io.netty:netty-resolver-dns:4.2.5.Final -> 4.2.9.Final (*)
|
|
||||||
\--- org.springframework.data:spring-data-redis:4.0.1
|
|
||||||
+--- org.springframework.data:spring-data-keyvalue:4.0.1
|
|
||||||
| +--- org.springframework.data:spring-data-commons:4.0.1 (*)
|
|
||||||
| +--- org.springframework:spring-context:7.0.2 (*)
|
|
||||||
| +--- org.springframework:spring-tx:7.0.2 (*)
|
|
||||||
| \--- org.slf4j:slf4j-api:2.0.17
|
|
||||||
+--- org.springframework:spring-tx:7.0.2 (*)
|
|
||||||
+--- org.springframework:spring-oxm:7.0.2
|
|
||||||
| +--- org.springframework:spring-beans:7.0.2 (*)
|
|
||||||
| \--- org.springframework:spring-core:7.0.2 (*)
|
|
||||||
+--- org.springframework:spring-aop:7.0.2 (*)
|
|
||||||
+--- org.springframework:spring-context-support:7.0.2 (*)
|
|
||||||
\--- org.slf4j:slf4j-api:2.0.17
|
|
||||||
|
|
||||||
(c) - A dependency constraint, not a dependency. The dependency affected by the constraint occurs elsewhere in the tree.
|
|
||||||
(*) - Indicates repeated occurrences of a transitive dependency subtree. Gradle expands transitive dependency subtrees only once per project; repeat occurrences only display the root of the subtree, followed by this annotation.
|
|
||||||
|
|
||||||
A web-based, searchable dependency report is available by adding the --scan option.
|
|
||||||
|
|
||||||
[Incubating] Problems report is available at: file:///home/stefan-mo/WsMeldestelle/Meldestelle/build/reports/problems/problems-report.html
|
|
||||||
|
|
||||||
Deprecated Gradle features were used in this build, making it incompatible with Gradle 10.
|
|
||||||
|
|
||||||
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
|
|
||||||
|
|
||||||
For more on this, please refer to https://docs.gradle.org/9.2.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.
|
|
||||||
|
|
||||||
BUILD SUCCESSFUL in 3s
|
|
||||||
1 actionable task: 1 executed
|
|
||||||
|
|
@ -4,10 +4,10 @@
|
||||||
### 1. Kern-Spezifikationen
|
### 1. Kern-Spezifikationen
|
||||||
|
|
||||||
| Komponente | Version | Status |
|
| Komponente | Version | Status |
|
||||||
| --- | --- | --- |
|
| --- |----------| --- |
|
||||||
| **Kotlin** | `2.3.0` | Stabil (K2 Compiler standardmäßig aktiv) |
|
| **Kotlin** | `2.3.0` | Stabil (K2 Compiler standardmäßig aktiv) |
|
||||||
| **Java (JDK)** | `25` | LTS (Long-Term Support) |
|
| **Java (JDK)** | `25` | LTS (Long-Term Support) |
|
||||||
| **Gradle** | `9.2+` | Erforderlich für JDK 25 Support |
|
| **Gradle** | `9.2.1` | Erforderlich für JDK 25 Support |
|
||||||
| **Android Plugin (AGP)** | `8.8.0+` | Empfohlen für Gradle 9.x Kompatibilität |
|
| **Android Plugin (AGP)** | `8.8.0+` | Empfohlen für Gradle 9.x Kompatibilität |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -52,7 +52,7 @@ Damit das Projekt Java 25 erkennt, muss der Wrapper auf dem neuesten Stand sein:
|
||||||
**Terminal-Befehl:**
|
**Terminal-Befehl:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./gradlew wrapper --gradle-version 9.2 --distribution-type all
|
./gradlew wrapper --gradle-version 9.2.1 --distribution-type all
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ dependencies {
|
||||||
|
|
||||||
// === GATEWAY-SPEZIFISCHE ABHÄNGIGKEITEN ===
|
// === GATEWAY-SPEZIFISCHE ABHÄNGIGKEITEN ===
|
||||||
// Die WebFlux-Abhängigkeit wird jetzt korrekt durch das BOM bereitgestellt.
|
// Die WebFlux-Abhängigkeit wird jetzt korrekt durch das BOM bereitgestellt.
|
||||||
// implementation(libs.spring.boot.starter.webflux)
|
implementation(libs.spring.boot.starter.webflux)
|
||||||
|
|
||||||
// Kern-Gateway inkl. Security, Actuator, CircuitBreaker, Discovery
|
// Kern-Gateway inkl. Security, Actuator, CircuitBreaker, Discovery
|
||||||
implementation(libs.bundles.gateway.core)
|
implementation(libs.bundles.gateway.core)
|
||||||
|
|
@ -34,6 +34,12 @@ dependencies {
|
||||||
// Redis-Unterstützung für verteiltes Rate Limiting (RequestRateLimiter)
|
// Redis-Unterstützung für verteiltes Rate Limiting (RequestRateLimiter)
|
||||||
implementation(libs.bundles.gateway.redis)
|
implementation(libs.bundles.gateway.redis)
|
||||||
|
|
||||||
|
// === Tracing Dependencies (Micrometer Tracing) ===
|
||||||
|
// Ermöglicht verteiltes Tracing über Thread-Grenzen hinweg (ersetzt manuellen MDC-Filter)
|
||||||
|
implementation(libs.micrometer.tracing.bridge.brave)
|
||||||
|
// Optional: Zipkin Reporter, falls du Traces an Zipkin senden willst (bereits im monitoringClient enthalten, aber hier explizit schadet nicht)
|
||||||
|
// implementation(libs.zipkin.reporter.brave)
|
||||||
|
|
||||||
// === Test Dependencies ===
|
// === Test Dependencies ===
|
||||||
testImplementation(projects.platform.platformTesting)
|
testImplementation(projects.platform.platformTesting)
|
||||||
testImplementation(libs.bundles.testing.jvm)
|
testImplementation(libs.bundles.testing.jvm)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package at.mocode.infrastructure.gateway
|
package at.mocode.infrastructure.gateway
|
||||||
|
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.beans.factory.getBean
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||||
import org.springframework.boot.runApplication
|
import org.springframework.boot.runApplication
|
||||||
import org.springframework.core.env.Environment
|
import org.springframework.core.env.Environment
|
||||||
|
|
@ -11,7 +12,7 @@ class GatewayApplication
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val context = runApplication<GatewayApplication>(*args)
|
val context = runApplication<GatewayApplication>(*args)
|
||||||
val logger = LoggerFactory.getLogger(GatewayApplication::class.java)
|
val logger = LoggerFactory.getLogger(GatewayApplication::class.java)
|
||||||
val env = context.getBean(Environment::class.java)
|
val env = context.getBean<Environment>()
|
||||||
val port = env.getProperty("server.port") ?: "8081"
|
val port = env.getProperty("server.port") ?: "8081"
|
||||||
|
|
||||||
logger.info("""
|
logger.info("""
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package at.mocode.infrastructure.gateway.config
|
package at.mocode.infrastructure.gateway.config
|
||||||
|
|
||||||
|
import io.micrometer.tracing.Tracer
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain
|
||||||
import org.springframework.cloud.gateway.filter.GlobalFilter
|
import org.springframework.cloud.gateway.filter.GlobalFilter
|
||||||
|
|
@ -7,17 +8,21 @@ import org.springframework.core.Ordered
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
import org.springframework.web.server.ServerWebExchange
|
import org.springframework.web.server.ServerWebExchange
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gateway-Konfiguration für erweiterte Funktionalitäten wie Logging, Rate Limiting und Security.
|
* Gateway-Konfiguration für erweiterte Funktionalitäten wie Logging, Rate Limiting und Security.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global Filter für Correlations-IDs zur Request-Verfolgung.
|
* Globaler Filter, der sicherstellt, dass die Trace-ID (von Micrometer Tracing)
|
||||||
|
* auch als "X-Correlation-ID" im Response-Header zurückgegeben wird.
|
||||||
|
*
|
||||||
|
* Hinweis: Micrometer Tracing kümmert sich bereits automatisch um die Propagation
|
||||||
|
* der Trace-ID (b3 oder w3c) an nachgelagerte Services. Dieser Filter dient nur
|
||||||
|
* der Bequemlichkeit für Clients (z. B. Frontend), um die ID einfach auslesen zu können.
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
class CorrelationIdFilter : GlobalFilter, Ordered {
|
class CorrelationIdFilter(private val tracer: Tracer) : GlobalFilter, Ordered {
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(CorrelationIdFilter::class.java)
|
private val logger = LoggerFactory.getLogger(CorrelationIdFilter::class.java)
|
||||||
|
|
||||||
|
|
@ -26,26 +31,21 @@ class CorrelationIdFilter : GlobalFilter, Ordered {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
|
override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
|
||||||
val request = exchange.request
|
// Die aktuelle Trace-ID aus dem Micrometer Tracer holen
|
||||||
val correlationId = request.headers.getFirst(CORRELATION_ID_HEADER)
|
val currentSpan = tracer.currentSpan()
|
||||||
?: UUID.randomUUID().toString()
|
val traceId = currentSpan?.context()?.traceId()
|
||||||
|
|
||||||
val mutatedRequest = request.mutate()
|
if (traceId != null) {
|
||||||
.header(CORRELATION_ID_HEADER, correlationId)
|
// Trace-ID als Response-Header hinzufügen
|
||||||
.build()
|
exchange.response.headers.add(CORRELATION_ID_HEADER, traceId)
|
||||||
|
}
|
||||||
|
|
||||||
val mutatedExchange = exchange.mutate()
|
return chain.filter(exchange)
|
||||||
.request(mutatedRequest)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
// Response-Header nach der Verarbeitung hinzufügen
|
|
||||||
mutatedExchange.response.headers.add(CORRELATION_ID_HEADER, correlationId)
|
|
||||||
|
|
||||||
return chain.filter(mutatedExchange)
|
|
||||||
.doOnError { ex ->
|
.doOnError { ex ->
|
||||||
logger.error("Error in CorrelationIdFilter for request {}: {}", request.uri, ex.message)
|
logger.error("Error processing request {}: {}", exchange.request.uri, ex.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getOrder(): Int = Ordered.HIGHEST_PRECEDENCE
|
// Niedrige Priorität, damit Tracing-Kontext bereits initialisiert ist
|
||||||
|
override fun getOrder(): Int = Ordered.LOWEST_PRECEDENCE
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package at.mocode.infrastructure.gateway.config
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||||
|
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import org.springframework.context.annotation.Primary
|
||||||
|
import reactor.core.publisher.Mono
|
||||||
|
import java.security.Principal
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
class RateLimitConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard KeyResolver: IP-basiert.
|
||||||
|
* Nutzt X-Forwarded-For (für Proxies/LoadBalancer), wenn vorhanden, sonst die Remote-Adresse.
|
||||||
|
* Wird verwendet, wenn kein anderer KeyResolver explizit angefordert wird oder aktiv ist.
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@Primary
|
||||||
|
fun ipAddressKeyResolver(): KeyResolver = KeyResolver { exchange ->
|
||||||
|
val forwardedFor = exchange.request.headers.getFirst("X-Forwarded-For")
|
||||||
|
?.split(',')?.firstOrNull()?.trim()
|
||||||
|
val ip = forwardedFor
|
||||||
|
?: exchange.request.remoteAddress?.address?.hostAddress
|
||||||
|
?: "unknown"
|
||||||
|
Mono.just(ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erweiterter KeyResolver: Principal-basiert (User-ID).
|
||||||
|
* Versucht, den authentifizierten User (Principal) zu nutzen.
|
||||||
|
* Fallback auf IP-Adresse, falls der User nicht eingeloggt ist.
|
||||||
|
*
|
||||||
|
* Aktivierung über Property: gateway.ratelimit.principal-key-resolver.enabled=true
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnProperty(prefix = "gateway.ratelimit.principal-key-resolver", name = ["enabled"], havingValue = "true", matchIfMissing = false)
|
||||||
|
fun principalNameKeyResolver(): KeyResolver = KeyResolver { exchange ->
|
||||||
|
exchange.getPrincipal<Principal>()
|
||||||
|
.map { it.name }
|
||||||
|
.switchIfEmpty(
|
||||||
|
Mono.just(
|
||||||
|
exchange.request.headers.getFirst("X-Forwarded-For")?.split(",")?.first()?.trim()
|
||||||
|
?: exchange.request.headers.getFirst("X-Real-IP")
|
||||||
|
?: exchange.request.remoteAddress?.address?.hostAddress
|
||||||
|
?: "unknown"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
package at.mocode.infrastructure.gateway.config
|
|
||||||
|
|
||||||
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
|
||||||
import org.springframework.context.annotation.Bean
|
|
||||||
import org.springframework.context.annotation.Configuration
|
|
||||||
import reactor.core.publisher.Mono
|
|
||||||
import java.security.Principal
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
class RateLimiterConfig {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* KeyResolver basierend auf authentifiziertem Principal; Fallback auf Client-IP.
|
|
||||||
* Funktioniert out-of-the-box mit Keycloak (Resource Server), sofern Security aktiv ist.
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnProperty(prefix = "gateway.ratelimit.principal-key-resolver", name = ["enabled"], havingValue = "true", matchIfMissing = false)
|
|
||||||
fun principalNameKeyResolver(): KeyResolver = KeyResolver { exchange ->
|
|
||||||
exchange.getPrincipal<Principal>()
|
|
||||||
.map { it.name }
|
|
||||||
.switchIfEmpty(
|
|
||||||
Mono.just(
|
|
||||||
exchange.request.headers.getFirst("X-Forwarded-For")?.split(",")?.first()?.trim()
|
|
||||||
?: exchange.request.headers.getFirst("X-Real-IP")
|
|
||||||
?: exchange.request.remoteAddress?.address?.hostAddress
|
|
||||||
?: "unknown"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
package at.mocode.infrastructure.gateway.config
|
|
||||||
|
|
||||||
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver
|
|
||||||
import org.springframework.context.annotation.Primary
|
|
||||||
import org.springframework.context.annotation.Bean
|
|
||||||
import org.springframework.context.annotation.Configuration
|
|
||||||
import reactor.core.publisher.Mono
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
class RateLimitingConfig {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Einfache IP-basierte KeyResolver-Implementierung für das RequestRateLimiter-Filter.
|
|
||||||
* Nutzt X-Forwarded-For, wenn vorhanden, sonst die Remote-Adresse.
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
@Primary
|
|
||||||
fun ipAddressKeyResolver(): KeyResolver = KeyResolver { exchange ->
|
|
||||||
val forwardedFor = exchange.request.headers.getFirst("X-Forwarded-For")
|
|
||||||
?.split(',')?.firstOrNull()?.trim()
|
|
||||||
val ip = forwardedFor
|
|
||||||
?: exchange.request.remoteAddress?.address?.hostAddress
|
|
||||||
?: "unknown"
|
|
||||||
Mono.just(ip)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
package at.mocode.infrastructure.gateway.fallback
|
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
|
||||||
import org.springframework.http.HttpStatus
|
|
||||||
import org.springframework.http.ResponseEntity
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping
|
|
||||||
import org.springframework.web.bind.annotation.RestController
|
|
||||||
import java.time.Instant
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Alternative FallbackController (deaktiviert per Default), nur aktivierbar über
|
|
||||||
* property `gateway.customFallback.enabled=true`. Standardmäßig existiert bereits
|
|
||||||
* ein FallbackController unter `...gateway.controller.FallbackController`.
|
|
||||||
*/
|
|
||||||
@RestController
|
|
||||||
@ConditionalOnProperty(prefix = "gateway.customFallback", name = ["enabled"], havingValue = "true", matchIfMissing = false)
|
|
||||||
class FallbackController {
|
|
||||||
|
|
||||||
@RequestMapping("/fallback/ping")
|
|
||||||
fun pingFallback(): ResponseEntity<Map<String, Any>> =
|
|
||||||
ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(
|
|
||||||
mapOf(
|
|
||||||
"message" to "Ping service unavailable",
|
|
||||||
"timestamp" to Instant.now().toString()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
package at.mocode.infrastructure.gateway.health
|
package at.mocode.infrastructure.gateway.health
|
||||||
|
|
||||||
import org.springframework.boot.actuate.health.Health
|
import org.springframework.boot.health.contributor.Health
|
||||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator
|
import org.springframework.boot.health.contributor.ReactiveHealthIndicator
|
||||||
|
import org.springframework.cloud.client.ServiceInstance
|
||||||
import org.springframework.cloud.client.discovery.DiscoveryClient
|
import org.springframework.cloud.client.discovery.DiscoveryClient
|
||||||
import org.springframework.core.env.Environment
|
import org.springframework.core.env.Environment
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
|
|
@ -9,7 +10,9 @@ import org.springframework.web.reactive.function.client.WebClient
|
||||||
import org.springframework.web.reactive.function.client.WebClientResponseException
|
import org.springframework.web.reactive.function.client.WebClientResponseException
|
||||||
import reactor.core.publisher.Flux
|
import reactor.core.publisher.Flux
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
|
import reactor.core.scheduler.Schedulers
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
|
import java.util.concurrent.TimeoutException
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gateway Health Indicator zur Überwachung der Downstream Services.
|
* Gateway Health Indicator zur Überwachung der Downstream Services.
|
||||||
|
|
@ -40,46 +43,47 @@ class GatewayHealthIndicator(
|
||||||
)
|
)
|
||||||
|
|
||||||
private val HEALTH_CHECK_TIMEOUT = Duration.ofSeconds(5)
|
private val HEALTH_CHECK_TIMEOUT = Duration.ofSeconds(5)
|
||||||
|
private const val PARALLELISM = 8
|
||||||
}
|
}
|
||||||
|
|
||||||
// KORREKTUR für Spring Boot 4: Die `health()`-Methode und ihr Rückgabetyp `Mono<Health>`
|
|
||||||
// erlauben keine Null-Werte mehr. Die Fragezeichen (?) wurden entfernt.
|
|
||||||
override fun health(): Mono<Health> {
|
override fun health(): Mono<Health> {
|
||||||
val builder = Health.up()
|
val builder = Health.up()
|
||||||
val details = mutableMapOf<String, Any>()
|
val details = mutableMapOf<String, Any>()
|
||||||
|
|
||||||
return Mono.fromCallable { discoveryClient.services }
|
return Mono.fromCallable { discoveryClient.services }
|
||||||
.flatMapMany { services ->
|
.subscribeOn(Schedulers.boundedElastic())
|
||||||
|
.flatMapMany { services: List<String> ->
|
||||||
details["totalServices"] = services.size
|
details["totalServices"] = services.size
|
||||||
Flux.fromIterable(services)
|
Flux.fromIterable(services)
|
||||||
}
|
}
|
||||||
.flatMap({ serviceName ->
|
.flatMap({ serviceName: String ->
|
||||||
val instances = discoveryClient.getInstances(serviceName)
|
Mono.fromCallable { discoveryClient.getInstances(serviceName) }
|
||||||
|
.subscribeOn(Schedulers.boundedElastic())
|
||||||
|
.flatMap { instances: List<ServiceInstance> ->
|
||||||
val instanceDetails = mapOf(
|
val instanceDetails = mapOf(
|
||||||
"instanceCount" to instances.size,
|
"instanceCount" to instances.size,
|
||||||
"instances" to instances.map { "${it.host}:${it.port}" }
|
"instances" to instances.map { "${it.host}:${it.port}" }
|
||||||
)
|
)
|
||||||
// Für Health-Check nur auf definierte Services gehen
|
|
||||||
val checkMono = when {
|
val checkMono: Mono<String> = when {
|
||||||
CRITICAL_SERVICES.contains(serviceName) || OPTIONAL_SERVICES.contains(serviceName) ->
|
CRITICAL_SERVICES.contains(serviceName) || OPTIONAL_SERVICES.contains(serviceName) ->
|
||||||
checkServiceHealthReactive(serviceName)
|
checkServiceHealthReactive(serviceName, instances)
|
||||||
else -> Mono.just("SKIPPED")
|
else -> Mono.just("SKIPPED")
|
||||||
}
|
}
|
||||||
checkMono
|
checkMono.map { status -> Triple(serviceName, status, instanceDetails) }
|
||||||
.map { status -> Triple(serviceName, status, instanceDetails) }
|
}
|
||||||
}, 8) // begrenze Parallelität
|
}, PARALLELISM)
|
||||||
.collectList()
|
.collectList()
|
||||||
.map { results ->
|
.flatMap { results: List<Triple<String, String, Map<String, Any>>> ->
|
||||||
val discoveredServices = mutableMapOf<String, Any>()
|
val discoveredServices = mutableMapOf<String, Any>()
|
||||||
val criticalServiceStatus = mutableMapOf<String, String>()
|
val criticalServiceStatus = mutableMapOf<String, String>()
|
||||||
val optionalServiceStatus = mutableMapOf<String, String>()
|
val optionalServiceStatus = mutableMapOf<String, String>()
|
||||||
|
|
||||||
results.forEach { (serviceName, status, instanceDetails) ->
|
results.forEach { (serviceName, status, instanceDetails) ->
|
||||||
discoveredServices[serviceName] = instanceDetails
|
discoveredServices[serviceName] = instanceDetails
|
||||||
if (CRITICAL_SERVICES.contains(serviceName)) {
|
when {
|
||||||
criticalServiceStatus[serviceName] = status
|
CRITICAL_SERVICES.contains(serviceName) -> criticalServiceStatus[serviceName] = status
|
||||||
} else if (OPTIONAL_SERVICES.contains(serviceName)) {
|
OPTIONAL_SERVICES.contains(serviceName) -> optionalServiceStatus[serviceName] = status
|
||||||
optionalServiceStatus[serviceName] = status
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,38 +103,39 @@ class GatewayHealthIndicator(
|
||||||
details["status"] = "UP"
|
details["status"] = "UP"
|
||||||
details["reason"] = when {
|
details["reason"] = when {
|
||||||
isTestEnvironment -> "Gesundheitsprüfung erfolgreich (Testumgebung)"
|
isTestEnvironment -> "Gesundheitsprüfung erfolgreich (Testumgebung)"
|
||||||
isDevEnvironment -> "Gesundheitsprüfung erfolgreich (Entwicklungsumgebung - nicht alle Services erforderlich)"
|
isDevEnvironment -> "Gesundheitsprüfung erfolgreich (Entwicklungsumgebung)"
|
||||||
else -> "Alle kritischen Services sind verfügbar oder optional"
|
else -> "Alle kritischen Services sind verfügbar"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.withDetails(details).build()
|
Mono.just(builder.withDetails(details).build())
|
||||||
}
|
}
|
||||||
.onErrorResume { ex ->
|
.onErrorResume { ex ->
|
||||||
Mono.just(
|
Mono.just(
|
||||||
Health.down(ex)
|
Health.down(ex)
|
||||||
.withDetail("status", "DOWN")
|
.withDetail("status", "DOWN")
|
||||||
.withDetail("reason", "Fehler beim Prüfen der nachgelagerten Services: ${ex.message}")
|
.withDetail("reason", "Fehler bei der Service-Prüfung: ${ex.message}")
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkServiceHealthReactive(serviceName: String): Mono<String> {
|
private fun checkServiceHealthReactive(serviceName: String, instances: List<ServiceInstance>): Mono<String> {
|
||||||
return Mono.fromCallable { discoveryClient.getInstances(serviceName) }
|
|
||||||
.flatMap { instances ->
|
|
||||||
if (instances.isEmpty()) {
|
if (instances.isEmpty()) {
|
||||||
Mono.just("NO_INSTANCES")
|
return Mono.just("NO_INSTANCES")
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
// Wir prüfen exemplarisch die erste Instanz
|
||||||
val instance = instances.first()
|
val instance = instances.first()
|
||||||
val healthUrl = "http://${instance.host}:${instance.port}/actuator/health"
|
val healthUrl = "http://${instance.host}:${instance.port}/actuator/health"
|
||||||
webClient.get()
|
|
||||||
|
return webClient.get()
|
||||||
.uri(healthUrl)
|
.uri(healthUrl)
|
||||||
.retrieve()
|
.retrieve()
|
||||||
.bodyToMono(Map::class.java)
|
.bodyToMono(Map::class.java)
|
||||||
.timeout(HEALTH_CHECK_TIMEOUT)
|
.timeout(HEALTH_CHECK_TIMEOUT)
|
||||||
.map { it["status"]?.toString() ?: "UNKNOWN" }
|
.map { it["status"]?.toString() ?: "UNKNOWN" }
|
||||||
.map { status -> if (status == "UP") "UP" else "DOWN" }
|
.map { status -> if (status.equals("UP", ignoreCase = true)) "UP" else "DOWN" }
|
||||||
.onErrorResume { ex ->
|
.onErrorResume { ex ->
|
||||||
when (ex) {
|
when (ex) {
|
||||||
is WebClientResponseException -> when (ex.statusCode.value()) {
|
is WebClientResponseException -> when (ex.statusCode.value()) {
|
||||||
|
|
@ -138,10 +143,9 @@ class GatewayHealthIndicator(
|
||||||
503 -> Mono.just("DOWN")
|
503 -> Mono.just("DOWN")
|
||||||
else -> Mono.just("ERROR")
|
else -> Mono.just("ERROR")
|
||||||
}
|
}
|
||||||
|
is TimeoutException -> Mono.just("TIMEOUT")
|
||||||
else -> Mono.just("ERROR")
|
else -> Mono.just("ERROR")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import org.springframework.security.web.server.util.matcher.ServerWebExchangeMat
|
||||||
import org.springframework.web.cors.CorsConfiguration
|
import org.springframework.web.cors.CorsConfiguration
|
||||||
import org.springframework.web.cors.reactive.CorsConfigurationSource
|
import org.springframework.web.cors.reactive.CorsConfigurationSource
|
||||||
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource
|
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource
|
||||||
|
import reactor.core.publisher.Mono
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
|
@ -69,35 +70,53 @@ class SecurityConfig(
|
||||||
* Erstellt einen ReactiveJwtDecoder für die JWT-Validierung.
|
* Erstellt einen ReactiveJwtDecoder für die JWT-Validierung.
|
||||||
*
|
*
|
||||||
* Verwendet die JWK Set URI aus der Konfiguration, um die öffentlichen Schlüssel
|
* Verwendet die JWK Set URI aus der Konfiguration, um die öffentlichen Schlüssel
|
||||||
* von Keycloak zu laden. Falls die URI nicht konfiguriert ist oder Keycloak
|
* von Keycloak zu laden.
|
||||||
* nicht erreichbar ist, wird trotzdem ein Bean erstellt, um Startfehler zu vermeiden.
|
*
|
||||||
|
* Resilience-Optimierung:
|
||||||
|
* Anstatt beim Start zu failen oder einen statischen NoOp-Decoder zu nutzen,
|
||||||
|
* verwenden wir einen delegierenden Decoder. Dieser versucht bei jedem Request,
|
||||||
|
* den echten Decoder (lazy) zu initialisieren, falls er noch nicht bereit ist.
|
||||||
|
* So kann Keycloak auch NACH dem Gateway starten.
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
fun reactiveJwtDecoder(
|
fun reactiveJwtDecoder(
|
||||||
@Value($$"${spring.security.oauth2.resourceserver.jwt.jwk-set-uri:}") jwkSetUri: String
|
@Value($$"${spring.security.oauth2.resourceserver.jwt.jwk-set-uri:}") jwkSetUri: String
|
||||||
): ReactiveJwtDecoder {
|
): ReactiveJwtDecoder {
|
||||||
return if (jwkSetUri.isNotBlank()) {
|
return ResilienceReactiveJwtDecoder(jwkSetUri)
|
||||||
try {
|
|
||||||
NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri).build()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
// Log warning and return a no-op decoder to allow startup
|
|
||||||
logger.warn("Failed to configure JWT decoder with JWK Set URI: {} - {}", jwkSetUri, e.message)
|
|
||||||
logger.warn("JWT authentication will not work until Keycloak is available")
|
|
||||||
createNoOpJwtDecoder()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.info("No JWK Set URI configured, using no-op JWT decoder")
|
|
||||||
createNoOpJwtDecoder()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erstellt einen No-Op JWT Decoder für Fälle, in denen Keycloak nicht verfügbar ist.
|
* Ein Wrapper um den NimbusReactiveJwtDecoder, der Initialisierungsfehler abfängt
|
||||||
* Dieser Decoder lehnt alle Token ab, erlaubt aber den Anwendungsstart.
|
* und erst zur Laufzeit (lazy) versucht, die JWKs zu laden.
|
||||||
*/
|
*/
|
||||||
private fun createNoOpJwtDecoder(): ReactiveJwtDecoder {
|
class ResilienceReactiveJwtDecoder(private val jwkSetUri: String) : ReactiveJwtDecoder {
|
||||||
return ReactiveJwtDecoder { token ->
|
private val logger = LoggerFactory.getLogger(ResilienceReactiveJwtDecoder::class.java)
|
||||||
throw IllegalStateException("JWT validation is not available - Keycloak may not be running")
|
private var delegate: ReactiveJwtDecoder? = null
|
||||||
|
|
||||||
|
override fun decode(token: String): Mono<org.springframework.security.oauth2.jwt.Jwt> {
|
||||||
|
if (delegate == null) {
|
||||||
|
synchronized(this) {
|
||||||
|
if (delegate == null) {
|
||||||
|
try {
|
||||||
|
if (jwkSetUri.isBlank()) {
|
||||||
|
throw IllegalArgumentException("JWK Set URI is missing")
|
||||||
|
}
|
||||||
|
logger.info("Attempting to initialize JWT Decoder with URI: {}", jwkSetUri)
|
||||||
|
delegate = NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri).build()
|
||||||
|
logger.info("JWT Decoder successfully initialized.")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.warn("Could not initialize JWT Decoder (Keycloak might be down): {}", e.message)
|
||||||
|
return Mono.error(IllegalStateException("Identity Provider currently unavailable. Please try again later."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return delegate!!.decode(token)
|
||||||
|
.onErrorResume { e ->
|
||||||
|
// Falls der Decoder zwar da ist, aber z.B. Netzwerkfehler auftreten, loggen wir das
|
||||||
|
logger.debug("JWT decoding failed: {}", e.message)
|
||||||
|
Mono.error(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,11 @@ management:
|
||||||
web:
|
web:
|
||||||
exposure:
|
exposure:
|
||||||
include: health,info,prometheus
|
include: health,info,prometheus
|
||||||
|
tracing:
|
||||||
|
sampling:
|
||||||
|
probability: 1.0 # 100% der Requests tracen (für Dev/Test sinnvoll, in Prod reduzieren)
|
||||||
|
propagation:
|
||||||
|
type: w3c # Standard W3C Trace Context (kompatibel mit OpenTelemetry)
|
||||||
|
|
||||||
# Gateway-spezifische Einstellungen
|
# Gateway-spezifische Einstellungen
|
||||||
gateway:
|
gateway:
|
||||||
|
|
|
||||||
|
|
@ -1,61 +1,38 @@
|
||||||
// Optimized Spring Boot ping service for testing microservice architecture
|
|
||||||
// This service demonstrates circuit breaker patterns, service discovery, and monitoring
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.kotlinJvm)
|
alias(libs.plugins.kotlinJvm)
|
||||||
alias(libs.plugins.kotlinSpring)
|
alias(libs.plugins.kotlinSpring)
|
||||||
alias(libs.plugins.kotlinJpa)
|
alias(libs.plugins.kotlinJpa)
|
||||||
alias(libs.plugins.spring.boot)
|
alias(libs.plugins.spring.boot)
|
||||||
// FINALE BEREINIGUNG: Das `dependencyManagement`-Plugin wird entfernt.
|
|
||||||
// alias(libs.plugins.spring.dependencyManagement)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the main class for the executable JAR
|
kotlin {
|
||||||
springBoot {
|
compilerOptions {
|
||||||
mainClass.set("at.mocode.ping.service.PingServiceApplicationKt")
|
// Aktiviert die experimentelle UUID API von Kotlin 2.3.0
|
||||||
|
freeCompilerArgs.add("-opt-in=kotlin.uuid.ExperimentalUuidApi")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// Die `platform`-Deklaration ist der einzig korrekte Weg.
|
// === Project Dependencies ===
|
||||||
implementation(platform(projects.platform.platformBom))
|
|
||||||
|
|
||||||
// Platform und Core Dependencies
|
|
||||||
implementation(projects.platform.platformDependencies)
|
|
||||||
implementation(projects.backend.services.ping.pingApi)
|
implementation(projects.backend.services.ping.pingApi)
|
||||||
implementation(projects.backend.infrastructure.monitoring.monitoringClient)
|
implementation(projects.platform.platformDependencies)
|
||||||
|
|
||||||
// Spring Boot Service Complete Bundle
|
// === Spring Boot & Cloud ===
|
||||||
// Provides: web, validation, actuator, security, oauth2-client, oauth2-resource-server,
|
|
||||||
// data-jpa, data-redis, micrometer-prometheus, tracing, zipkin
|
|
||||||
implementation(libs.bundles.spring.boot.service.complete)
|
implementation(libs.bundles.spring.boot.service.complete)
|
||||||
|
// WICHTIG: Da wir JPA (blockierend) nutzen, brauchen wir Spring MVC (nicht WebFlux)
|
||||||
// Datenbank (PostgresQL) Driver
|
|
||||||
implementation(libs.postgresql.driver)
|
|
||||||
|
|
||||||
// Web-Server (Tomcat) explizit hinzufügen!
|
|
||||||
implementation(libs.spring.boot.starter.web)
|
implementation(libs.spring.boot.starter.web)
|
||||||
|
implementation(libs.bundles.spring.cloud.gateway) // Für Discovery Client
|
||||||
|
|
||||||
// Jackson Kotlin Support Bundle
|
// === Database & Persistence ===
|
||||||
implementation(libs.bundles.jackson.kotlin)
|
implementation(libs.bundles.database.complete)
|
||||||
|
|
||||||
// Kotlin Reflection (now from version catalog)
|
// === Resilience ===
|
||||||
implementation(libs.kotlin.reflect)
|
|
||||||
|
|
||||||
// Service Discovery
|
|
||||||
implementation(libs.spring.cloud.starter.consul.discovery)
|
|
||||||
|
|
||||||
// Caching (Caffeine for Spring Cloud LoadBalancer)
|
|
||||||
implementation(libs.caffeine)
|
|
||||||
implementation(libs.spring.web) // Provides spring-context-support
|
|
||||||
|
|
||||||
// Resilience4j Bundle (Circuit Breaker, Reactor, AOP)
|
|
||||||
implementation(libs.bundles.resilience)
|
implementation(libs.bundles.resilience)
|
||||||
|
|
||||||
// OpenAPI Documentation
|
// === Testing ===
|
||||||
implementation(libs.springdoc.openapi.starter.webmvc.ui)
|
|
||||||
|
|
||||||
// Test Dependencies
|
|
||||||
testImplementation(projects.platform.platformTesting)
|
|
||||||
testImplementation(libs.bundles.testing.jvm)
|
testImplementation(libs.bundles.testing.jvm)
|
||||||
testImplementation(libs.spring.boot.starter.test)
|
}
|
||||||
testImplementation(libs.spring.boot.starter.web)
|
|
||||||
|
tasks.test {
|
||||||
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
package at.mocode.ping.service
|
package at.mocode.ping
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||||
import org.springframework.boot.runApplication
|
import org.springframework.boot.runApplication
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.EnableAspectJAutoProxy
|
import org.springframework.context.annotation.EnableAspectJAutoProxy
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry
|
import org.springframework.web.reactive.config.CorsRegistry
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
|
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
// Scannt explizit alle Sub-Packages (infrastructure, application, domain)
|
||||||
@EnableAspectJAutoProxy
|
@EnableAspectJAutoProxy
|
||||||
class PingServiceApplication {
|
class PingServiceApplication {
|
||||||
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
package at.mocode.ping.application
|
||||||
|
|
||||||
|
import at.mocode.ping.domain.Ping
|
||||||
|
import at.mocode.ping.domain.PingRepository
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
import kotlin.uuid.ExperimentalUuidApi
|
||||||
|
import kotlin.uuid.Uuid
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application Service.
|
||||||
|
* Implementiert den Use Case und orchestriert Domain & Repository.
|
||||||
|
* Hier darf Spring (@Service, @Transactional) verwendet werden, da es "Application Logic" ist.
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@OptIn(ExperimentalUuidApi::class)
|
||||||
|
class PingService(
|
||||||
|
private val repository: PingRepository
|
||||||
|
) : PingUseCase {
|
||||||
|
|
||||||
|
private val logger = LoggerFactory.getLogger(PingService::class.java)
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
override fun executePing(message: String): Ping {
|
||||||
|
logger.info("Executing ping with message: {}", message)
|
||||||
|
|
||||||
|
// Domain Logic: Erstelle neue Entity (generiert UUID v7 automatisch)
|
||||||
|
val ping = Ping(message = message)
|
||||||
|
|
||||||
|
// Persistence
|
||||||
|
return repository.save(ping)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
override fun getPingHistory(): List<Ping> {
|
||||||
|
return repository.findAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
override fun getPing(id: Uuid): Ping? {
|
||||||
|
return repository.findById(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package at.mocode.ping.application
|
||||||
|
|
||||||
|
import at.mocode.ping.domain.Ping
|
||||||
|
import kotlin.uuid.ExperimentalUuidApi
|
||||||
|
import kotlin.uuid.Uuid
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Primary Port (Inbound Port).
|
||||||
|
* Definiert die fachlichen Operationen, die von außen (Controller) aufgerufen werden können.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalUuidApi::class)
|
||||||
|
interface PingUseCase {
|
||||||
|
fun executePing(message: String): Ping
|
||||||
|
fun getPingHistory(): List<Ping>
|
||||||
|
fun getPing(id: Uuid): Ping?
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package at.mocode.ping.domain
|
||||||
|
|
||||||
|
import kotlin.uuid.ExperimentalUuidApi
|
||||||
|
import kotlin.uuid.Uuid
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Domain Entity für einen Ping.
|
||||||
|
* Unabhängig von Frameworks (Pure Kotlin).
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalUuidApi::class)
|
||||||
|
data class Ping(
|
||||||
|
val id: Uuid = Uuid.generateV7(), // Kotlin 2.3.0 UUID v7
|
||||||
|
val message: String,
|
||||||
|
val timestamp: Instant = Instant.now()
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package at.mocode.ping.domain
|
||||||
|
|
||||||
|
import kotlin.uuid.ExperimentalUuidApi
|
||||||
|
import kotlin.uuid.Uuid
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Secondary Port (Outbound Port).
|
||||||
|
* Definiert, wie Pings gespeichert werden, ohne die Technologie (DB) zu kennen.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalUuidApi::class)
|
||||||
|
interface PingRepository {
|
||||||
|
fun save(ping: Ping): Ping
|
||||||
|
fun findAll(): List<Ping>
|
||||||
|
fun findById(id: Uuid): Ping?
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package at.mocode.ping.infrastructure.persistence
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity
|
||||||
|
import jakarta.persistence.Id
|
||||||
|
import jakarta.persistence.Table
|
||||||
|
import java.time.Instant
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JPA Entity (Infrastructure Detail).
|
||||||
|
* Spiegelt die Datenbank-Tabelle wider.
|
||||||
|
* Nutzt java.util.UUID für JPA-Kompatibilität (bis Hibernate kotlin.uuid nativ unterstützt).
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "pings")
|
||||||
|
class PingJpaEntity(
|
||||||
|
@Id
|
||||||
|
val id: UUID,
|
||||||
|
val message: String,
|
||||||
|
val timestamp: Instant
|
||||||
|
) {
|
||||||
|
// Default constructor for JPA
|
||||||
|
protected constructor() : this(UUID.randomUUID(), "", Instant.now())
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
package at.mocode.ping.infrastructure.persistence
|
||||||
|
|
||||||
|
import at.mocode.ping.domain.Ping
|
||||||
|
import at.mocode.ping.domain.PingRepository
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
import kotlin.uuid.ExperimentalUuidApi
|
||||||
|
import kotlin.uuid.Uuid
|
||||||
|
import kotlin.uuid.toJavaUuid
|
||||||
|
import kotlin.uuid.toKotlinUuid
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Driven Adapter.
|
||||||
|
* Implementiert den Domain-Port `PingRepository` mithilfe von Spring Data JPA.
|
||||||
|
* Mappt zwischen Domain-Entity und JPA-Entity.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@OptIn(ExperimentalUuidApi::class)
|
||||||
|
class PingRepositoryAdapter(
|
||||||
|
private val jpaRepository: SpringDataPingRepository
|
||||||
|
) : PingRepository {
|
||||||
|
|
||||||
|
override fun save(ping: Ping): Ping {
|
||||||
|
val jpaEntity = PingJpaEntity(
|
||||||
|
id = ping.id.toJavaUuid(),
|
||||||
|
message = ping.message,
|
||||||
|
timestamp = ping.timestamp
|
||||||
|
)
|
||||||
|
val saved = jpaRepository.save(jpaEntity)
|
||||||
|
return mapToDomain(saved)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun findAll(): List<Ping> {
|
||||||
|
return jpaRepository.findAll().map { mapToDomain(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun findById(id: Uuid): Ping? {
|
||||||
|
return jpaRepository.findById(id.toJavaUuid())
|
||||||
|
.map { mapToDomain(it) }
|
||||||
|
.orElse(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun mapToDomain(entity: PingJpaEntity): Ping {
|
||||||
|
return Ping(
|
||||||
|
id = entity.id.toKotlinUuid(),
|
||||||
|
message = entity.message,
|
||||||
|
timestamp = entity.timestamp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package at.mocode.ping.infrastructure.persistence
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository
|
||||||
|
import org.springframework.stereotype.Repository
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
interface SpringDataPingRepository : JpaRepository<PingJpaEntity, UUID>
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
package at.mocode.ping.infrastructure.web
|
||||||
|
|
||||||
|
import at.mocode.ping.api.EnhancedPingResponse
|
||||||
|
import at.mocode.ping.api.HealthResponse
|
||||||
|
import at.mocode.ping.api.PingApi
|
||||||
|
import at.mocode.ping.api.PingResponse
|
||||||
|
import at.mocode.ping.application.PingUseCase
|
||||||
|
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.web.bind.annotation.*
|
||||||
|
import java.time.ZoneOffset
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Driving Adapter (REST Controller).
|
||||||
|
* Nutzt den Application Port (PingUseCase).
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@CrossOrigin(allowedHeaders = ["*"], allowCredentials = "true")
|
||||||
|
class PingController(
|
||||||
|
private val pingUseCase: PingUseCase
|
||||||
|
) : PingApi {
|
||||||
|
|
||||||
|
private val logger = LoggerFactory.getLogger(PingController::class.java)
|
||||||
|
private val formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val PING_CIRCUIT_BREAKER = "pingCircuitBreaker"
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/ping/simple")
|
||||||
|
override suspend fun simplePing(): PingResponse {
|
||||||
|
// Ruft Use Case auf -> Speichert in DB
|
||||||
|
val domainPing = pingUseCase.executePing("Simple Ping")
|
||||||
|
|
||||||
|
return PingResponse(
|
||||||
|
status = "pong",
|
||||||
|
timestamp = domainPing.timestamp.atOffset(ZoneOffset.UTC).format(formatter),
|
||||||
|
service = "ping-service"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/ping/enhanced")
|
||||||
|
@CircuitBreaker(name = PING_CIRCUIT_BREAKER, fallbackMethod = "fallbackPing")
|
||||||
|
override suspend fun enhancedPing(
|
||||||
|
@RequestParam(required = false, defaultValue = "false") simulate: Boolean
|
||||||
|
): EnhancedPingResponse {
|
||||||
|
val start = System.nanoTime()
|
||||||
|
|
||||||
|
if (simulate && Random.nextDouble() < 0.6) {
|
||||||
|
throw RuntimeException("Simulated service failure")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use Case Aufruf
|
||||||
|
val domainPing = pingUseCase.executePing("Enhanced Ping")
|
||||||
|
|
||||||
|
val elapsedMs = (System.nanoTime() - start) / 1_000_000
|
||||||
|
|
||||||
|
return EnhancedPingResponse(
|
||||||
|
status = "pong",
|
||||||
|
timestamp = domainPing.timestamp.atOffset(ZoneOffset.UTC).format(formatter),
|
||||||
|
service = "ping-service",
|
||||||
|
circuitBreakerState = "CLOSED",
|
||||||
|
responseTime = elapsedMs
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback muss public sein für Resilience4j Proxy
|
||||||
|
fun fallbackPing(simulate: Boolean, ex: Exception): EnhancedPingResponse {
|
||||||
|
logger.warn("Circuit breaker fallback triggered: {}", ex.message)
|
||||||
|
return EnhancedPingResponse(
|
||||||
|
status = "fallback",
|
||||||
|
timestamp = java.time.OffsetDateTime.now().format(formatter),
|
||||||
|
service = "ping-service-fallback",
|
||||||
|
circuitBreakerState = "OPEN",
|
||||||
|
responseTime = 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/ping/health")
|
||||||
|
override suspend fun healthCheck(): HealthResponse {
|
||||||
|
return HealthResponse(
|
||||||
|
status = "up",
|
||||||
|
timestamp = java.time.OffsetDateTime.now().format(formatter),
|
||||||
|
service = "ping-service",
|
||||||
|
healthy = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zusätzlicher Endpunkt um die DB zu prüfen (History)
|
||||||
|
@GetMapping("/ping/history")
|
||||||
|
fun getHistory() = pingUseCase.getPingHistory().map {
|
||||||
|
mapOf("id" to it.id.toString(), "message" to it.message, "time" to it.timestamp.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
package at.mocode.ping.service
|
|
||||||
|
|
||||||
import at.mocode.ping.api.EnhancedPingResponse
|
|
||||||
import at.mocode.ping.api.HealthResponse
|
|
||||||
import at.mocode.ping.api.PingApi
|
|
||||||
import at.mocode.ping.api.PingResponse
|
|
||||||
import org.springframework.web.bind.annotation.*
|
|
||||||
import java.time.OffsetDateTime
|
|
||||||
import java.time.format.DateTimeFormatter
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
@CrossOrigin(
|
|
||||||
origins = ["http://localhost:8080", "http://localhost:8083", "http://localhost:4000"],
|
|
||||||
methods = [RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE, RequestMethod.OPTIONS],
|
|
||||||
allowedHeaders = ["*"],
|
|
||||||
allowCredentials = "true"
|
|
||||||
)
|
|
||||||
class PingController(
|
|
||||||
private val pingService: PingServiceCircuitBreaker
|
|
||||||
) : PingApi {
|
|
||||||
|
|
||||||
// Contract endpoints
|
|
||||||
@GetMapping("/ping/simple")
|
|
||||||
override suspend fun simplePing(): PingResponse {
|
|
||||||
val now = OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
|
|
||||||
return PingResponse(
|
|
||||||
status = "pong",
|
|
||||||
timestamp = now,
|
|
||||||
service = "ping-service"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/ping/enhanced")
|
|
||||||
override suspend fun enhancedPing(
|
|
||||||
@RequestParam(required = false, defaultValue = "false") simulate: Boolean
|
|
||||||
): EnhancedPingResponse = pingService.ping(simulate)
|
|
||||||
|
|
||||||
@GetMapping("/ping/health")
|
|
||||||
override suspend fun healthCheck(): HealthResponse = pingService.healthCheck()
|
|
||||||
}
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
package at.mocode.ping.service
|
|
||||||
|
|
||||||
import at.mocode.ping.api.EnhancedPingResponse
|
|
||||||
import at.mocode.ping.api.HealthResponse
|
|
||||||
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker
|
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import org.springframework.stereotype.Service
|
|
||||||
import java.time.LocalDateTime
|
|
||||||
import java.time.format.DateTimeFormatter
|
|
||||||
import kotlin.random.Random
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Service demonstrating a Circuit Breaker pattern with Resilience
|
|
||||||
*
|
|
||||||
* This service simulates potential failures and uses circuit breaker
|
|
||||||
* to handle service degradation gracefully with fallback responses.
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
class PingServiceCircuitBreaker {
|
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(PingServiceCircuitBreaker::class.java)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val PING_CIRCUIT_BREAKER = "pingCircuitBreaker"
|
|
||||||
private val formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME //.ofPattern("yyyy-MM-dd HH:mm:ss")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Primary ping method with circuit breaker protection returning DTO directly
|
|
||||||
*
|
|
||||||
* @param simulateFailure - if true, randomly throws exceptions to test circuit breaker
|
|
||||||
*/
|
|
||||||
@CircuitBreaker(name = PING_CIRCUIT_BREAKER, fallbackMethod = "fallbackPing")
|
|
||||||
fun ping(simulateFailure: Boolean = false): EnhancedPingResponse {
|
|
||||||
val start = System.nanoTime()
|
|
||||||
logger.info("Executing ping service call...")
|
|
||||||
|
|
||||||
if (simulateFailure && Random.nextDouble() < 0.6) {
|
|
||||||
logger.warn("Simulating service failure for circuit breaker testing")
|
|
||||||
throw RuntimeException("Simulated service failure")
|
|
||||||
}
|
|
||||||
|
|
||||||
val currentTime = LocalDateTime.now().atOffset(java.time.ZoneOffset.UTC).format(formatter)
|
|
||||||
val elapsedMs = (System.nanoTime() - start) / 1_000_000
|
|
||||||
logger.info("Ping service call successful")
|
|
||||||
|
|
||||||
return EnhancedPingResponse(
|
|
||||||
status = "pong",
|
|
||||||
timestamp = currentTime,
|
|
||||||
service = "ping-service",
|
|
||||||
circuitBreakerState = "CLOSED",
|
|
||||||
responseTime = elapsedMs
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fallback method called when circuit breaker is OPEN
|
|
||||||
*
|
|
||||||
* @param simulateFailure - original parameter (ignored in fallback)
|
|
||||||
* @param exception - the exception that triggered the fallback
|
|
||||||
*/
|
|
||||||
fun fallbackPing(simulateFailure: Boolean = false, exception: Exception): EnhancedPingResponse {
|
|
||||||
val start = System.nanoTime()
|
|
||||||
// Die volle Exception nur loggen, nicht an den Client weitergeben.
|
|
||||||
logger.warn("Circuit breaker fallback triggered due to: {}", exception.toString())
|
|
||||||
|
|
||||||
val currentTime = LocalDateTime.now().atOffset(java.time.ZoneOffset.UTC).format(formatter)
|
|
||||||
val elapsedMs = (System.nanoTime() - start) / 1_000_000
|
|
||||||
|
|
||||||
return EnhancedPingResponse(
|
|
||||||
status = "fallback",
|
|
||||||
timestamp = currentTime,
|
|
||||||
service = "ping-service-fallback",
|
|
||||||
circuitBreakerState = "OPEN",
|
|
||||||
responseTime = elapsedMs
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Health check method with circuit breaker protection returning DTO directly
|
|
||||||
*/
|
|
||||||
@CircuitBreaker(name = PING_CIRCUIT_BREAKER, fallbackMethod = "fallbackHealth")
|
|
||||||
fun healthCheck(): HealthResponse {
|
|
||||||
logger.info("Executing health check...")
|
|
||||||
|
|
||||||
val currentTime = LocalDateTime.now().atOffset(java.time.ZoneOffset.UTC).format(formatter)
|
|
||||||
return HealthResponse(
|
|
||||||
status = "pong",
|
|
||||||
timestamp = currentTime,
|
|
||||||
service = "ping-service",
|
|
||||||
healthy = true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fallback for health check returning DTO
|
|
||||||
*/
|
|
||||||
fun fallbackHealth(exception: Exception): HealthResponse {
|
|
||||||
logger.warn("Health check fallback triggered: {}", exception.message)
|
|
||||||
|
|
||||||
val currentTime = LocalDateTime.now().atOffset(java.time.ZoneOffset.UTC).format(formatter)
|
|
||||||
return HealthResponse(
|
|
||||||
status = "down",
|
|
||||||
timestamp = currentTime,
|
|
||||||
service = "ping-service",
|
|
||||||
healthy = false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -16,8 +16,9 @@ kotlinx-coroutines = "1.10.2"
|
||||||
|
|
||||||
|
|
||||||
# --- Spring Ecosystem ---
|
# --- Spring Ecosystem ---
|
||||||
springBoot = "4.0.1"
|
# KORREKTUR: Version auf Benutzerwunsch angepasst (war 4.0.1)
|
||||||
# Spring Cloud Version kompatibel zu Spring Boot 4.0.1
|
springBoot = "3.5.9"
|
||||||
|
# Spring Cloud Version kompatibel zu Spring Boot
|
||||||
springCloud = "2025.1.0"
|
springCloud = "2025.1.0"
|
||||||
# springCloudGateway = "4.3.0"
|
# springCloudGateway = "4.3.0"
|
||||||
springDependencyManagement = "1.1.7"
|
springDependencyManagement = "1.1.7"
|
||||||
|
|
@ -153,8 +154,8 @@ spring-boot-starter-oauth2-resource-server = { module = "org.springframework.boo
|
||||||
spring-boot-starter-security = { module = "org.springframework.boot:spring-boot-starter-security" }
|
spring-boot-starter-security = { module = "org.springframework.boot:spring-boot-starter-security" }
|
||||||
spring-boot-starter-webflux = { module = "org.springframework.boot:spring-boot-starter-webflux" }
|
spring-boot-starter-webflux = { module = "org.springframework.boot:spring-boot-starter-webflux" }
|
||||||
spring-boot-starter-json = { module = "org.springframework.boot:spring-boot-starter-json" }
|
spring-boot-starter-json = { module = "org.springframework.boot:spring-boot-starter-json" }
|
||||||
# KORREKTUR: Fehlende Definition für spring-boot-starter-aop hinzugefügt.
|
# KORREKTUR: Explizite Versionierung über BOM-Referenz
|
||||||
spring-boot-starter-aop = { module = "org.springframework.boot:spring-boot-starter-aop" }
|
spring-boot-starter-aop = { module = "org.springframework.boot:spring-boot-starter-aop", version.ref = "springBoot" }
|
||||||
spring-kafka = { module = "org.springframework.kafka:spring-kafka" }
|
spring-kafka = { module = "org.springframework.kafka:spring-kafka" }
|
||||||
spring-security-oauth2-jose = { module = "org.springframework.security:spring-security-oauth2-jose" }
|
spring-security-oauth2-jose = { module = "org.springframework.security:spring-security-oauth2-jose" }
|
||||||
spring-web = { module = "org.springframework:spring-web" }
|
spring-web = { module = "org.springframework:spring-web" }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user