V5 迁移;集合段出现才写;白名单 7 类内未落态写入 UNMAPPED_FIELD,不扩白名单。 Co-authored-by: Cursor <cursoragent@cursor.com>
320 lines
17 KiB
Kotlin
320 lines
17 KiB
Kotlin
package com.gzzn.omms.msgexchange.codec
|
||
|
||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper
|
||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
|
||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement
|
||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText
|
||
import com.gzzn.omms.msgexchange.domain.flight.ScheduleRecord
|
||
import com.gzzn.omms.msgexchange.domain.flight.UnmappedFieldEntry
|
||
|
||
/** Stable payload boundary used by processing. It is deliberately not an XML model. */
|
||
data class FlopPayload(
|
||
val flid: String,
|
||
val scalars: Map<String, String> = emptyMap(),
|
||
val collections: Map<String, List<Map<String, String>>> = emptyMap(),
|
||
val unmapped: List<UnmappedFieldEntry> = emptyList(),
|
||
)
|
||
|
||
data class ScheduleBody(
|
||
val recsDeclared: Int,
|
||
val records: List<ScheduleRecord>,
|
||
)
|
||
|
||
/**
|
||
* `SRVT`/`VIPF` 集合键(`[G-SRVT-VIPF]`):用于入站出现次数指标;明细落库见 `FLIGHT_SRVT`/`FLIGHT_VIPF`,
|
||
* 不参与合并层与 Redis 快照。
|
||
*/
|
||
private val UNPERSISTED_COLLECTION_KEYS: Set<String> = setOf("SRVT", "VIPF")
|
||
|
||
/**
|
||
* 一条解码载荷里各未落库集合命中的**记录数**(`[G-SRVT-VIPF]`)。
|
||
*
|
||
* 按记录计(一条记录带该段即算 1),不按段内元素计;只返回命中项。载荷类型不在
|
||
* [ScheduleBody] / [FlopPayload] 之内时返回空——调用方不得据此改变处理结果。
|
||
*/
|
||
fun unpersistedCollectionHits(body: Any?): Map<String, Int> {
|
||
val perRecord = when (body) {
|
||
is ScheduleBody -> body.records.map { it.collections }
|
||
is FlopPayload -> listOf(body.collections)
|
||
else -> return emptyMap()
|
||
}
|
||
if (perRecord.isEmpty()) return emptyMap()
|
||
return UNPERSISTED_COLLECTION_KEYS
|
||
.mapNotNull { key -> perRecord.count { key in it }.takeIf { it > 0 }?.let { key to it } }
|
||
.toMap()
|
||
}
|
||
|
||
/**
|
||
* Wire DTOs for SIS in docs/legacy/SIS_AODB_RMS-V0.1.md.
|
||
* SIS permits a subsystem to ignore standard fields it does not use; those fields are
|
||
* therefore ignored here, while fields used by the state model are explicitly annotated.
|
||
*/
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
@JacksonXmlRootElement(localName = "MSG")
|
||
data class SisMessageXml(
|
||
@param:JacksonXmlProperty(localName = "META") val meta: SisMetaXml? = null,
|
||
@param:JacksonXmlProperty(localName = "SCHD") val schd: SchdXml? = null,
|
||
@param:JacksonXmlProperty(localName = "FLOP") val flop: FlightRecordXml? = null,
|
||
@param:JacksonXmlProperty(localName = "EROR") val eror: ErorXml? = null,
|
||
@param:JacksonXmlProperty(localName = "RQFD") val rqfd: RqfdXml? = null,
|
||
@param:JacksonXmlProperty(localName = "RQRD") val rqrd: RqrdXml? = null,
|
||
)
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class ErorXml(
|
||
@param:JacksonXmlProperty(localName = "SEQS") val seqs: Long? = null,
|
||
@param:JacksonXmlProperty(localName = "TYPS") val typs: String? = null,
|
||
@param:JacksonXmlProperty(localName = "STYS") val stys: String? = null,
|
||
@param:JacksonXmlProperty(localName = "ETEX") val etex: String? = null,
|
||
)
|
||
|
||
/** 出站 RQFD 空体占位(C-4 全量不带 STDB/STDE)。 */
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
class RqfdXml
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class RqrdXml(
|
||
@param:JacksonXmlProperty(localName = "RTYP") val rtyp: String? = null,
|
||
)
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
@JacksonXmlRootElement(localName = "MSG")
|
||
data class SisOutboundMessageXml(
|
||
@param:JacksonXmlProperty(localName = "META") val meta: SisMetaXml,
|
||
@param:JacksonXmlProperty(localName = "RQFD") val rqfd: RqfdXml? = null,
|
||
@param:JacksonXmlProperty(localName = "RQRD") val rqrd: RqrdXml? = null,
|
||
)
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class SisMetaXml(
|
||
@param:JacksonXmlProperty(localName = "SNDR") val sndr: String? = null,
|
||
@param:JacksonXmlProperty(localName = "SEQN") val seqn: Long? = null,
|
||
@param:JacksonXmlProperty(localName = "DTTM") val dttm: Long? = null,
|
||
@param:JacksonXmlProperty(localName = "TYPE") val type: String? = null,
|
||
@param:JacksonXmlProperty(localName = "STYP") val styp: String? = null,
|
||
)
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class SchdXml(
|
||
@param:JacksonXmlProperty(localName = "RECS") val recs: Int? = null,
|
||
@param:JacksonXmlElementWrapper(useWrapping = false)
|
||
@param:JacksonXmlProperty(localName = "FLTR") val fltr: List<FlightRecordXml> = emptyList(),
|
||
)
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class FlightRecordXml(
|
||
@param:JacksonXmlProperty(localName = "FLID") val flid: String? = null,
|
||
@param:JacksonXmlProperty(localName = "FDEL") val fdel: FdelXml? = null,
|
||
@param:JacksonXmlProperty(localName = "ALCD") val alcd: String? = null,
|
||
@param:JacksonXmlProperty(localName = "ALSC") val alsc: String? = null,
|
||
@param:JacksonXmlProperty(localName = "FLNO") val flno: String? = null,
|
||
@param:JacksonXmlProperty(localName = "MVIN") val mvin: String? = null,
|
||
@param:JacksonXmlProperty(localName = "SODT") val sodt: String? = null,
|
||
@param:JacksonXmlProperty(localName = "FLTY") val flty: String? = null,
|
||
@param:JacksonXmlProperty(localName = "FLIN") val flin: String? = null,
|
||
@param:JacksonXmlProperty(localName = "ACFT") val acft: String? = null,
|
||
@param:JacksonXmlProperty(localName = "RENO") val reno: String? = null,
|
||
@param:JacksonXmlProperty(localName = "TAOP") val taop: String? = null,
|
||
@param:JacksonXmlProperty(localName = "TAFL") val tafl: String? = null,
|
||
@param:JacksonXmlProperty(localName = "TAID") val taid: String? = null,
|
||
@param:JacksonXmlProperty(localName = "TRML") val trml: String? = null,
|
||
@param:JacksonXmlProperty(localName = "MAXP") val maxp: String? = null,
|
||
@param:JacksonXmlProperty(localName = "CSOP") val csop: String? = null,
|
||
@param:JacksonXmlProperty(localName = "CSFT") val csft: String? = null,
|
||
@param:JacksonXmlProperty(localName = "MAID") val maid: String? = null,
|
||
@param:JacksonXmlProperty(localName = "ESTT") val estt: String? = null,
|
||
@param:JacksonXmlProperty(localName = "ACTT") val actt: String? = null,
|
||
@param:JacksonXmlProperty(localName = "STND") val stnd: String? = null,
|
||
@param:JacksonXmlProperty(localName = "PHAG") val phag: String? = null,
|
||
@param:JacksonXmlProperty(localName = "CNCL") val cncl: String? = null,
|
||
@param:JacksonXmlProperty(localName = "REMC") val remc: String? = null,
|
||
@param:JacksonXmlProperty(localName = "BOTM") val botm: String? = null,
|
||
@param:JacksonXmlProperty(localName = "LACL") val lacl: String? = null,
|
||
@param:JacksonXmlProperty(localName = "FINT") val fint: String? = null,
|
||
@param:JacksonXmlProperty(localName = "APPT") val appt: String? = null,
|
||
@param:JacksonXmlProperty(localName = "EGSR") val egsr: String? = null,
|
||
@param:JacksonXmlProperty(localName = "EGST") val egst: String? = null,
|
||
@param:JacksonXmlProperty(localName = "FHAG") val fhag: String? = null,
|
||
@param:JacksonXmlProperty(localName = "MHAG") val mhag: String? = null,
|
||
@param:JacksonXmlProperty(localName = "VIPP") val vipp: String? = null,
|
||
@param:JacksonXmlProperty(localName = "VIPR") val vipr: String? = null,
|
||
@param:JacksonXmlProperty(localName = "LBNO") val lbno: String? = null,
|
||
@param:JacksonXmlProperty(localName = "LBWT") val lbwt: String? = null,
|
||
@param:JacksonXmlProperty(localName = "PAXC") val paxc: String? = null,
|
||
@param:JacksonXmlProperty(localName = "EXSC") val exsc: String? = null,
|
||
@param:JacksonXmlProperty(localName = "EXSR") val exsr: String? = null,
|
||
@param:JacksonXmlProperty(localName = "FTSS") val ftss: String? = null,
|
||
@param:JacksonXmlProperty(localName = "PEDT") val pedt: String? = null,
|
||
@param:JacksonXmlProperty(localName = "NAAT") val naat: String? = null,
|
||
@param:JacksonXmlProperty(localName = "NEAT") val neat: String? = null,
|
||
@param:JacksonXmlProperty(localName = "PADT") val padt: String? = null,
|
||
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "GTDT") val gtdt: List<GtdtXml> = emptyList(),
|
||
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "CKDT") val ckdt: List<CkdtXml> = emptyList(),
|
||
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "CLDT") val cldt: List<CldtXml> = emptyList(),
|
||
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "PSDT") val psdt: List<PsdtXml> = emptyList(),
|
||
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "CHDT") val chdt: List<ChdtXml> = emptyList(),
|
||
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "DELY") val dely: List<DelyXml> = emptyList(),
|
||
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "ABTM") val abtm: List<AbtmXml> = emptyList(),
|
||
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "CHOT") val chot: List<ChotXml> = emptyList(),
|
||
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "ROUT") val rout: List<RoutXml> = emptyList(),
|
||
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "ERUT") val erut: List<RoutXml> = emptyList(),
|
||
// SRVT/VIPF 用可空表达"段是否出现":null = 未出现;出现即为列表(空元素得到一行空行)。
|
||
// 明细表见 `G-SRVT-VIPF`;缺席是否清除待 `Q2`,现行默认不删已有行。
|
||
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "SRVT") val srvt: List<SrvtXml>? = null,
|
||
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "VIPF") val vipf: List<VipfXml>? = null,
|
||
@param:JacksonXmlProperty(localName = "FDIV") val fdiv: FdivXml? = null,
|
||
@param:JacksonXmlProperty(localName = "FRET") val fret: FretXml? = null,
|
||
)
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class FdivXml(
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "DDES") val ddes: String? = null,
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "DDIR") val ddir: String? = null,
|
||
) {
|
||
@field:JacksonXmlText
|
||
var text: String? = null
|
||
}
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class FretXml(
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "REID") val reid: String? = null,
|
||
) {
|
||
@field:JacksonXmlText
|
||
var text: String? = null
|
||
}
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
class FdelXml
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class GtdtXml(
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "GTNO") val gtno: String? = null,
|
||
@param:JacksonXmlProperty(localName = "GATE") val gate: String? = null,
|
||
@param:JacksonXmlProperty(localName = "PGOT") val pgot: String? = null,
|
||
@param:JacksonXmlProperty(localName = "PGCT") val pgct: String? = null,
|
||
@param:JacksonXmlProperty(localName = "GOTM") val gotm: String? = null,
|
||
@param:JacksonXmlProperty(localName = "GCTM") val gctm: String? = null,
|
||
@param:JacksonXmlProperty(localName = "GTYP") val gtyp: String? = null,
|
||
)
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class CkdtXml(
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "CKNO") val ckno: String? = null,
|
||
@param:JacksonXmlProperty(localName = "CHKC") val chkc: String? = null,
|
||
@param:JacksonXmlProperty(localName = "CCLS") val ccls: String? = null,
|
||
@param:JacksonXmlProperty(localName = "PCOT") val pcot: String? = null,
|
||
@param:JacksonXmlProperty(localName = "PCCT") val pcct: String? = null,
|
||
@param:JacksonXmlProperty(localName = "COTM") val cotm: String? = null,
|
||
@param:JacksonXmlProperty(localName = "CCTM") val cctm: String? = null,
|
||
@param:JacksonXmlProperty(localName = "CTYP") val ctyp: String? = null,
|
||
)
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class CldtXml(
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "CLNO") val clno: String? = null,
|
||
@param:JacksonXmlProperty(localName = "BELT") val belt: String? = null,
|
||
@param:JacksonXmlProperty(localName = "BCLS") val bcls: String? = null,
|
||
@param:JacksonXmlProperty(localName = "PCOT") val pcot: String? = null,
|
||
@param:JacksonXmlProperty(localName = "PCCT") val pcct: String? = null,
|
||
@param:JacksonXmlProperty(localName = "FBAG") val fbag: String? = null,
|
||
@param:JacksonXmlProperty(localName = "LBAG") val lbag: String? = null,
|
||
@param:JacksonXmlProperty(localName = "BTYP") val btyp: String? = null,
|
||
)
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class PsdtXml(
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "PSNO") val psno: String? = null,
|
||
@param:JacksonXmlProperty(localName = "PSST") val psst: String? = null,
|
||
@param:JacksonXmlProperty(localName = "STST") val stst: String? = null,
|
||
@param:JacksonXmlProperty(localName = "STET") val stet: String? = null,
|
||
)
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class ChdtXml(
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "CHNO") val chno: String? = null,
|
||
@param:JacksonXmlProperty(localName = "CHUT") val chut: String? = null,
|
||
// SIS 的 CHDT 类字段固定为 CCLS/CTYP(implementation.md「动态运行事件」);曾误绑 CHCLS/CHTYP
|
||
@param:JacksonXmlProperty(localName = "CCLS") val ccls: String? = null,
|
||
@param:JacksonXmlProperty(localName = "PCBT") val pcbt: String? = null,
|
||
@param:JacksonXmlProperty(localName = "PCET") val pcet: String? = null,
|
||
@param:JacksonXmlProperty(localName = "CBTM") val cbtm: String? = null,
|
||
@param:JacksonXmlProperty(localName = "CETM") val cetm: String? = null,
|
||
@param:JacksonXmlProperty(localName = "CTYP") val ctyp: String? = null,
|
||
)
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class DelyXml(
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "CODE") val code: String? = null,
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "STRT") val strt: String? = null,
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "DURA") val dura: String? = null,
|
||
) {
|
||
@field:JacksonXmlText
|
||
var text: String? = null
|
||
}
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class AbtmXml(
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "ASNO") val asno: String? = null,
|
||
@param:JacksonXmlProperty(localName = "ABDG") val abdg: String? = null,
|
||
@param:JacksonXmlProperty(localName = "ABOP") val abop: String? = null,
|
||
@param:JacksonXmlProperty(localName = "AOTM") val aotm: String? = null,
|
||
)
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class ChotXml(
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "CSNO") val csno: String? = null,
|
||
@param:JacksonXmlProperty(localName = "CHID") val chid: String? = null,
|
||
@param:JacksonXmlProperty(localName = "CHST") val chst: String? = null,
|
||
@param:JacksonXmlProperty(localName = "CHTM") val chtm: String? = null,
|
||
)
|
||
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class RoutXml(
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "RTNO") val rtno: String? = null,
|
||
@param:JacksonXmlProperty(localName = "APCD") val apcd: String? = null,
|
||
@param:JacksonXmlProperty(localName = "SCAT") val scat: String? = null,
|
||
@param:JacksonXmlProperty(localName = "SCDT") val scdt: String? = null,
|
||
)
|
||
|
||
/**
|
||
* SIS `SRVT`/`SERVICEDATA`(SCHD)与 `OPT_SERVICEDATA`(FLOP):一次服务明细,可重复出现。
|
||
*
|
||
* 字段形态以 `docs/legacy/unisysaodbsis.xsd` 为准。`OPER` 是元素属性,SIS 正文未记载其值域;
|
||
* `SANR`/`SARR` 只出现在 FLOP 的 `OPT_SERVICEDATA`。协议未给序号属性,故没有源序号。
|
||
*/
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class SrvtXml(
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "OPER") val oper: String? = null,
|
||
@param:JacksonXmlProperty(localName = "SRTC") val srtc: String? = null,
|
||
@param:JacksonXmlProperty(localName = "SRQT") val srqt: String? = null,
|
||
@param:JacksonXmlProperty(localName = "SRST") val srst: String? = null,
|
||
@param:JacksonXmlProperty(localName = "SRET") val sret: String? = null,
|
||
@param:JacksonXmlProperty(localName = "SRPR") val srpr: String? = null,
|
||
@param:JacksonXmlProperty(localName = "SANR") val sanr: String? = null,
|
||
@param:JacksonXmlProperty(localName = "SARR") val sarr: String? = null,
|
||
)
|
||
|
||
/**
|
||
* SIS `VIPF`/`VIPDATA`(SCHD)与 `OPT_VIPDATA`(FLOP):一位 VIP,可重复出现。
|
||
*
|
||
* `VIPT` 按 XSD 至多一个;SIS 正文"每个 VIP 重复"的说法与之冲突,形态以 XSD 为准。
|
||
*/
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class VipfXml(
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "OPER") val oper: String? = null,
|
||
@param:JacksonXmlProperty(localName = "VPCD") val vpcd: String? = null,
|
||
@param:JacksonXmlProperty(localName = "VFES") val vfes: String? = null,
|
||
@param:JacksonXmlProperty(localName = "VIPT") val vipt: ViptXml? = null,
|
||
)
|
||
|
||
/** SIS `VIPT`/`VIPTXNDATA`:VIP 关联的服务交易明细,嵌套在 [VipfXml] 内。 */
|
||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||
data class ViptXml(
|
||
@param:JacksonXmlProperty(isAttribute = true, localName = "OPER") val oper: String? = null,
|
||
@param:JacksonXmlProperty(localName = "VSCD") val vscd: String? = null,
|
||
@param:JacksonXmlProperty(localName = "VTQY") val vtqy: String? = null,
|
||
@param:JacksonXmlProperty(localName = "VTST") val vtst: String? = null,
|
||
@param:JacksonXmlProperty(localName = "VTET") val vtet: String? = null,
|
||
)
|