mirror of
https://github.com/pcvolkmer/etl-processor.git
synced 2025-04-19 17:26:51 +00:00
Merge pull request #54 from CCC-MF/issue_53
Anzeige gPAS Verbindungsstatus
This commit is contained in:
commit
a8e008000e
@ -19,11 +19,14 @@
|
|||||||
|
|
||||||
package dev.dnpm.etl.processor.web
|
package dev.dnpm.etl.processor.web
|
||||||
|
|
||||||
|
import dev.dnpm.etl.processor.config.AppConfiguration
|
||||||
import dev.dnpm.etl.processor.config.AppSecurityConfiguration
|
import dev.dnpm.etl.processor.config.AppSecurityConfiguration
|
||||||
import dev.dnpm.etl.processor.monitoring.ConnectionCheckService
|
import dev.dnpm.etl.processor.monitoring.ConnectionCheckService
|
||||||
|
import dev.dnpm.etl.processor.monitoring.RestConnectionCheckService
|
||||||
import dev.dnpm.etl.processor.output.MtbFileSender
|
import dev.dnpm.etl.processor.output.MtbFileSender
|
||||||
import dev.dnpm.etl.processor.pseudonym.Generator
|
import dev.dnpm.etl.processor.pseudonym.Generator
|
||||||
import dev.dnpm.etl.processor.services.RequestProcessor
|
import dev.dnpm.etl.processor.services.RequestProcessor
|
||||||
|
import dev.dnpm.etl.processor.services.TokenRepository
|
||||||
import dev.dnpm.etl.processor.services.TransformationService
|
import dev.dnpm.etl.processor.services.TransformationService
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
@ -50,6 +53,7 @@ abstract class MockSink : Sinks.Many<Boolean>
|
|||||||
@ContextConfiguration(
|
@ContextConfiguration(
|
||||||
classes = [
|
classes = [
|
||||||
ConfigController::class,
|
ConfigController::class,
|
||||||
|
AppConfiguration::class,
|
||||||
AppSecurityConfiguration::class
|
AppSecurityConfiguration::class
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -67,7 +71,9 @@ abstract class MockSink : Sinks.Many<Boolean>
|
|||||||
MtbFileSender::class,
|
MtbFileSender::class,
|
||||||
ConnectionCheckService::class,
|
ConnectionCheckService::class,
|
||||||
RequestProcessor::class,
|
RequestProcessor::class,
|
||||||
TransformationService::class
|
TransformationService::class,
|
||||||
|
TokenRepository::class,
|
||||||
|
RestConnectionCheckService::class
|
||||||
)
|
)
|
||||||
class ConfigControllerTest {
|
class ConfigControllerTest {
|
||||||
|
|
||||||
|
@ -67,11 +67,13 @@ public class GpasPseudonymGenerator implements Generator {
|
|||||||
private final RetryTemplate retryTemplate;
|
private final RetryTemplate retryTemplate;
|
||||||
private final Logger log = LoggerFactory.getLogger(GpasPseudonymGenerator.class);
|
private final Logger log = LoggerFactory.getLogger(GpasPseudonymGenerator.class);
|
||||||
|
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
|
||||||
private SSLContext customSslContext;
|
private SSLContext customSslContext;
|
||||||
private RestTemplate restTemplate;
|
|
||||||
|
|
||||||
public GpasPseudonymGenerator(GPasConfigProperties gpasCfg, RetryTemplate retryTemplate) {
|
public GpasPseudonymGenerator(GPasConfigProperties gpasCfg, RetryTemplate retryTemplate) {
|
||||||
this.retryTemplate = retryTemplate;
|
this.retryTemplate = retryTemplate;
|
||||||
|
this.restTemplate = getRestTemplete();
|
||||||
|
|
||||||
this.gPasUrl = gpasCfg.getUri();
|
this.gPasUrl = gpasCfg.getUri();
|
||||||
this.psnTargetDomain = gpasCfg.getTarget();
|
this.psnTargetDomain = gpasCfg.getTarget();
|
||||||
@ -139,7 +141,6 @@ public class GpasPseudonymGenerator implements Generator {
|
|||||||
|
|
||||||
HttpEntity<String> requestEntity = new HttpEntity<>(gPasRequestBody, this.httpHeader);
|
HttpEntity<String> requestEntity = new HttpEntity<>(gPasRequestBody, this.httpHeader);
|
||||||
ResponseEntity<String> responseEntity;
|
ResponseEntity<String> responseEntity;
|
||||||
var restTemplate = getRestTemplete();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
responseEntity = retryTemplate.execute(
|
responseEntity = retryTemplate.execute(
|
||||||
@ -226,14 +227,8 @@ public class GpasPseudonymGenerator implements Generator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected RestTemplate getRestTemplete() {
|
protected RestTemplate getRestTemplete() {
|
||||||
|
|
||||||
if (restTemplate != null) {
|
|
||||||
return restTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (customSslContext == null) {
|
if (customSslContext == null) {
|
||||||
restTemplate = new RestTemplate();
|
return new RestTemplate();
|
||||||
return restTemplate;
|
|
||||||
}
|
}
|
||||||
final var sslsf = new SSLConnectionSocketFactory(customSslContext);
|
final var sslsf = new SSLConnectionSocketFactory(customSslContext);
|
||||||
final Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
|
final Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
|
||||||
@ -246,7 +241,6 @@ public class GpasPseudonymGenerator implements Generator {
|
|||||||
|
|
||||||
final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(
|
final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(
|
||||||
httpClient);
|
httpClient);
|
||||||
restTemplate = new RestTemplate(requestFactory);
|
return new RestTemplate(requestFactory);
|
||||||
return restTemplate;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
package dev.dnpm.etl.processor.config
|
package dev.dnpm.etl.processor.config
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import dev.dnpm.etl.processor.monitoring.ReportService
|
import dev.dnpm.etl.processor.monitoring.*
|
||||||
import dev.dnpm.etl.processor.pseudonym.AnonymizingGenerator
|
import dev.dnpm.etl.processor.pseudonym.AnonymizingGenerator
|
||||||
import dev.dnpm.etl.processor.pseudonym.Generator
|
import dev.dnpm.etl.processor.pseudonym.Generator
|
||||||
import dev.dnpm.etl.processor.pseudonym.GpasPseudonymGenerator
|
import dev.dnpm.etl.processor.pseudonym.GpasPseudonymGenerator
|
||||||
@ -44,6 +44,7 @@ import org.springframework.retry.support.RetryTemplateBuilder
|
|||||||
import org.springframework.scheduling.annotation.EnableScheduling
|
import org.springframework.scheduling.annotation.EnableScheduling
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder
|
import org.springframework.security.crypto.password.PasswordEncoder
|
||||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
||||||
|
import org.springframework.web.client.RestTemplate
|
||||||
import reactor.core.publisher.Sinks
|
import reactor.core.publisher.Sinks
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
import kotlin.time.toJavaDuration
|
import kotlin.time.toJavaDuration
|
||||||
@ -62,6 +63,11 @@ class AppConfiguration {
|
|||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(AppConfiguration::class.java)
|
private val logger = LoggerFactory.getLogger(AppConfiguration::class.java)
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun restTemplate(): RestTemplate {
|
||||||
|
return RestTemplate()
|
||||||
|
}
|
||||||
|
|
||||||
@ConditionalOnProperty(value = ["app.pseudonymize.generator"], havingValue = "GPAS")
|
@ConditionalOnProperty(value = ["app.pseudonymize.generator"], havingValue = "GPAS")
|
||||||
@Bean
|
@Bean
|
||||||
fun gpasPseudonymGenerator(configProperties: GPasConfigProperties, retryTemplate: RetryTemplate): Generator {
|
fun gpasPseudonymGenerator(configProperties: GPasConfigProperties, retryTemplate: RetryTemplate): Generator {
|
||||||
@ -142,8 +148,29 @@ class AppConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun configsUpdateProducer(): Sinks.Many<Boolean> {
|
fun connectionCheckUpdateProducer(): Sinks.Many<ConnectionCheckResult> {
|
||||||
return Sinks.many().multicast().directBestEffort()
|
return Sinks.many().multicast().onBackpressureBuffer()
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConditionalOnProperty(value = ["app.pseudonymize.generator"], havingValue = "GPAS")
|
||||||
|
@Bean
|
||||||
|
fun gPasConnectionCheckService(
|
||||||
|
restTemplate: RestTemplate,
|
||||||
|
gPasConfigProperties: GPasConfigProperties,
|
||||||
|
connectionCheckUpdateProducer: Sinks.Many<ConnectionCheckResult>
|
||||||
|
): ConnectionCheckService {
|
||||||
|
return GPasConnectionCheckService(restTemplate, gPasConfigProperties, connectionCheckUpdateProducer)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConditionalOnProperty(value = ["app.pseudonymizer"], havingValue = "GPAS")
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
@Bean
|
||||||
|
fun gPasConnectionCheckServiceOnDeprecatedProperty(
|
||||||
|
restTemplate: RestTemplate,
|
||||||
|
gPasConfigProperties: GPasConfigProperties,
|
||||||
|
connectionCheckUpdateProducer: Sinks.Many<ConnectionCheckResult>
|
||||||
|
): ConnectionCheckService {
|
||||||
|
return GPasConnectionCheckService(restTemplate, gPasConfigProperties, connectionCheckUpdateProducer)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ package dev.dnpm.etl.processor.config
|
|||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import dev.dnpm.etl.processor.input.KafkaInputListener
|
import dev.dnpm.etl.processor.input.KafkaInputListener
|
||||||
|
import dev.dnpm.etl.processor.monitoring.ConnectionCheckResult
|
||||||
import dev.dnpm.etl.processor.monitoring.ConnectionCheckService
|
import dev.dnpm.etl.processor.monitoring.ConnectionCheckService
|
||||||
import dev.dnpm.etl.processor.monitoring.KafkaConnectionCheckService
|
import dev.dnpm.etl.processor.monitoring.KafkaConnectionCheckService
|
||||||
import dev.dnpm.etl.processor.output.KafkaMtbFileSender
|
import dev.dnpm.etl.processor.output.KafkaMtbFileSender
|
||||||
@ -105,8 +106,11 @@ class AppKafkaConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun connectionCheckService(consumerFactory: ConsumerFactory<String, String>, configsUpdateProducer: Sinks.Many<Boolean>): ConnectionCheckService {
|
fun kafkaConnectionCheckService(
|
||||||
return KafkaConnectionCheckService(consumerFactory.createConsumer(), configsUpdateProducer)
|
consumerFactory: ConsumerFactory<String, String>,
|
||||||
|
connectionCheckUpdateProducer: Sinks.Many<ConnectionCheckResult>
|
||||||
|
): ConnectionCheckService {
|
||||||
|
return KafkaConnectionCheckService(consumerFactory.createConsumer(), connectionCheckUpdateProducer)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package dev.dnpm.etl.processor.config
|
package dev.dnpm.etl.processor.config
|
||||||
|
|
||||||
|
import dev.dnpm.etl.processor.monitoring.ConnectionCheckResult
|
||||||
import dev.dnpm.etl.processor.monitoring.ConnectionCheckService
|
import dev.dnpm.etl.processor.monitoring.ConnectionCheckService
|
||||||
import dev.dnpm.etl.processor.monitoring.RestConnectionCheckService
|
import dev.dnpm.etl.processor.monitoring.RestConnectionCheckService
|
||||||
import dev.dnpm.etl.processor.output.MtbFileSender
|
import dev.dnpm.etl.processor.output.MtbFileSender
|
||||||
@ -47,11 +48,6 @@ class AppRestConfiguration {
|
|||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(AppRestConfiguration::class.java)
|
private val logger = LoggerFactory.getLogger(AppRestConfiguration::class.java)
|
||||||
|
|
||||||
@Bean
|
|
||||||
fun restTemplate(): RestTemplate {
|
|
||||||
return RestTemplate()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun restMtbFileSender(
|
fun restMtbFileSender(
|
||||||
restTemplate: RestTemplate,
|
restTemplate: RestTemplate,
|
||||||
@ -63,12 +59,12 @@ class AppRestConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun connectionCheckService(
|
fun restConnectionCheckService(
|
||||||
restTemplate: RestTemplate,
|
restTemplate: RestTemplate,
|
||||||
restTargetProperties: RestTargetProperties,
|
restTargetProperties: RestTargetProperties,
|
||||||
configsUpdateProducer: Sinks.Many<Boolean>
|
connectionCheckUpdateProducer: Sinks.Many<ConnectionCheckResult>
|
||||||
): ConnectionCheckService {
|
): ConnectionCheckService {
|
||||||
return RestConnectionCheckService(restTemplate, restTargetProperties, configsUpdateProducer)
|
return RestConnectionCheckService(restTemplate, restTargetProperties, connectionCheckUpdateProducer)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,14 +20,21 @@
|
|||||||
|
|
||||||
package dev.dnpm.etl.processor.monitoring
|
package dev.dnpm.etl.processor.monitoring
|
||||||
|
|
||||||
|
import dev.dnpm.etl.processor.config.GPasConfigProperties
|
||||||
import dev.dnpm.etl.processor.config.RestTargetProperties
|
import dev.dnpm.etl.processor.config.RestTargetProperties
|
||||||
import jakarta.annotation.PostConstruct
|
import jakarta.annotation.PostConstruct
|
||||||
import org.apache.kafka.clients.consumer.Consumer
|
import org.apache.kafka.clients.consumer.Consumer
|
||||||
import org.apache.kafka.common.errors.TimeoutException
|
import org.apache.kafka.common.errors.TimeoutException
|
||||||
import org.springframework.beans.factory.annotation.Qualifier
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
|
import org.springframework.http.HttpEntity
|
||||||
|
import org.springframework.http.HttpHeaders
|
||||||
|
import org.springframework.http.HttpMethod
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
|
import org.springframework.http.MediaType
|
||||||
|
import org.springframework.http.RequestEntity
|
||||||
import org.springframework.scheduling.annotation.Scheduled
|
import org.springframework.scheduling.annotation.Scheduled
|
||||||
import org.springframework.web.client.RestTemplate
|
import org.springframework.web.client.RestTemplate
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder
|
||||||
import reactor.core.publisher.Sinks
|
import reactor.core.publisher.Sinks
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
import kotlin.time.toJavaDuration
|
import kotlin.time.toJavaDuration
|
||||||
@ -38,11 +45,22 @@ interface ConnectionCheckService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface OutputConnectionCheckService : ConnectionCheckService
|
||||||
|
|
||||||
|
sealed class ConnectionCheckResult {
|
||||||
|
|
||||||
|
abstract val available: Boolean
|
||||||
|
|
||||||
|
data class KafkaConnectionCheckResult(override val available: Boolean) : ConnectionCheckResult()
|
||||||
|
data class RestConnectionCheckResult(override val available: Boolean) : ConnectionCheckResult()
|
||||||
|
data class GPasConnectionCheckResult(override val available: Boolean) : ConnectionCheckResult()
|
||||||
|
}
|
||||||
|
|
||||||
class KafkaConnectionCheckService(
|
class KafkaConnectionCheckService(
|
||||||
private val consumer: Consumer<String, String>,
|
private val consumer: Consumer<String, String>,
|
||||||
@Qualifier("configsUpdateProducer")
|
@Qualifier("connectionCheckUpdateProducer")
|
||||||
private val configsUpdateProducer: Sinks.Many<Boolean>
|
private val connectionCheckUpdateProducer: Sinks.Many<ConnectionCheckResult>
|
||||||
) : ConnectionCheckService {
|
) : OutputConnectionCheckService {
|
||||||
|
|
||||||
private var connectionAvailable: Boolean = false
|
private var connectionAvailable: Boolean = false
|
||||||
|
|
||||||
@ -55,7 +73,10 @@ class KafkaConnectionCheckService(
|
|||||||
} catch (e: TimeoutException) {
|
} catch (e: TimeoutException) {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
configsUpdateProducer.emitNext(connectionAvailable, Sinks.EmitFailureHandler.FAIL_FAST)
|
connectionCheckUpdateProducer.emitNext(
|
||||||
|
ConnectionCheckResult.KafkaConnectionCheckResult(connectionAvailable),
|
||||||
|
Sinks.EmitFailureHandler.FAIL_FAST
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun connectionAvailable(): Boolean {
|
override fun connectionAvailable(): Boolean {
|
||||||
@ -67,9 +88,9 @@ class KafkaConnectionCheckService(
|
|||||||
class RestConnectionCheckService(
|
class RestConnectionCheckService(
|
||||||
private val restTemplate: RestTemplate,
|
private val restTemplate: RestTemplate,
|
||||||
private val restTargetProperties: RestTargetProperties,
|
private val restTargetProperties: RestTargetProperties,
|
||||||
@Qualifier("configsUpdateProducer")
|
@Qualifier("connectionCheckUpdateProducer")
|
||||||
private val configsUpdateProducer: Sinks.Many<Boolean>
|
private val connectionCheckUpdateProducer: Sinks.Many<ConnectionCheckResult>
|
||||||
) : ConnectionCheckService {
|
) : OutputConnectionCheckService {
|
||||||
|
|
||||||
private var connectionAvailable: Boolean = false
|
private var connectionAvailable: Boolean = false
|
||||||
|
|
||||||
@ -84,7 +105,55 @@ class RestConnectionCheckService(
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
configsUpdateProducer.emitNext(connectionAvailable, Sinks.EmitFailureHandler.FAIL_FAST)
|
connectionCheckUpdateProducer.emitNext(
|
||||||
|
ConnectionCheckResult.RestConnectionCheckResult(connectionAvailable),
|
||||||
|
Sinks.EmitFailureHandler.FAIL_FAST
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun connectionAvailable(): Boolean {
|
||||||
|
return this.connectionAvailable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GPasConnectionCheckService(
|
||||||
|
private val restTemplate: RestTemplate,
|
||||||
|
private val gPasConfigProperties: GPasConfigProperties,
|
||||||
|
@Qualifier("connectionCheckUpdateProducer")
|
||||||
|
private val connectionCheckUpdateProducer: Sinks.Many<ConnectionCheckResult>
|
||||||
|
) : ConnectionCheckService {
|
||||||
|
|
||||||
|
private var connectionAvailable: Boolean = false
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
@Scheduled(cron = "0 * * * * *")
|
||||||
|
fun check() {
|
||||||
|
connectionAvailable = try {
|
||||||
|
val uri = UriComponentsBuilder.fromUriString(
|
||||||
|
gPasConfigProperties.uri?.replace("/\$pseudonymizeAllowCreate", "/\$pseudonymize").toString()
|
||||||
|
)
|
||||||
|
.queryParam("target", gPasConfigProperties.target)
|
||||||
|
.queryParam("original", "???")
|
||||||
|
.build().toUri()
|
||||||
|
|
||||||
|
val headers = HttpHeaders()
|
||||||
|
headers.contentType = MediaType.APPLICATION_JSON
|
||||||
|
if (!gPasConfigProperties.username.isNullOrBlank() && !gPasConfigProperties.password.isNullOrBlank()) {
|
||||||
|
headers.setBasicAuth(gPasConfigProperties.username, gPasConfigProperties.password)
|
||||||
|
}
|
||||||
|
restTemplate.exchange(
|
||||||
|
uri,
|
||||||
|
HttpMethod.GET,
|
||||||
|
HttpEntity<Void>(headers),
|
||||||
|
Void::class.java
|
||||||
|
).statusCode == HttpStatus.OK
|
||||||
|
} catch (e: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
connectionCheckUpdateProducer.emitNext(
|
||||||
|
ConnectionCheckResult.GPasConnectionCheckResult(connectionAvailable),
|
||||||
|
Sinks.EmitFailureHandler.FAIL_FAST
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun connectionAvailable(): Boolean {
|
override fun connectionAvailable(): Boolean {
|
||||||
|
@ -19,7 +19,10 @@
|
|||||||
|
|
||||||
package dev.dnpm.etl.processor.web
|
package dev.dnpm.etl.processor.web
|
||||||
|
|
||||||
|
import dev.dnpm.etl.processor.monitoring.ConnectionCheckResult
|
||||||
import dev.dnpm.etl.processor.monitoring.ConnectionCheckService
|
import dev.dnpm.etl.processor.monitoring.ConnectionCheckService
|
||||||
|
import dev.dnpm.etl.processor.monitoring.GPasConnectionCheckService
|
||||||
|
import dev.dnpm.etl.processor.monitoring.OutputConnectionCheckService
|
||||||
import dev.dnpm.etl.processor.output.MtbFileSender
|
import dev.dnpm.etl.processor.output.MtbFileSender
|
||||||
import dev.dnpm.etl.processor.pseudonym.Generator
|
import dev.dnpm.etl.processor.pseudonym.Generator
|
||||||
import dev.dnpm.etl.processor.security.Role
|
import dev.dnpm.etl.processor.security.Role
|
||||||
@ -40,22 +43,29 @@ import reactor.core.publisher.Sinks
|
|||||||
@Controller
|
@Controller
|
||||||
@RequestMapping(path = ["configs"])
|
@RequestMapping(path = ["configs"])
|
||||||
class ConfigController(
|
class ConfigController(
|
||||||
@Qualifier("configsUpdateProducer")
|
@Qualifier("connectionCheckUpdateProducer")
|
||||||
private val configsUpdateProducer: Sinks.Many<Boolean>,
|
private val connectionCheckUpdateProducer: Sinks.Many<ConnectionCheckResult>,
|
||||||
private val transformationService: TransformationService,
|
private val transformationService: TransformationService,
|
||||||
private val pseudonymGenerator: Generator,
|
private val pseudonymGenerator: Generator,
|
||||||
private val mtbFileSender: MtbFileSender,
|
private val mtbFileSender: MtbFileSender,
|
||||||
private val connectionCheckService: ConnectionCheckService,
|
private val connectionCheckServices: List<ConnectionCheckService>,
|
||||||
private val tokenService: TokenService?,
|
private val tokenService: TokenService?,
|
||||||
private val userRoleService: UserRoleService?
|
private val userRoleService: UserRoleService?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
fun index(model: Model): String {
|
fun index(model: Model): String {
|
||||||
|
val outputConnectionAvailable =
|
||||||
|
connectionCheckServices.filterIsInstance<OutputConnectionCheckService>().first().connectionAvailable()
|
||||||
|
|
||||||
|
val gPasConnectionAvailable =
|
||||||
|
connectionCheckServices.filterIsInstance<GPasConnectionCheckService>().firstOrNull()?.connectionAvailable()
|
||||||
|
|
||||||
model.addAttribute("pseudonymGenerator", pseudonymGenerator.javaClass.simpleName)
|
model.addAttribute("pseudonymGenerator", pseudonymGenerator.javaClass.simpleName)
|
||||||
model.addAttribute("mtbFileSender", mtbFileSender.javaClass.simpleName)
|
model.addAttribute("mtbFileSender", mtbFileSender.javaClass.simpleName)
|
||||||
model.addAttribute("mtbFileEndpoint", mtbFileSender.endpoint())
|
model.addAttribute("mtbFileEndpoint", mtbFileSender.endpoint())
|
||||||
model.addAttribute("connectionAvailable", connectionCheckService.connectionAvailable())
|
model.addAttribute("outputConnectionAvailable", outputConnectionAvailable)
|
||||||
|
model.addAttribute("gPasConnectionAvailable", gPasConnectionAvailable)
|
||||||
model.addAttribute("tokensEnabled", tokenService != null)
|
model.addAttribute("tokensEnabled", tokenService != null)
|
||||||
if (tokenService != null) {
|
if (tokenService != null) {
|
||||||
model.addAttribute("tokens", tokenService.findAll())
|
model.addAttribute("tokens", tokenService.findAll())
|
||||||
@ -73,11 +83,14 @@ class ConfigController(
|
|||||||
return "configs"
|
return "configs"
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(params = ["connectionAvailable"])
|
@GetMapping(params = ["outputConnectionAvailable"])
|
||||||
fun connectionAvailable(model: Model): String {
|
fun outputConnectionAvailable(model: Model): String {
|
||||||
|
val outputConnectionAvailable =
|
||||||
|
connectionCheckServices.filterIsInstance<OutputConnectionCheckService>().first().connectionAvailable()
|
||||||
|
|
||||||
model.addAttribute("mtbFileSender", mtbFileSender.javaClass.simpleName)
|
model.addAttribute("mtbFileSender", mtbFileSender.javaClass.simpleName)
|
||||||
model.addAttribute("mtbFileEndpoint", mtbFileSender.endpoint())
|
model.addAttribute("mtbFileEndpoint", mtbFileSender.endpoint())
|
||||||
model.addAttribute("connectionAvailable", connectionCheckService.connectionAvailable())
|
model.addAttribute("outputConnectionAvailable", outputConnectionAvailable)
|
||||||
if (tokenService != null) {
|
if (tokenService != null) {
|
||||||
model.addAttribute("tokensEnabled", true)
|
model.addAttribute("tokensEnabled", true)
|
||||||
model.addAttribute("tokens", tokenService.findAll())
|
model.addAttribute("tokens", tokenService.findAll())
|
||||||
@ -85,7 +98,25 @@ class ConfigController(
|
|||||||
model.addAttribute("tokens", listOf<Token>())
|
model.addAttribute("tokens", listOf<Token>())
|
||||||
}
|
}
|
||||||
|
|
||||||
return "configs/connectionAvailable"
|
return "configs/outputConnectionAvailable"
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(params = ["gPasConnectionAvailable"])
|
||||||
|
fun gPasConnectionAvailable(model: Model): String {
|
||||||
|
val gPasConnectionAvailable =
|
||||||
|
connectionCheckServices.filterIsInstance<GPasConnectionCheckService>().firstOrNull()?.connectionAvailable()
|
||||||
|
|
||||||
|
model.addAttribute("mtbFileSender", mtbFileSender.javaClass.simpleName)
|
||||||
|
model.addAttribute("mtbFileEndpoint", mtbFileSender.endpoint())
|
||||||
|
model.addAttribute("gPasConnectionAvailable", gPasConnectionAvailable)
|
||||||
|
if (tokenService != null) {
|
||||||
|
model.addAttribute("tokensEnabled", true)
|
||||||
|
model.addAttribute("tokens", tokenService.findAll())
|
||||||
|
} else {
|
||||||
|
model.addAttribute("tokens", listOf<Token>())
|
||||||
|
}
|
||||||
|
|
||||||
|
return "configs/gPasConnectionAvailable"
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(path = ["tokens"])
|
@PostMapping(path = ["tokens"])
|
||||||
@ -152,9 +183,15 @@ class ConfigController(
|
|||||||
|
|
||||||
@GetMapping(path = ["events"], produces = [MediaType.TEXT_EVENT_STREAM_VALUE])
|
@GetMapping(path = ["events"], produces = [MediaType.TEXT_EVENT_STREAM_VALUE])
|
||||||
fun events(): Flux<ServerSentEvent<Any>> {
|
fun events(): Flux<ServerSentEvent<Any>> {
|
||||||
return configsUpdateProducer.asFlux().map {
|
return connectionCheckUpdateProducer.asFlux().map {
|
||||||
|
val event = when (it) {
|
||||||
|
is ConnectionCheckResult.KafkaConnectionCheckResult -> "output-connection-check"
|
||||||
|
is ConnectionCheckResult.RestConnectionCheckResult -> "output-connection-check"
|
||||||
|
is ConnectionCheckResult.GPasConnectionCheckResult -> "gpas-connection-check"
|
||||||
|
}
|
||||||
|
|
||||||
ServerSentEvent.builder<Any>()
|
ServerSentEvent.builder<Any>()
|
||||||
.event("connection-available").id("none").data("")
|
.event(event).id("none").data(it)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,12 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section hx-ext="sse" th:sse-connect="@{/configs/events}">
|
<section hx-ext="sse" th:sse-connect="@{/configs/events}">
|
||||||
<div th:insert="~{configs/connectionAvailable.html}" th:hx-get="@{/configs?connectionAvailable}" hx-trigger="sse:connection-available">
|
<div th:insert="~{configs/gPasConnectionAvailable.html}" th:hx-get="@{/configs?gPasConnectionAvailable}" hx-trigger="sse:gpas-connection-check">
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section hx-ext="sse" th:sse-connect="@{/configs/events}">
|
||||||
|
<div th:insert="~{configs/outputConnectionAvailable.html}" th:hx-get="@{/configs?outputConnectionAvailable}" hx-trigger="sse:output-connection-check">
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
<th:block th:if="${gPasConnectionAvailable == null}">
|
||||||
|
<h2><span>🟦</span> gPAS nicht konfiguriert - Patienten-IDs werden intern anonymisiert</h2>
|
||||||
|
</th:block>
|
||||||
|
<th:block th:if="${gPasConnectionAvailable != null}">
|
||||||
|
<h2><span th:if="${gPasConnectionAvailable}">✅</span><span th:if="${not(gPasConnectionAvailable)}">⚡</span> Verbindung zu gPAS</h2>
|
||||||
|
<div>
|
||||||
|
Die Verbindung ist aktuell
|
||||||
|
<strong th:if="${gPasConnectionAvailable}" style="color: green">verfügbar.</strong>
|
||||||
|
<strong th:if="${not(gPasConnectionAvailable)}" style="color: red">nicht verfügbar.</strong>
|
||||||
|
</div>
|
||||||
|
<div class="connection-display border">
|
||||||
|
<img th:src="@{/server.png}" alt="ETL-Processor" />
|
||||||
|
<span class="connection" th:classappend="${gPasConnectionAvailable ? 'available' : ''}"></span>
|
||||||
|
<img th:src="@{/server.png}" alt="gPAS" />
|
||||||
|
<span>ETL-Processor</span>
|
||||||
|
<span></span>
|
||||||
|
<span>gPAS</span>
|
||||||
|
</div>
|
||||||
|
</th:block>
|
@ -1,12 +1,12 @@
|
|||||||
<h2><span th:if="${connectionAvailable}">✅</span><span th:if="${not(connectionAvailable)}">⚡</span> Verbindung zum bwHC-Backend</h2>
|
<h2><span th:if="${outputConnectionAvailable}">✅</span><span th:if="${not(outputConnectionAvailable)}">⚡</span> MTB-File Verbindung</h2>
|
||||||
<div>
|
<div>
|
||||||
Verbindung über <code>[[ ${mtbFileSender} ]]</code>. Die Verbindung ist aktuell
|
Verbindung über <code>[[ ${mtbFileSender} ]]</code>. Die Verbindung ist aktuell
|
||||||
<strong th:if="${connectionAvailable}" style="color: green">verfügbar.</strong>
|
<strong th:if="${outputConnectionAvailable}" style="color: green">verfügbar.</strong>
|
||||||
<strong th:if="${not(connectionAvailable)}" style="color: red">nicht verfügbar.</strong>
|
<strong th:if="${not(outputConnectionAvailable)}" style="color: red">nicht verfügbar.</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="connection-display border">
|
<div class="connection-display border">
|
||||||
<img th:src="@{/server.png}" alt="ETL-Processor" />
|
<img th:src="@{/server.png}" alt="ETL-Processor" />
|
||||||
<span class="connection" th:classappend="${connectionAvailable ? 'available' : ''}"></span>
|
<span class="connection" th:classappend="${outputConnectionAvailable ? 'available' : ''}"></span>
|
||||||
<img th:if="${mtbFileSender.startsWith('Rest')}" th:src="@{/server.png}" alt="bwHC-Backend" />
|
<img th:if="${mtbFileSender.startsWith('Rest')}" th:src="@{/server.png}" alt="bwHC-Backend" />
|
||||||
<img th:if="${mtbFileSender.startsWith('Kafka')}" th:src="@{/kafka.png}" alt="Kafka-Broker" />
|
<img th:if="${mtbFileSender.startsWith('Kafka')}" th:src="@{/kafka.png}" alt="Kafka-Broker" />
|
||||||
<span>ETL-Processor</span>
|
<span>ETL-Processor</span>
|
Loading…
x
Reference in New Issue
Block a user