mirror of
https://github.com/pcvolkmer/onco-analytics-monitor.git
synced 2025-04-19 19:16:52 +00:00
refactor: put FHIR data extraction into abstract class
This commit is contained in:
parent
64818ab7b0
commit
48677250b4
@ -0,0 +1,44 @@
|
||||
package dev.pcvolkmer.oncoanalytics.monitor.topiclisteners
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext
|
||||
import dev.pcvolkmer.oncoanalytics.monitor.conditions.Condition
|
||||
import dev.pcvolkmer.oncoanalytics.monitor.conditions.ConditionId
|
||||
import dev.pcvolkmer.oncoanalytics.monitor.conditions.Statistics
|
||||
import org.hl7.fhir.r4.model.Bundle
|
||||
import reactor.core.publisher.Sinks
|
||||
|
||||
/**
|
||||
* Abstract class with common methods for FHIR TopicMonitors
|
||||
*
|
||||
* @property statisticsEventProducer The event producer/sink to notify about saved condition
|
||||
*
|
||||
* @author Paul-Christian Volkmer
|
||||
* @since 0.1.0
|
||||
*/
|
||||
abstract class AbstractFhirTopicMonitor(statisticsEventProducer: Sinks.Many<Statistics>) :
|
||||
AbstractTopicMonitor(statisticsEventProducer) {
|
||||
|
||||
private val fhirContext = FhirContext.forR4()
|
||||
|
||||
/**
|
||||
* Handle parsable FHIR resource
|
||||
*
|
||||
* @param payload The string representation of the FHIR resource
|
||||
* @param handler The handler function to define what to do if payload contains usable FHIR condition
|
||||
*/
|
||||
fun handleUsableFhirPayload(payload: String, handler: (condition: Condition) -> Unit) {
|
||||
val bundle = fhirContext.newJsonParser().parseResource(Bundle::class.java, payload)
|
||||
val firstEntry = bundle.entry.firstOrNull() ?: return
|
||||
|
||||
if (firstEntry.resource.fhirType() == "Condition") {
|
||||
val condition = firstEntry.resource as org.hl7.fhir.r4.model.Condition
|
||||
handler(
|
||||
Condition(
|
||||
ConditionId(condition.id),
|
||||
condition.code.coding.first { "http://fhir.de/CodeSystem/bfarm/icd-10-gm" == it.system }.code
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package dev.pcvolkmer.oncoanalytics.monitor.topiclisteners
|
||||
|
||||
import dev.pcvolkmer.oncoanalytics.monitor.conditions.Statistics
|
||||
import org.apache.kafka.common.TopicPartition
|
||||
import org.springframework.kafka.listener.ConsumerSeekAware
|
||||
import org.springframework.kafka.listener.ConsumerSeekAware.ConsumerSeekCallback
|
||||
import reactor.core.publisher.Sinks
|
||||
|
||||
/**
|
||||
* Abstract class with common methods for all TopicMonitors
|
||||
*
|
||||
* This implements ConsumerSeekAware to seek any topic to the beginning and load all available topic records from start.
|
||||
*
|
||||
* @property statisticsEventProducer The event producer/sink to notify about saved condition
|
||||
*
|
||||
* @author Paul-Christian Volkmer
|
||||
* @since 0.1.0
|
||||
*
|
||||
* @see ConsumerSeekAware
|
||||
*/
|
||||
abstract class AbstractTopicMonitor(private val statisticsEventProducer: Sinks.Many<Statistics>) : TopicMonitor,
|
||||
ConsumerSeekAware {
|
||||
|
||||
/**
|
||||
* This will send new/updated statistics
|
||||
*
|
||||
* @param statistics The statistics to be sent/updated
|
||||
*/
|
||||
fun sendUpdatedStatistics(statistics: Statistics) {
|
||||
statisticsEventProducer.emitNext(statistics) { _, _ -> false }
|
||||
}
|
||||
|
||||
/**
|
||||
* This will seek assigned Kafka Partitions back to the beginning for all inheriting classes
|
||||
*/
|
||||
override fun onPartitionsAssigned(assignments: MutableMap<TopicPartition, Long>, callback: ConsumerSeekCallback) {
|
||||
callback.seekToBeginning(assignments.keys)
|
||||
}
|
||||
|
||||
}
|
@ -1,12 +1,8 @@
|
||||
package dev.pcvolkmer.oncoanalytics.monitor.topiclisteners
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext
|
||||
import dev.pcvolkmer.oncoanalytics.monitor.StatisticsSink
|
||||
import dev.pcvolkmer.oncoanalytics.monitor.conditions.Condition
|
||||
import dev.pcvolkmer.oncoanalytics.monitor.conditions.ConditionId
|
||||
import dev.pcvolkmer.oncoanalytics.monitor.conditions.ConditionRepository
|
||||
import dev.pcvolkmer.oncoanalytics.monitor.fetchStatistics
|
||||
import org.hl7.fhir.r4.model.Bundle
|
||||
import org.springframework.beans.factory.annotation.Qualifier
|
||||
import org.springframework.kafka.annotation.KafkaListener
|
||||
import org.springframework.kafka.support.KafkaHeaders
|
||||
@ -14,12 +10,20 @@ import org.springframework.messaging.handler.annotation.Header
|
||||
import org.springframework.messaging.handler.annotation.Payload
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
/**
|
||||
* FHIR TopicMonitor to listen to Kafka Topics matching 'fhir.obds.Condition.*'
|
||||
*
|
||||
* @property statisticsEventProducer The event producer/sink to notify about saved condition
|
||||
*
|
||||
* @author Paul-Christian Volkmer
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Component
|
||||
class FhirObdsTopicMonitor(
|
||||
@Qualifier("fhirObdsConditionRepository")
|
||||
private val conditionRepository: ConditionRepository,
|
||||
statisticsEventProducer: StatisticsSink,
|
||||
) : TopicMonitor(statisticsEventProducer) {
|
||||
) : AbstractFhirTopicMonitor(statisticsEventProducer) {
|
||||
|
||||
@KafkaListener(topicPattern = "fhir.obds.Condition.*")
|
||||
override fun handleTopicRecord(
|
||||
@ -29,22 +33,8 @@ class FhirObdsTopicMonitor(
|
||||
@Payload payload: String,
|
||||
) {
|
||||
try {
|
||||
val ctx = FhirContext.forR4()
|
||||
val parser = ctx.newJsonParser()
|
||||
|
||||
val bundle = parser.parseResource(Bundle::class.java, payload)
|
||||
val firstEntry = bundle.entry.firstOrNull() ?: return
|
||||
|
||||
if (firstEntry.resource.fhirType() == "Condition") {
|
||||
val condition = firstEntry.resource as org.hl7.fhir.r4.model.Condition
|
||||
val updated = conditionRepository.save(
|
||||
Condition(
|
||||
ConditionId(condition.id),
|
||||
condition.code.coding.first { "http://fhir.de/CodeSystem/bfarm/icd-10-gm" == it.system }.code
|
||||
)
|
||||
)
|
||||
|
||||
if (updated) {
|
||||
this.handleUsableFhirPayload(payload) { condition ->
|
||||
if (conditionRepository.save(condition)) {
|
||||
sendUpdatedStatistics(fetchStatistics("fhirobds", conditionRepository))
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,8 @@
|
||||
package dev.pcvolkmer.oncoanalytics.monitor.topiclisteners
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext
|
||||
import dev.pcvolkmer.oncoanalytics.monitor.StatisticsSink
|
||||
import dev.pcvolkmer.oncoanalytics.monitor.conditions.Condition
|
||||
import dev.pcvolkmer.oncoanalytics.monitor.conditions.ConditionId
|
||||
import dev.pcvolkmer.oncoanalytics.monitor.conditions.ConditionRepository
|
||||
import dev.pcvolkmer.oncoanalytics.monitor.fetchStatistics
|
||||
import org.hl7.fhir.r4.model.Bundle
|
||||
import org.springframework.beans.factory.annotation.Qualifier
|
||||
import org.springframework.kafka.annotation.KafkaListener
|
||||
import org.springframework.kafka.support.KafkaHeaders
|
||||
@ -14,12 +10,20 @@ import org.springframework.messaging.handler.annotation.Header
|
||||
import org.springframework.messaging.handler.annotation.Payload
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
/**
|
||||
* FHIR TopicMonitor to listen to Kafka Topics matching 'fhir.pseudonymized.*'
|
||||
*
|
||||
* @property statisticsEventProducer The event producer/sink to notify about saved condition
|
||||
*
|
||||
* @author Paul-Christian Volkmer
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Component
|
||||
class FhirPseudonymizedTopicMonitor(
|
||||
@Qualifier("fhirPseudonymizedConditionRepository")
|
||||
private val conditionRepository: ConditionRepository,
|
||||
statisticsEventProducer: StatisticsSink,
|
||||
) : TopicMonitor(statisticsEventProducer) {
|
||||
) : AbstractFhirTopicMonitor(statisticsEventProducer) {
|
||||
|
||||
@KafkaListener(topicPattern = "fhir.pseudonymized.*")
|
||||
override fun handleTopicRecord(
|
||||
@ -29,22 +33,8 @@ class FhirPseudonymizedTopicMonitor(
|
||||
@Payload payload: String,
|
||||
) {
|
||||
try {
|
||||
val ctx = FhirContext.forR4()
|
||||
val parser = ctx.newJsonParser()
|
||||
|
||||
val bundle = parser.parseResource(Bundle::class.java, payload)
|
||||
val firstEntry = bundle.entry.firstOrNull() ?: return
|
||||
|
||||
if (firstEntry.resource.fhirType() == "Condition") {
|
||||
val condition = firstEntry.resource as org.hl7.fhir.r4.model.Condition
|
||||
val updated = conditionRepository.save(
|
||||
Condition(
|
||||
ConditionId(condition.id),
|
||||
condition.code.coding.first { "http://fhir.de/CodeSystem/bfarm/icd-10-gm" == it.system }.code
|
||||
)
|
||||
)
|
||||
|
||||
if (updated) {
|
||||
this.handleUsableFhirPayload(payload) { condition ->
|
||||
if (conditionRepository.save(condition)) {
|
||||
sendUpdatedStatistics(fetchStatistics("fhirpseudonymized", conditionRepository))
|
||||
}
|
||||
}
|
||||
|
@ -19,13 +19,21 @@ import org.xml.sax.InputSource
|
||||
import java.io.StringReader
|
||||
import javax.xml.xpath.XPathFactory
|
||||
|
||||
/**
|
||||
* oBDS TopicMonitor to listen to Kafka Topics matching 'onkostar.MELDUNG_EXPORT.*'
|
||||
*
|
||||
* @property statisticsEventProducer The event producer/sink to notify about saved condition
|
||||
*
|
||||
* @author Paul-Christian Volkmer
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Component
|
||||
class ObdsXmlTopicMonitor(
|
||||
@Qualifier("obdsXmlConditionRepository")
|
||||
private val conditionRepository: ConditionRepository,
|
||||
private val objectMapper: ObjectMapper,
|
||||
statisticsEventProducer: StatisticsSink,
|
||||
) : TopicMonitor(statisticsEventProducer) {
|
||||
) : AbstractTopicMonitor(statisticsEventProducer) {
|
||||
|
||||
@KafkaListener(topicPattern = "onkostar.MELDUNG_EXPORT.*")
|
||||
override fun handleTopicRecord(
|
||||
|
@ -1,21 +1,19 @@
|
||||
package dev.pcvolkmer.oncoanalytics.monitor.topiclisteners
|
||||
|
||||
import dev.pcvolkmer.oncoanalytics.monitor.conditions.Statistics
|
||||
import org.apache.kafka.common.TopicPartition
|
||||
import org.springframework.kafka.listener.ConsumerSeekAware
|
||||
import org.springframework.kafka.listener.ConsumerSeekAware.ConsumerSeekCallback
|
||||
import reactor.core.publisher.Sinks
|
||||
|
||||
abstract class TopicMonitor(private val statisticsEventProducer: Sinks.Many<Statistics>) : ConsumerSeekAware {
|
||||
|
||||
abstract fun handleTopicRecord(topic: String, timestamp: Long, key: String, payload: String)
|
||||
|
||||
fun sendUpdatedStatistics(statistics: Statistics) {
|
||||
statisticsEventProducer.emitNext(statistics) { _, _ -> false }
|
||||
}
|
||||
|
||||
override fun onPartitionsAssigned(assignments: MutableMap<TopicPartition, Long>, callback: ConsumerSeekCallback) {
|
||||
callback.seekToBeginning(assignments.keys)
|
||||
}
|
||||
|
||||
/**
|
||||
* TopicMonitor to listen to Kafka Topics
|
||||
*
|
||||
* @author Paul-Christian Volkmer
|
||||
* @since 0.1.0
|
||||
*/
|
||||
interface TopicMonitor {
|
||||
/**
|
||||
* Handle incoming Kafka Record
|
||||
*
|
||||
* @param topic The exact name of the topic
|
||||
* @param timestamp The timestamp the record has been published
|
||||
* @param key The records key
|
||||
* @param payload The records payload
|
||||
*/
|
||||
fun handleTopicRecord(topic: String, timestamp: Long, key: String, payload: String)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user