Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions ebms-provider/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ tasks {
}
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().all {
compilerOptions {
freeCompilerArgs = listOf("-opt-in=kotlin.uuid.ExperimentalUuidApi")
}
}

dependencies {
implementation(project(":felles"))
implementation(project(":ebxml-processing-model"))
Expand Down
11 changes: 7 additions & 4 deletions ebms-provider/src/main/kotlin/no/nav/emottak/ebms/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import kotlinx.coroutines.awaitCancellation
import no.nav.emottak.ebms.configuration.config
import no.nav.emottak.ebms.processing.ProcessingService
import no.nav.emottak.ebms.sendin.SendInService
import no.nav.emottak.ebms.util.EventRegistrationService
import no.nav.emottak.ebms.util.EventRegistrationServiceImpl
import no.nav.emottak.ebms.validation.DokumentValidator
import no.nav.emottak.utils.kafka.client.EventPublisherClient
import no.nav.emottak.utils.kafka.service.EventLoggingService
Expand All @@ -38,7 +40,8 @@ fun main() = SuspendApp {
val sendInService = SendInService(sendInClient)

val kafkaPublisherClient = EventPublisherClient(config().kafka)
val eventLoggingService = EventLoggingService(kafkaPublisherClient)
val eventLoggingService = EventLoggingService(config().eventLogging, kafkaPublisherClient)
val eventRegistrationService = EventRegistrationServiceImpl(eventLoggingService)

result {
resourceScope {
Expand All @@ -50,7 +53,7 @@ fun main() = SuspendApp {
dokumentValidator,
processingService,
sendInService,
eventLoggingService
eventRegistrationService
)
}
).also { it.engineConfig.maxChunkSize = 100000 }
Expand All @@ -70,7 +73,7 @@ fun Application.ebmsProviderModule(
validator: DokumentValidator,
processing: ProcessingService,
sendInService: SendInService,
eventLoggingService: EventLoggingService
eventRegistrationService: EventRegistrationService
) {
val appMicrometerRegistry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT)

Expand All @@ -84,6 +87,6 @@ fun Application.ebmsProviderModule(
registerPrometheusEndpoint(appMicrometerRegistry)
registerNavCheckStatus()

postEbmsSync(validator, processing, sendInService, eventLoggingService)
postEbmsSync(validator, processing, sendInService, eventRegistrationService)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import no.nav.emottak.message.xml.getDocumentBuilder
import java.io.ByteArrayInputStream
import java.nio.charset.StandardCharsets
import java.util.Base64
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid

fun PartData.payload(clearText: Boolean = false): ByteArray {
Expand Down Expand Up @@ -70,7 +69,6 @@ fun Headers.actuallyUsefulToString(): String {
return sb.toString()
}

@OptIn(ExperimentalUuidApi::class)
@Throws(MimeValidationException::class)
suspend fun ApplicationCall.receiveEbmsDokument(): EbMSDocument {
log.info("Parsing message with Message-Id: ${request.header(SMTPHeaders.MESSAGE_ID)}")
Expand Down
47 changes: 8 additions & 39 deletions ebms-provider/src/main/kotlin/no/nav/emottak/ebms/Routes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import no.nav.emottak.constants.SMTPHeaders
import no.nav.emottak.ebms.model.signer
import no.nav.emottak.ebms.processing.ProcessingService
import no.nav.emottak.ebms.sendin.SendInService
import no.nav.emottak.ebms.util.EventRegistrationService
import no.nav.emottak.ebms.util.marker
import no.nav.emottak.ebms.validation.DokumentValidator
import no.nav.emottak.ebms.validation.MimeValidationException
Expand All @@ -24,20 +25,15 @@ import no.nav.emottak.message.model.PayloadProcessing
import no.nav.emottak.message.model.SignatureDetails
import no.nav.emottak.util.marker
import no.nav.emottak.util.retrieveLoggableHeaderPairs
import no.nav.emottak.utils.common.parseOrGenerateUuid
import no.nav.emottak.utils.kafka.model.Event
import no.nav.emottak.utils.kafka.model.EventType
import no.nav.emottak.utils.kafka.service.EventLoggingService
import no.nav.emottak.utils.serialization.toEventDataJson
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid

@OptIn(ExperimentalUuidApi::class)
fun Route.postEbmsSync(
validator: DokumentValidator,
processingService: ProcessingService,
sendInService: SendInService,
eventLoggingService: EventLoggingService
eventRegistrationService: EventRegistrationService
): Route = post("/ebms/sync") {
log.info("Receiving synchronous request")

Expand All @@ -47,7 +43,9 @@ fun Route.postEbmsSync(
call.request.validateMime()
ebMSDocument = call.receiveEbmsDokument()
log.info(ebMSDocument.messageHeader().marker(loggableHeaders), "Melding mottatt")
eventLoggingService.registerEvent(

eventRegistrationService.registerEventMessageDetails(ebMSDocument)
eventRegistrationService.registerEvent(
EventType.MESSAGE_RECEIVED_VIA_HTTP,
ebMSDocument
)
Expand Down Expand Up @@ -119,7 +117,7 @@ fun Route.postEbmsSync(
}
)
log.info(it.first.marker(), "Melding ferdig behandlet og svar returnert")
eventLoggingService.registerEvent(
eventRegistrationService.registerEvent(
EventType.MESSAGE_SENT_VIA_HTTP,
it.first.toEbmsDokument()
)
Expand All @@ -133,7 +131,7 @@ fun Route.postEbmsSync(
}
log.info(ebmsMessage.marker(), "Created MessageError response")

eventLoggingService.registerEvent(
eventRegistrationService.registerEvent(
EventType.ERROR_WHILE_SENDING_MESSAGE_VIA_HTTP,
ebMSDocument,
ebmsException.toEventDataJson()
Expand All @@ -145,7 +143,7 @@ fun Route.postEbmsSync(
} catch (ex: Exception) {
log.error(ebmsMessage.marker(), "Unknown error during message processing: ${ex.message}", ex)

eventLoggingService.registerEvent(
eventRegistrationService.registerEvent(
EventType.ERROR_WHILE_SENDING_MESSAGE_VIA_HTTP,
ebMSDocument,
ex.toEventDataJson()
Expand All @@ -157,32 +155,3 @@ fun Route.postEbmsSync(
)
}
}

@OptIn(ExperimentalUuidApi::class)
suspend fun EventLoggingService.registerEvent(
eventType: EventType,
ebMSDocument: EbMSDocument,
eventData: String = ""
) {
log.debug("Event reg. test: Registering event for requestId: ${ebMSDocument.requestId}")

try {
val requestId = ebMSDocument.requestId.parseOrGenerateUuid()

log.debug("Event reg. test: RequestId: $requestId")

val event = Event(
eventType = eventType,
requestId = requestId,
contentId = "",
messageId = ebMSDocument.transform().messageId,
eventData = eventData
)

log.debug("Event reg. test: Publishing event: $event")
this.logEvent(event)
log.debug("Event reg. test: Event published successfully")
} catch (e: Exception) {
log.error("Event reg. test: Error while registering event: ${e.message}", e)
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package no.nav.emottak.ebms.configuration

import no.nav.emottak.utils.config.EventLogging
import no.nav.emottak.utils.config.Kafka

data class Config(
val kafka: Kafka,
val eventLogging: EventLogging,
val kafkaSignalReceiver: KafkaSignalReceiver,
val kafkaSignalProducer: KafkaSignalProducer,
val kafkaPayloadReceiver: KafkaPayloadReceiver,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package no.nav.emottak.ebms.util

import no.nav.emottak.ebms.log
import no.nav.emottak.message.model.EbMSDocument
import no.nav.emottak.message.model.PartyId
import no.nav.emottak.utils.common.parseOrGenerateUuid
import no.nav.emottak.utils.kafka.model.EbmsMessageDetails
import no.nav.emottak.utils.kafka.model.Event
import no.nav.emottak.utils.kafka.model.EventType
import no.nav.emottak.utils.kafka.service.EventLoggingService

interface EventRegistrationService {
suspend fun registerEvent(
eventType: EventType,
ebMSDocument: EbMSDocument,
eventData: String = "{}"
)

suspend fun registerEventMessageDetails(ebMSDocument: EbMSDocument)

companion object {
fun serializePartyId(partyIDs: List<PartyId>): String {
val partyId = partyIDs.firstOrNull { it.type == "orgnummer" }
?: partyIDs.firstOrNull { it.type == "HER" }
?: partyIDs.firstOrNull { it.type == "ENH" }
?: partyIDs.first()

return "${partyId.type}:${partyId.value}"
}
}
}

class EventRegistrationServiceImpl(
private val eventLoggingService: EventLoggingService
) : EventRegistrationService {
override suspend fun registerEvent(
eventType: EventType,
ebMSDocument: EbMSDocument,
eventData: String
) {
log.debug("Registering event for requestId: ${ebMSDocument.requestId}")

try {
val requestId = ebMSDocument.requestId.parseOrGenerateUuid()

val event = Event(
eventType = eventType,
requestId = requestId,
contentId = "",
messageId = ebMSDocument.transform().messageId,
eventData = eventData
)
log.debug("Event reg. test: Publishing event: $event")

eventLoggingService.logEvent(event)
log.debug("Event reg. test: Event published successfully")
} catch (e: Exception) {
log.error("Event reg. test: Error while registering event: ${e.message}", e)
}
}

override suspend fun registerEventMessageDetails(ebMSDocument: EbMSDocument) {
log.debug("Registering message with requestId: ${ebMSDocument.requestId}")

try {
val ebmsMessage = ebMSDocument.transform()
val requestId = ebmsMessage.requestId.parseOrGenerateUuid()

val ebmsMessageDetails = EbmsMessageDetails(
requestId = requestId,
cpaId = ebmsMessage.cpaId,
conversationId = ebmsMessage.conversationId,
messageId = ebmsMessage.messageId,
refToMessageId = ebmsMessage.refToMessageId,
fromPartyId = EventRegistrationService.serializePartyId(ebmsMessage.addressing.from.partyId),
fromRole = ebmsMessage.addressing.from.role,
toPartyId = EventRegistrationService.serializePartyId(ebmsMessage.addressing.to.partyId),
toRole = ebmsMessage.addressing.to.role,
service = ebmsMessage.addressing.service,
action = ebmsMessage.addressing.action,
refParam = null,
sender = null,
sentAt = ebmsMessage.sentAt
)
log.debug("Publishing message details: $ebmsMessageDetails")

eventLoggingService.logMessageDetails(ebmsMessageDetails)
log.debug("Message details published successfully")
} catch (e: Exception) {
log.error("Error while registering message details: ${e.message}", e)
}
}
}

class EventRegistrationServiceFake : EventRegistrationService {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Litt nitpicky, men navngivningen bør være FakeEventRegistrationService.

Her kan du også implementere dette som en funksjon som beskrevet ovenfor. Du får da:

fakeEventRegistrationService( ... )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hvordan er FakeEventRegistrationService bedre enn EventRegistrationServiceFake ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MyService, FooService, BarService er jo typisk et pattern vi vil følge.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hvorfor har vi slike viljer?
Det siste gang jeg spurte, så hadde teamet vårt ingen kodestandard.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hva mener du ? Dette er helt STANDARD navngivning.

Copy link
Contributor Author

@OleksandrChmyrNAV OleksandrChmyrNAV May 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hver gang når jeg prøvde å bruke noe standard i eMottak, så fikk jeg avslag og flere klager fordi
vi eksperimenterer og ingenting er skrevet på stein
Jeg prøver å forstå hvorfor det ble plutselig ikke lov til å eksperimentere med navngivelse?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kort fortalt så ser det litt rart ut. Hvis det hadde vært konsistent, dvs ALLE service-implementasjoner hadde blitt post-fixet med implementasjon, ala: MyServiceFoo, MyServiceBar, MyServiceFake hadde det hvertfall vært gjennomført og konsistent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Og det er akkurat slik akkurat nå.
EventRegistrationServiceImpl og EventRegistrationServiceFake er de eneste service-implementasjoner i hele prosjektet (kanskje i hele eMottak også) resten av services er vanlige klasser uten den interface overengineering som bare forstyrer smidighet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Det ser fortsatt rart ut og EventRegistrationServiceFake leser ikke noe godt, imho. Det er hvertfall ukonvensjonell måte å navngi på. Jeg skal ikke blokke PR'en pga av dette, men min personlige preferanse er at du hadde implementert interfacet via en funksjon slik jeg foreslo. Da hadde du også sluppet unna med denne redundante bruken av Impl i klassenavnet og brukt elegante features i Kotlin. For meg føles dette veldig Java'ish ut.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Takk for at du er konstruktiv! 🙌

override suspend fun registerEvent(
eventType: EventType,
ebMSDocument: EbMSDocument,
eventData: String
) {
log.debug("Registering event $eventType for ebMSDocument: $ebMSDocument and eventData: $eventData")
}

override suspend fun registerEventMessageDetails(ebMSDocument: EbMSDocument) {
log.debug("Registering message details for ebMSDocument: $ebMSDocument")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import io.mockk.coVerify
import io.mockk.mockk
import no.nav.emottak.ebms.processing.ProcessingService
import no.nav.emottak.ebms.sendin.SendInService
import no.nav.emottak.ebms.util.EventRegistrationServiceFake
import no.nav.emottak.ebms.validation.DokumentValidator
import no.nav.emottak.ebms.validation.MimeHeaders
import no.nav.emottak.message.ebxml.errorList
Expand All @@ -27,7 +28,6 @@ import no.nav.emottak.message.model.ValidationResult
import no.nav.emottak.message.xml.xmlMarshaller
import no.nav.emottak.util.decodeBase64
import no.nav.emottak.utils.environment.getEnvVar
import no.nav.emottak.utils.kafka.service.EventLoggingService
import org.apache.xml.security.algorithms.MessageDigestAlgorithm
import org.apache.xml.security.signature.XMLSignature
import org.junit.jupiter.api.Assertions
Expand All @@ -39,7 +39,7 @@ abstract class EbmsRoutFellesIT(val endpoint: String) {

val validMultipartRequest = validMultipartRequest()
val processingService = mockk<ProcessingService>()
val eventLoggingService = mockk<EventLoggingService>()
val eventRegistrationService = EventRegistrationServiceFake()
val mockProcessConfig = ProcessConfig(
true,
true,
Expand Down Expand Up @@ -69,7 +69,7 @@ abstract class EbmsRoutFellesIT(val endpoint: String) {
}

routing {
postEbmsSync(dokumentValidator, processingService, SendInService(sendInClient), eventLoggingService)
postEbmsSync(dokumentValidator, processingService, SendInService(sendInClient), eventRegistrationService)
}
}
externalServices {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,10 @@ import no.nav.emottak.utils.environment.getEnvVar
import org.apache.xml.security.algorithms.MessageDigestAlgorithm
import org.apache.xml.security.signature.XMLSignature
import org.junit.jupiter.api.Test
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid

private const val SYNC_PATH = "/ebms/sync"

@OptIn(ExperimentalUuidApi::class)
class EbmsRouteSyncIT : EbmsRoutFellesIT(SYNC_PATH) {

fun <T> testSyncApp(testBlock: suspend ApplicationTestBuilder.() -> T) = testApplication {
Expand All @@ -69,7 +67,7 @@ class EbmsRouteSyncIT : EbmsRoutFellesIT(SYNC_PATH) {
incomingMessage
}
routing {
postEbmsSync(dokumentValidator, processingService, SendInService(sendInClient), eventLoggingService)
postEbmsSync(dokumentValidator, processingService, SendInService(sendInClient), eventRegistrationService)
}
}
externalServices {
Expand Down Expand Up @@ -131,7 +129,6 @@ class EbmsRouteSyncIT : EbmsRoutFellesIT(SYNC_PATH) {
testBlock()
}

@OptIn(ExperimentalUuidApi::class)
@Test
fun `Valid payload request should trigger processing and validation on way out`() = testSyncApp {
mockkStatic(EbMSDocument::signer)
Expand All @@ -149,7 +146,6 @@ class EbmsRouteSyncIT : EbmsRoutFellesIT(SYNC_PATH) {
println("----=_Part_" + Uuid.random().toString())
}

@OptIn(ExperimentalUuidApi::class)
@Test
fun `Feilmelding fra fagsystemet må propageres til brukeren`() = testSyncApp {
val soapFault = "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Header/><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>Noe gikk galt i fagsystemet</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>"
Expand Down
Loading