Skip to content
Draft
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
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package com.simprints.feature.clientapi.usecases

import com.fasterxml.jackson.databind.module.SimpleModule
import com.simprints.core.domain.tokenization.TokenizableString
import com.simprints.core.domain.tokenization.serialization.TokenizationClassNameDeserializer
import com.simprints.core.domain.tokenization.serialization.TokenizationClassNameSerializer
import com.simprints.core.tools.json.JsonHelper
import com.simprints.core.tools.utils.EncodingUtils
import com.simprints.infra.config.store.models.canCoSyncAllData
Expand All @@ -12,7 +9,11 @@ import com.simprints.infra.config.sync.ConfigManager
import com.simprints.infra.enrolment.records.repository.EnrolmentRecordRepository
import com.simprints.infra.enrolment.records.repository.domain.models.Subject
import com.simprints.infra.enrolment.records.repository.domain.models.SubjectQuery
import com.simprints.infra.events.event.cosync.CoSyncEnrolmentRecordEvents
import com.simprints.infra.events.event.domain.models.subject.EnrolmentRecordEvents
import com.simprints.infra.events.event.cosync.v1.TokenizableStringV1
import com.simprints.infra.events.event.cosync.v1.TokenizableStringV1Deserializer
import com.simprints.infra.events.event.cosync.v1.TokenizableStringV1Serializer
import com.simprints.infra.events.event.cosync.v1.toCoSyncV1
import com.simprints.infra.events.event.domain.models.subject.EnrolmentRecordCreationEvent
import com.simprints.infra.logging.Simber
import javax.inject.Inject
Expand Down Expand Up @@ -46,7 +47,9 @@ internal class GetEnrolmentCreationEventForSubjectUseCase @Inject constructor(
return null
}

return jsonHelper.toJson(CoSyncEnrolmentRecordEvents(listOf(recordCreationEvent)), coSyncSerializationModule)
// Convert to V1 external schema before serialization for stable contract
val v1Events = EnrolmentRecordEvents(listOf(recordCreationEvent)).toCoSyncV1()
return jsonHelper.toJson(v1Events, coSyncSerializationModule)
}

private fun Subject.fromSubjectToEnrolmentCreationEvent() = EnrolmentRecordCreationEvent(
Expand All @@ -60,8 +63,8 @@ internal class GetEnrolmentCreationEventForSubjectUseCase @Inject constructor(

companion object {
val coSyncSerializationModule = SimpleModule().apply {
addSerializer(TokenizableString::class.java, TokenizationClassNameSerializer())
addDeserializer(TokenizableString::class.java, TokenizationClassNameDeserializer())
addSerializer(TokenizableStringV1::class.java, TokenizableStringV1Serializer())
Copy link
Collaborator

Choose a reason for hiding this comment

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

@BurningAXE I don't yet understand why we are exporting the TokenizableString class info to the calling apps

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because properties in the model are using it? :D If we strip it we'll have to guess about the tokenization state of those fields. Which is already the case with some historical data but does not need to continue.
Do you see any issues with it?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I just see that tokenization handling adds a lot of it complexity

addDeserializer(TokenizableStringV1::class.java, TokenizableStringV1Deserializer())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ import com.simprints.core.DispatcherBG
import com.simprints.core.domain.common.Modality
import com.simprints.core.domain.sample.Identity
import com.simprints.core.domain.sample.Sample
import com.simprints.core.domain.tokenization.TokenizableString
import com.simprints.core.domain.tokenization.serialization.TokenizationClassNameDeserializer
import com.simprints.core.domain.tokenization.serialization.TokenizationClassNameSerializer
import com.simprints.core.tools.json.JsonHelper
import com.simprints.core.tools.time.TimeHelper
import com.simprints.core.tools.utils.EncodingUtils
Expand All @@ -25,8 +22,13 @@ import com.simprints.infra.enrolment.records.repository.domain.models.BiometricD
import com.simprints.infra.enrolment.records.repository.domain.models.IdentityBatch
import com.simprints.infra.enrolment.records.repository.domain.models.SubjectQuery
import com.simprints.infra.enrolment.records.repository.usecases.CompareImplicitTokenizedStringsUseCase
import com.simprints.infra.events.event.cosync.CoSyncEnrolmentRecordCreationEventDeserializer
import com.simprints.infra.events.event.cosync.CoSyncEnrolmentRecordEvents
import com.simprints.infra.events.event.cosync.v1.CoSyncEnrolmentRecordCreationEventV1
import com.simprints.infra.events.event.cosync.v1.CoSyncEnrolmentRecordCreationEventV1Deserializer
import com.simprints.infra.events.event.cosync.v1.CoSyncEnrolmentRecordEventsV1
import com.simprints.infra.events.event.cosync.v1.TokenizableStringV1
import com.simprints.infra.events.event.cosync.v1.TokenizableStringV1Deserializer
import com.simprints.infra.events.event.cosync.v1.TokenizableStringV1Serializer
import com.simprints.infra.events.event.cosync.v1.toDomain
import com.simprints.infra.events.event.domain.models.subject.EnrolmentRecordCreationEvent
import com.simprints.infra.events.event.domain.models.subject.FaceReference
import com.simprints.infra.events.event.domain.models.subject.FingerprintReference
Expand Down Expand Up @@ -254,11 +256,12 @@ internal class CommCareIdentityDataSource @Inject constructor(

private fun parseRecordEvents(subjectActions: String) = subjectActions.takeIf(String::isNotEmpty)?.let {
try {
jsonHelper.fromJson<CoSyncEnrolmentRecordEvents>(
val v1Events = jsonHelper.fromJson<CoSyncEnrolmentRecordEventsV1>(
json = it,
module = coSyncSerializationModule,
type = object : TypeReference<CoSyncEnrolmentRecordEvents>() {},
type = object : TypeReference<CoSyncEnrolmentRecordEventsV1>() {},
)
v1Events.toDomain()
} catch (e: Exception) {
Simber.e("Error while parsing subjectActions", e)
null
Expand All @@ -267,16 +270,16 @@ internal class CommCareIdentityDataSource @Inject constructor(

private val coSyncSerializationModule = SimpleModule().apply {
addSerializer(
TokenizableString::class.java,
TokenizationClassNameSerializer(),
TokenizableStringV1::class.java,
TokenizableStringV1Serializer(),
)
addDeserializer(
TokenizableString::class.java,
TokenizationClassNameDeserializer(),
TokenizableStringV1::class.java,
TokenizableStringV1Deserializer(),
)
addDeserializer(
EnrolmentRecordCreationEvent::class.java,
CoSyncEnrolmentRecordCreationEventDeserializer(),
CoSyncEnrolmentRecordCreationEventV1::class.java,
CoSyncEnrolmentRecordCreationEventV1Deserializer(),
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import android.database.Cursor
import androidx.core.net.toUri
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.module.SimpleModule
import com.simprints.core.domain.tokenization.TokenizableString
import com.simprints.core.domain.tokenization.serialization.TokenizationClassNameDeserializer
import com.simprints.core.domain.tokenization.serialization.TokenizationClassNameSerializer
import com.simprints.core.tools.json.JsonHelper
import com.simprints.infra.config.store.LastCallingPackageStore
import com.simprints.infra.events.event.cosync.CoSyncEnrolmentRecordCreationEventDeserializer
import com.simprints.infra.events.event.cosync.CoSyncEnrolmentRecordEvents
import com.simprints.infra.events.event.cosync.v1.CoSyncEnrolmentRecordCreationEventV1
import com.simprints.infra.events.event.cosync.v1.CoSyncEnrolmentRecordCreationEventV1Deserializer
import com.simprints.infra.events.event.cosync.v1.CoSyncEnrolmentRecordEventsV1
import com.simprints.infra.events.event.cosync.v1.TokenizableStringV1
import com.simprints.infra.events.event.cosync.v1.TokenizableStringV1Deserializer
import com.simprints.infra.events.event.cosync.v1.TokenizableStringV1Serializer
import com.simprints.infra.events.event.cosync.v1.toDomain
import com.simprints.infra.events.event.domain.models.subject.EnrolmentRecordCreationEvent
import com.simprints.infra.events.event.domain.models.subject.EnrolmentRecordDeletionEvent
import com.simprints.infra.events.event.domain.models.subject.EnrolmentRecordEvent
Expand Down Expand Up @@ -228,11 +230,12 @@ internal class CommCareEventDataSource @Inject constructor(

private fun parseRecordEvents(subjectActions: String) = subjectActions.takeIf(String::isNotEmpty)?.let {
try {
jsonHelper.fromJson<CoSyncEnrolmentRecordEvents>(
val v1Events = jsonHelper.fromJson<CoSyncEnrolmentRecordEventsV1>(
json = it,
module = coSyncSerializationModule,
type = object : TypeReference<CoSyncEnrolmentRecordEvents>() {},
type = object : TypeReference<CoSyncEnrolmentRecordEventsV1>() {},
)
v1Events.toDomain()
} catch (e: Exception) {
Simber.e("Error while parsing subjectActions", e)
null
Expand Down Expand Up @@ -300,16 +303,16 @@ internal class CommCareEventDataSource @Inject constructor(

private val coSyncSerializationModule = SimpleModule().apply {
addSerializer(
TokenizableString::class.java,
TokenizationClassNameSerializer(),
TokenizableStringV1::class.java,
TokenizableStringV1Serializer(),
)
addDeserializer(
TokenizableString::class.java,
TokenizationClassNameDeserializer(),
TokenizableStringV1::class.java,
TokenizableStringV1Deserializer(),
)
addDeserializer(
EnrolmentRecordCreationEvent::class.java,
CoSyncEnrolmentRecordCreationEventDeserializer(),
CoSyncEnrolmentRecordCreationEventV1::class.java,
CoSyncEnrolmentRecordCreationEventV1Deserializer(),
)
}

Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package com.simprints.infra.events.event.cosync.v1

import androidx.annotation.Keep
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.simprints.infra.events.event.domain.models.subject.BiometricReference
import com.simprints.infra.events.event.domain.models.subject.FaceReference
import com.simprints.infra.events.event.domain.models.subject.FingerprintReference

/**
* V1 external schema for biometric references (polymorphic base type).
*
* Uses Jackson polymorphic serialization with "type" discriminator field.
*/
@Keep
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY,
property = "type",
)
@JsonSubTypes(
JsonSubTypes.Type(value = FaceReferenceV1::class, name = "FACE_REFERENCE"),
JsonSubTypes.Type(value = FingerprintReferenceV1::class, name = "FINGERPRINT_REFERENCE"),
)
@JsonInclude(JsonInclude.Include.NON_NULL)
sealed class BiometricReferenceV1(
open val id: String,
open val format: String,
val type: String,
)

/**
* V1 face reference with face templates.
*/
@Keep
@JsonInclude(JsonInclude.Include.NON_NULL)
data class FaceReferenceV1(
override val id: String,
val templates: List<FaceTemplateV1>,
override val format: String,
val metadata: Map<String, String>? = null,
) : BiometricReferenceV1(id, format, "FACE_REFERENCE")

/**
* V1 fingerprint reference with fingerprint templates.
*/
@Keep
@JsonInclude(JsonInclude.Include.NON_NULL)
data class FingerprintReferenceV1(
override val id: String,
val templates: List<FingerprintTemplateV1>,
override val format: String,
val metadata: Map<String, String>? = null,
) : BiometricReferenceV1(id, format, "FINGERPRINT_REFERENCE")

/**
* Converts internal BiometricReference to V1 external schema.
*/
fun BiometricReference.toCoSyncV1(): BiometricReferenceV1 = when (this) {
is FaceReference -> this.toCoSyncV1()
is FingerprintReference -> this.toCoSyncV1()
}

/**
* Converts V1 external schema to internal BiometricReference.
*/
fun BiometricReferenceV1.toDomain(): BiometricReference = when (this) {
is FaceReferenceV1 -> this.toDomain()
is FingerprintReferenceV1 -> this.toDomain()
}

/**
* Converts internal FaceReference to V1 external schema.
*/
fun FaceReference.toCoSyncV1() = FaceReferenceV1(
id = id,
templates = templates.map { it.toCoSyncV1() },
format = format,
metadata = metadata,
)

/**
* Converts V1 external schema to internal FaceReference.
*/
fun FaceReferenceV1.toDomain() = FaceReference(
id = id,
templates = templates.map { it.toDomain() },
format = format,
metadata = metadata,
)

/**
* Converts internal FingerprintReference to V1 external schema.
*/
fun FingerprintReference.toCoSyncV1() = FingerprintReferenceV1(
id = id,
templates = templates.map { it.toCoSyncV1() },
format = format,
metadata = metadata,
)

/**
* Converts V1 external schema to internal FingerprintReference.
*/
fun FingerprintReferenceV1.toDomain() = FingerprintReference(
id = id,
templates = templates.map { it.toDomain() },
format = format,
metadata = metadata,
)
Loading