Skip to content
Open
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
1 change: 1 addition & 0 deletions .nais/cpa-repo-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ spec:
- application: ebms-async
- application: ebms-provider
- application: ebms-payload
- application: emottak-monitor
outbound:
external:
- host: crl.buypass.no
Expand Down
1 change: 1 addition & 0 deletions .nais/cpa-repo-prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ spec:
- application: ebms-provider
- application: ebms-async
- application: ebms-payload
- application: emottak-monitor
outbound:
external:
- host: crl.buypassca.com
Expand Down
1 change: 1 addition & 0 deletions cpa-repo/src/main/kotlin/no/nav/emottak/cpa/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ fun cpaApplicationModule(
getCPA(cpaRepository)
getTimeStamps(cpaRepository)
getTimeStampsLatest(cpaRepository)
getTimeStampsLastUsed(cpaRepository)
getCertificate(cpaRepository)
signingCertificate(cpaRepository)
getMessagingCharacteristics(cpaRepository)
Expand Down
22 changes: 17 additions & 5 deletions cpa-repo/src/main/kotlin/no/nav/emottak/cpa/Routes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import no.nav.emottak.message.model.SignatureDetailsRequest
import no.nav.emottak.message.model.ValidationRequest
import no.nav.emottak.message.model.ValidationResult
import no.nav.emottak.util.createX509Certificate
import no.nav.emottak.util.isToday
import no.nav.emottak.util.marker
import no.nav.emottak.utils.common.model.EbmsProcessing
import no.nav.emottak.utils.environment.getEnvVar
Expand Down Expand Up @@ -146,7 +147,7 @@ fun Route.getTimeStamps(cpaRepository: CPARepository): Route = get("/cpa/timesta
log.info("Timestamps")
call.respond(
HttpStatusCode.OK,
cpaRepository.findCpaTimestamps(
cpaRepository.findTimestampsCpaUpdated(
withContext(Dispatchers.IO) {
return@withContext call.request.headers[CPA_IDS]
.let {
Expand All @@ -164,14 +165,22 @@ fun Route.getTimeStamps(cpaRepository: CPARepository): Route = get("/cpa/timesta
fun Route.getTimeStampsLatest(cpaRepository: CPARepository) = get("/cpa/timestamps/latest") {
log.info("Timestamplatest")
val latestTimestamp = withContext(Dispatchers.IO) {
cpaRepository.findLatestUpdatedCpaTimestamp()
cpaRepository.findTimestampCpaLatestUpdated()
}
when (latestTimestamp) {
null -> call.respond(HttpStatusCode.NotFound, "No timestamps found")
else -> call.respond(HttpStatusCode.OK, latestTimestamp)
}
}

fun Route.getTimeStampsLastUsed(cpaRepository: CPARepository): Route = get("/cpa/timestamps/last_used") {
log.info("Timestamps last_used")
call.respond(
HttpStatusCode.OK,
cpaRepository.findTimestampsCpaLastUsed()
)
}

fun Route.postCpa(cpaRepository: CPARepository) = post("/cpa") {
log.info("post-cpa")
val cpaString = call.receive<String>()
Expand All @@ -198,8 +207,11 @@ fun Route.validateCpa(

try {
log.info(validateRequest.marker(), "Validerer ebms mot CPA")
val cpa = cpaRepository.findCpa(validateRequest.cpaId)
?: throw NotFoundException("Fant ikke CPA (${validateRequest.cpaId})")
val (cpa, lastUsed) = cpaRepository.findCpaAndLastUsed(validateRequest.cpaId)
if (cpa == null) throw NotFoundException("Fant ikke CPA (${validateRequest.cpaId})")
if (!lastUsed.isToday() && !cpaRepository.updateCpaLastUsed(validateRequest.cpaId)) {
log.warn(validateRequest.marker(), "Feilet med å oppdatere last_used for CPA '${validateRequest.cpaId}'")
}
if (!validateRequest.isSignalMessage()) {
cpa.validate(validateRequest)
} // Delivery Failure
Expand Down Expand Up @@ -358,7 +370,7 @@ fun Routing.registerHealthEndpoints(
}
get("/internal/health/readiness") {
runCatching {
cpaRepository.findLatestUpdatedCpaTimestamp()
cpaRepository.findTimestampCpaLatestUpdated()
}.onSuccess {
call.respond(HttpStatusCode.OK, "Readiness OK")
}.onFailure {
Expand Down
27 changes: 16 additions & 11 deletions cpa-repo/src/main/kotlin/no/nav/emottak/cpa/persistence/CPA.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package no.nav.emottak.cpa.persistence

import no.nav.emottak.cpa.marshal
import no.nav.emottak.cpa.unmarshal
import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.ColumnType
import org.jetbrains.exposed.sql.Table
import org.jetbrains.exposed.sql.javatime.timestamp
import org.jetbrains.exposed.v1.core.Column
import org.jetbrains.exposed.v1.core.ColumnType
import org.jetbrains.exposed.v1.core.Table
import org.jetbrains.exposed.v1.javatime.timestamp
import org.oasis_open.committees.ebxml_cppa.schema.cpp_cpa_2_0.CollaborationProtocolAgreement

object CPA : Table("cpa") {
Expand All @@ -14,27 +14,32 @@ object CPA : Table("cpa") {
val cpa = json("cpa", CollaborationProtocolAgreement::class.java)
val updated_date = timestamp("updated_date")
val entryCreated = timestamp("create_date")
val lastUsed: Column<java.time.Instant?> = timestamp("last_used").nullable()
}

fun <T : Any> Table.json(
name: String,
clazz: Class<T>
clazz: Class<T>,
nullable: Boolean = false
): Column<T> =
registerColumn(
name = name,
type = JsonColumnType(clazz)
type = JsonColumnType(clazz, nullable)
)

class JsonColumnType<T : Any>(private val clazz: Class<T>) : ColumnType() {
override fun sqlType(): String =
"json"
class JsonColumnType<T : Any>(
private val clazz: Class<T>,
nullable: Boolean
) : ColumnType<T>(nullable) {
override fun sqlType(): String = "json"

override fun valueFromDB(value: Any): T = unmarshal(value as String, clazz)

override fun notNullValueToDB(value: Any): String = marshal(value)
override fun notNullValueToDB(value: T): String = marshal(value)

override fun valueToString(value: Any?): String =
override fun valueToString(value: T?): String =
when (value) {
null -> if (nullable) "NULL" else error("Null value for non‑nullable column")
is Iterable<*> -> notNullValueToDB(value)
else -> super.valueToString(value)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,39 +10,44 @@ import no.nav.emottak.message.ebxml.EbXMLConstants.MESSAGE_ERROR_ACTION
import no.nav.emottak.message.ebxml.PartyTypeEnum
import no.nav.emottak.message.model.ProcessConfig
import no.nav.emottak.utils.environment.isProdEnv
import org.jetbrains.exposed.sql.SortOrder
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.deleteAll
import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.upsert
import org.jetbrains.exposed.v1.core.SortOrder
import org.jetbrains.exposed.v1.core.and
import org.jetbrains.exposed.v1.core.eq
import org.jetbrains.exposed.v1.core.inList
import org.jetbrains.exposed.v1.core.isNotNull
import org.jetbrains.exposed.v1.jdbc.deleteAll
import org.jetbrains.exposed.v1.jdbc.deleteWhere
import org.jetbrains.exposed.v1.jdbc.select
import org.jetbrains.exposed.v1.jdbc.selectAll
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
import org.jetbrains.exposed.v1.jdbc.update
import org.jetbrains.exposed.v1.jdbc.upsert
import org.oasis_open.committees.ebxml_cppa.schema.cpp_cpa_2_0.CollaborationProtocolAgreement
import java.time.Instant
import java.time.temporal.ChronoUnit

class CPARepository(val database: Database) {

fun findCpa(cpaId: String): CollaborationProtocolAgreement? {
fun findCpa(cpaId: String): CollaborationProtocolAgreement? = findCpaAndLastUsed(cpaId).first

fun findCpaAndLastUsed(cpaId: String): Pair<CollaborationProtocolAgreement?, Instant?> {
if (cpaId == "nav:qass:30823" && !isProdEnv()) {
return loadOverrideCPA()
}
return transaction(db = database.db) {
val resultRow = transaction(db = database.db) {
CPA.selectAll().where {
CPA.id.eq(cpaId)
}.firstOrNull()?.get(
CPA.cpa
)
}.firstOrNull()
}
return Pair(resultRow?.get(CPA.cpa), resultRow?.get(CPA.lastUsed))
}

fun loadOverrideCPA(): CollaborationProtocolAgreement {
private fun loadOverrideCPA(): Pair<CollaborationProtocolAgreement, Instant> {
val cpaString = String(object {}::class.java.classLoader.getResource("cpa/nav_qass_30823_modified.xml").readBytes())
return xmlMarshaller.unmarshal(cpaString, CollaborationProtocolAgreement::class.java)
return Pair(xmlMarshaller.unmarshal(cpaString, CollaborationProtocolAgreement::class.java), Instant.now())
}

fun findCpaTimestamps(idList: List<String>): Map<String, String> {
fun findTimestampsCpaUpdated(idList: List<String>): Map<String, String> {
return transaction(db = database.db) {
if (idList.isNotEmpty()) {
CPA.select(CPA.id, CPA.updated_date).where { CPA.id inList idList }
Expand All @@ -54,7 +59,7 @@ class CPARepository(val database: Database) {
}
}

fun findLatestUpdatedCpaTimestamp(): String? {
fun findTimestampCpaLatestUpdated(): String? {
return transaction(db = database.db) {
CPA.select(CPA.id, CPA.updated_date)
.where { CPA.updated_date.isNotNull() }
Expand All @@ -73,20 +78,26 @@ class CPARepository(val database: Database) {
it[CPA.cpa],
it[CPA.updated_date],
it[CPA.entryCreated],
it[CPA.herId]
it[CPA.herId],
it[CPA.lastUsed]
)
}
}
}

fun updateOrInsert(cpa: CpaDbEntry): String {
transaction(database.db) {
CPA.upsert(CPA.id) {
cpa.cpa ?: throw IllegalArgumentException("Kan ikke sette null verdi for CPA i DB")
CPA.upsert(
CPA.id,
onUpdateExclude = listOf(CPA.lastUsed)
) {
it[id] = cpa.id
it[CPA.cpa] = cpa.cpa ?: throw IllegalArgumentException("Kan ikke sette null verdi for CPA i DB")
it[CPA.cpa] = cpa.cpa
it[entryCreated] = cpa.createdDate
it[updated_date] = cpa.updatedDate
it[herId] = cpa.herId
it[lastUsed] = null
}
}
return cpa.id
Expand Down Expand Up @@ -157,19 +168,44 @@ class CPARepository(val database: Database) {
}
}

fun updateCpaLastUsed(cpaId: String): Boolean {
if (cpaId == "nav:qass:30823" && !isProdEnv()) {
return true
}
return 1 == transaction(database.db) {
CPA.update({
CPA.id eq cpaId
}) {
it[lastUsed] = Instant.now().truncatedTo(ChronoUnit.SECONDS)
}
}
}

fun findTimestampsCpaLastUsed(): Map<String, String?> {
return transaction(db = database.db) {
CPA.select(CPA.id, CPA.lastUsed)
.orderBy(CPA.id, SortOrder.ASC)
.associate {
it[CPA.id] to it[CPA.lastUsed]?.toString()
}
}
}

data class CpaDbEntry(
val id: String,
val cpa: CollaborationProtocolAgreement? = null,
val updatedDate: Instant,
val createdDate: Instant,
val herId: String?
val herId: String?,
val lastUsed: Instant?
) {
constructor(cpa: CollaborationProtocolAgreement, updatedDateString: String?) : this(
id = cpa.cpaid,
cpa = cpa,
updatedDate = parseOrDefault(updatedDateString),
createdDate = Instant.now().truncatedTo(ChronoUnit.SECONDS),
herId = cpa.getPartnerPartyIdByType(PartyTypeEnum.HER)?.value
herId = cpa.getPartnerPartyIdByType(PartyTypeEnum.HER)?.value,
lastUsed = null
)

companion object {
Expand All @@ -182,11 +218,4 @@ class CPARepository(val database: Database) {
}
}
}

// @Serializable
// data class TimestampResponse(
// val idMap: Map<String, String>
// )

// fun List<Pair<>>.toTimestampResponse() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import no.nav.emottak.utils.environment.getEnvVar
import org.flywaydb.core.Flyway
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.v1.jdbc.Database

class Database(
dbConfig: HikariConfig
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package no.nav.emottak.cpa.persistence

import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.Table
import org.jetbrains.exposed.v1.core.Column
import org.jetbrains.exposed.v1.core.Table

object ProcessConfigTable : Table("process_config") {
val role: Column<String> = varchar("role", 50)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package no.nav.emottak.cpa.persistence.gammel

import org.jetbrains.exposed.sql.Table
import org.jetbrains.exposed.v1.core.Table

object PARTNER : Table("PARTNER") {
val partnerId = ulong("PARTNER_ID")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package no.nav.emottak.cpa.persistence.gammel
import no.nav.emottak.cpa.feil.MultiplePartnerException
import no.nav.emottak.cpa.feil.PartnerNotFoundException
import no.nav.emottak.cpa.persistence.Database
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.v1.core.eq
import org.jetbrains.exposed.v1.jdbc.selectAll
import org.jetbrains.exposed.v1.jdbc.transactions.transaction

class PartnerRepository(val database: Database) {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE cpa ADD last_used timestamp;
Loading
Loading