From 7a245215b816465e7e32e38ec564a57ad0649414 Mon Sep 17 00:00:00 2001 From: lingniu Date: Wed, 1 Jul 2026 02:58:38 +0800 Subject: [PATCH] refactor: use stateless identity fallback --- .../StatelessVehicleIdentityResolver.java | 34 +++++++++++ .../StatelessVehicleIdentityResolverTest.java | 57 +++++++++++++++++++ .../mqtt/client/MqttEndpointManager.java | 6 +- .../mqtt/mapper/YutongEventMapper.java | 6 +- .../handler/Jt1078MalformedRtpHandler.java | 6 +- .../Jt1078MalformedRtpEventPublisher.java | 6 +- .../config/Jt1078AutoConfigurationTest.java | 8 +++ 7 files changed, 111 insertions(+), 12 deletions(-) create mode 100644 modules/core/vehicle-identity/src/main/java/com/lingniu/ingest/identity/StatelessVehicleIdentityResolver.java create mode 100644 modules/core/vehicle-identity/src/test/java/com/lingniu/ingest/identity/StatelessVehicleIdentityResolverTest.java diff --git a/modules/core/vehicle-identity/src/main/java/com/lingniu/ingest/identity/StatelessVehicleIdentityResolver.java b/modules/core/vehicle-identity/src/main/java/com/lingniu/ingest/identity/StatelessVehicleIdentityResolver.java new file mode 100644 index 00000000..ecaa45f2 --- /dev/null +++ b/modules/core/vehicle-identity/src/main/java/com/lingniu/ingest/identity/StatelessVehicleIdentityResolver.java @@ -0,0 +1,34 @@ +package com.lingniu.ingest.identity; + +/** + * Stateless production fallback used when a caller has no injected identity service. + * + *

Persistent binding belongs to {@link MySqlVehicleIdentityService}; this resolver only keeps + * ingestion flowing with explicit VIN or stable external identifiers. + */ +public final class StatelessVehicleIdentityResolver implements VehicleIdentityResolver { + + @Override + public VehicleIdentity resolve(VehicleIdentityLookup lookup) { + if (lookup == null) { + return unknown(); + } + if (!lookup.vin().isBlank()) { + return new VehicleIdentity(lookup.vin(), true, VehicleIdentitySource.EXPLICIT_VIN); + } + if (!lookup.deviceId().isBlank()) { + return new VehicleIdentity(lookup.deviceId(), false, VehicleIdentitySource.FALLBACK_DEVICE_ID); + } + if (!lookup.phone().isBlank()) { + return new VehicleIdentity(lookup.phone(), false, VehicleIdentitySource.FALLBACK_PHONE); + } + if (!lookup.plate().isBlank()) { + return new VehicleIdentity(lookup.plate(), false, VehicleIdentitySource.FALLBACK_PLATE); + } + return unknown(); + } + + private static VehicleIdentity unknown() { + return new VehicleIdentity("unknown", false, VehicleIdentitySource.UNKNOWN); + } +} diff --git a/modules/core/vehicle-identity/src/test/java/com/lingniu/ingest/identity/StatelessVehicleIdentityResolverTest.java b/modules/core/vehicle-identity/src/test/java/com/lingniu/ingest/identity/StatelessVehicleIdentityResolverTest.java new file mode 100644 index 00000000..5314cf19 --- /dev/null +++ b/modules/core/vehicle-identity/src/test/java/com/lingniu/ingest/identity/StatelessVehicleIdentityResolverTest.java @@ -0,0 +1,57 @@ +package com.lingniu.ingest.identity; + +import com.lingniu.ingest.api.ProtocolId; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class StatelessVehicleIdentityResolverTest { + + private final StatelessVehicleIdentityResolver resolver = new StatelessVehicleIdentityResolver(); + + @Test + void explicitVinWinsWithoutPersistingAnyBinding() { + VehicleIdentity identity = resolver.resolve(new VehicleIdentityLookup( + ProtocolId.MQTT_YUTONG, "LNVIN000000000001", "13900000000", "DEV001", "粤B12345")); + + assertThat(identity.vin()).isEqualTo("LNVIN000000000001"); + assertThat(identity.resolved()).isTrue(); + assertThat(identity.source()).isEqualTo(VehicleIdentitySource.EXPLICIT_VIN); + } + + @Test + void fallsBackToStableExternalIdentifiersWithoutMarkingResolved() { + assertThat(resolver.resolve(new VehicleIdentityLookup( + ProtocolId.JT808, "", "13900000001", "DEV001", "粤B12345"))) + .satisfies(identity -> { + assertThat(identity.vin()).isEqualTo("DEV001"); + assertThat(identity.resolved()).isFalse(); + assertThat(identity.source()).isEqualTo(VehicleIdentitySource.FALLBACK_DEVICE_ID); + }); + + assertThat(resolver.resolve(new VehicleIdentityLookup( + ProtocolId.JT808, "", "13900000001", "", "粤B12345"))) + .satisfies(identity -> { + assertThat(identity.vin()).isEqualTo("13900000001"); + assertThat(identity.resolved()).isFalse(); + assertThat(identity.source()).isEqualTo(VehicleIdentitySource.FALLBACK_PHONE); + }); + + assertThat(resolver.resolve(new VehicleIdentityLookup( + ProtocolId.JT808, "", "", "", "粤B12345"))) + .satisfies(identity -> { + assertThat(identity.vin()).isEqualTo("粤B12345"); + assertThat(identity.resolved()).isFalse(); + assertThat(identity.source()).isEqualTo(VehicleIdentitySource.FALLBACK_PLATE); + }); + } + + @Test + void returnsUnknownWhenNoIdentitySignalExists() { + VehicleIdentity identity = resolver.resolve(new VehicleIdentityLookup(ProtocolId.JT808, "", "", "", "")); + + assertThat(identity.vin()).isEqualTo("unknown"); + assertThat(identity.resolved()).isFalse(); + assertThat(identity.source()).isEqualTo(VehicleIdentitySource.UNKNOWN); + } +} diff --git a/modules/inbound/inbound-mqtt/src/main/java/com/lingniu/ingest/inbound/mqtt/client/MqttEndpointManager.java b/modules/inbound/inbound-mqtt/src/main/java/com/lingniu/ingest/inbound/mqtt/client/MqttEndpointManager.java index ae2989bf..61a1ff51 100644 --- a/modules/inbound/inbound-mqtt/src/main/java/com/lingniu/ingest/inbound/mqtt/client/MqttEndpointManager.java +++ b/modules/inbound/inbound-mqtt/src/main/java/com/lingniu/ingest/inbound/mqtt/client/MqttEndpointManager.java @@ -3,7 +3,7 @@ package com.lingniu.ingest.inbound.mqtt.client; import com.lingniu.ingest.api.ProtocolId; import com.lingniu.ingest.api.pipeline.RawFrame; import com.lingniu.ingest.core.dispatcher.Dispatcher; -import com.lingniu.ingest.identity.InMemoryVehicleIdentityService; +import com.lingniu.ingest.identity.StatelessVehicleIdentityResolver; import com.lingniu.ingest.identity.VehicleIdentity; import com.lingniu.ingest.identity.VehicleIdentityLookup; import com.lingniu.ingest.identity.VehicleIdentityResolver; @@ -53,7 +53,7 @@ public final class MqttEndpointManager implements AutoCloseable { public MqttEndpointManager(MqttInboundProperties props, MqttProfileRegistry profileRegistry, Dispatcher dispatcher) { - this(props, profileRegistry, new InMemoryVehicleIdentityService(), dispatcher); + this(props, profileRegistry, new StatelessVehicleIdentityResolver(), dispatcher); } public MqttEndpointManager(MqttInboundProperties props, @@ -62,7 +62,7 @@ public final class MqttEndpointManager implements AutoCloseable { Dispatcher dispatcher) { this.props = props; this.profileRegistry = profileRegistry; - this.identityResolver = identityResolver == null ? new InMemoryVehicleIdentityService() : identityResolver; + this.identityResolver = identityResolver == null ? new StatelessVehicleIdentityResolver() : identityResolver; this.dispatcher = dispatcher; } diff --git a/modules/inbound/inbound-mqtt/src/main/java/com/lingniu/ingest/inbound/mqtt/mapper/YutongEventMapper.java b/modules/inbound/inbound-mqtt/src/main/java/com/lingniu/ingest/inbound/mqtt/mapper/YutongEventMapper.java index 756c0706..3087a925 100644 --- a/modules/inbound/inbound-mqtt/src/main/java/com/lingniu/ingest/inbound/mqtt/mapper/YutongEventMapper.java +++ b/modules/inbound/inbound-mqtt/src/main/java/com/lingniu/ingest/inbound/mqtt/mapper/YutongEventMapper.java @@ -6,7 +6,7 @@ import com.lingniu.ingest.api.event.LocationPayload; import com.lingniu.ingest.api.event.RealtimePayload; import com.lingniu.ingest.api.event.VehicleEvent; import com.lingniu.ingest.api.spi.EventMapper; -import com.lingniu.ingest.identity.InMemoryVehicleIdentityService; +import com.lingniu.ingest.identity.StatelessVehicleIdentityResolver; import com.lingniu.ingest.identity.VehicleIdentity; import com.lingniu.ingest.identity.VehicleIdentityLookup; import com.lingniu.ingest.identity.VehicleIdentityResolver; @@ -31,11 +31,11 @@ public final class YutongEventMapper implements EventMapper { private final VehicleIdentityResolver identityResolver; public YutongEventMapper() { - this(new InMemoryVehicleIdentityService()); + this(new StatelessVehicleIdentityResolver()); } public YutongEventMapper(VehicleIdentityResolver identityResolver) { - this.identityResolver = identityResolver == null ? new InMemoryVehicleIdentityService() : identityResolver; + this.identityResolver = identityResolver == null ? new StatelessVehicleIdentityResolver() : identityResolver; } @Override diff --git a/modules/protocols/protocol-jt1078/src/main/java/com/lingniu/ingest/protocol/jt1078/handler/Jt1078MalformedRtpHandler.java b/modules/protocols/protocol-jt1078/src/main/java/com/lingniu/ingest/protocol/jt1078/handler/Jt1078MalformedRtpHandler.java index d6f81fef..06fbf4b9 100644 --- a/modules/protocols/protocol-jt1078/src/main/java/com/lingniu/ingest/protocol/jt1078/handler/Jt1078MalformedRtpHandler.java +++ b/modules/protocols/protocol-jt1078/src/main/java/com/lingniu/ingest/protocol/jt1078/handler/Jt1078MalformedRtpHandler.java @@ -5,7 +5,7 @@ import com.lingniu.ingest.api.annotation.EventEmit; import com.lingniu.ingest.api.annotation.MessageMapping; import com.lingniu.ingest.api.annotation.ProtocolHandler; import com.lingniu.ingest.api.event.VehicleEvent; -import com.lingniu.ingest.identity.InMemoryVehicleIdentityService; +import com.lingniu.ingest.identity.StatelessVehicleIdentityResolver; import com.lingniu.ingest.identity.VehicleIdentity; import com.lingniu.ingest.identity.VehicleIdentityLookup; import com.lingniu.ingest.identity.VehicleIdentityResolver; @@ -25,11 +25,11 @@ public final class Jt1078MalformedRtpHandler { private final VehicleIdentityResolver identityResolver; public Jt1078MalformedRtpHandler() { - this(new InMemoryVehicleIdentityService()); + this(new StatelessVehicleIdentityResolver()); } public Jt1078MalformedRtpHandler(VehicleIdentityResolver identityResolver) { - this.identityResolver = identityResolver == null ? new InMemoryVehicleIdentityService() : identityResolver; + this.identityResolver = identityResolver == null ? new StatelessVehicleIdentityResolver() : identityResolver; } @MessageMapping(command = Jt1078MediaMessageId.MALFORMED_RTP, desc = "JT1078 RTP 入口坏包兜底") diff --git a/modules/protocols/protocol-jt1078/src/main/java/com/lingniu/ingest/protocol/jt1078/media/Jt1078MalformedRtpEventPublisher.java b/modules/protocols/protocol-jt1078/src/main/java/com/lingniu/ingest/protocol/jt1078/media/Jt1078MalformedRtpEventPublisher.java index 8300f99d..5961d364 100644 --- a/modules/protocols/protocol-jt1078/src/main/java/com/lingniu/ingest/protocol/jt1078/media/Jt1078MalformedRtpEventPublisher.java +++ b/modules/protocols/protocol-jt1078/src/main/java/com/lingniu/ingest/protocol/jt1078/media/Jt1078MalformedRtpEventPublisher.java @@ -2,7 +2,7 @@ package com.lingniu.ingest.protocol.jt1078.media; import com.lingniu.ingest.api.ProtocolId; import com.lingniu.ingest.api.pipeline.RawFrame; -import com.lingniu.ingest.identity.InMemoryVehicleIdentityService; +import com.lingniu.ingest.identity.StatelessVehicleIdentityResolver; import com.lingniu.ingest.identity.VehicleIdentity; import com.lingniu.ingest.identity.VehicleIdentityLookup; import com.lingniu.ingest.identity.VehicleIdentityResolver; @@ -19,12 +19,12 @@ public final class Jt1078MalformedRtpEventPublisher { private final Consumer dispatcher; public Jt1078MalformedRtpEventPublisher(Consumer dispatcher) { - this(new InMemoryVehicleIdentityService(), dispatcher); + this(new StatelessVehicleIdentityResolver(), dispatcher); } public Jt1078MalformedRtpEventPublisher(VehicleIdentityResolver identityResolver, Consumer dispatcher) { - this.identityResolver = identityResolver == null ? new InMemoryVehicleIdentityService() : identityResolver; + this.identityResolver = identityResolver == null ? new StatelessVehicleIdentityResolver() : identityResolver; this.dispatcher = dispatcher; } diff --git a/modules/protocols/protocol-jt1078/src/test/java/com/lingniu/ingest/protocol/jt1078/config/Jt1078AutoConfigurationTest.java b/modules/protocols/protocol-jt1078/src/test/java/com/lingniu/ingest/protocol/jt1078/config/Jt1078AutoConfigurationTest.java index 0fbfde9b..136f1bab 100644 --- a/modules/protocols/protocol-jt1078/src/test/java/com/lingniu/ingest/protocol/jt1078/config/Jt1078AutoConfigurationTest.java +++ b/modules/protocols/protocol-jt1078/src/test/java/com/lingniu/ingest/protocol/jt1078/config/Jt1078AutoConfigurationTest.java @@ -5,6 +5,7 @@ import com.lingniu.ingest.core.config.IngestCoreAutoConfiguration; import com.lingniu.ingest.api.event.VehicleEvent; import com.lingniu.ingest.api.sink.EventSink; import com.lingniu.ingest.identity.VehicleIdentity; +import com.lingniu.ingest.identity.VehicleIdentityRegistry; import com.lingniu.ingest.identity.VehicleIdentityResolver; import com.lingniu.ingest.identity.VehicleIdentitySource; import com.lingniu.ingest.identity.config.VehicleIdentityAutoConfiguration; @@ -71,6 +72,7 @@ class Jt1078AutoConfigurationTest { IngestCoreAutoConfiguration.class, SessionCoreAutoConfiguration.class, VehicleIdentityAutoConfiguration.class)) + .withUserConfiguration(SupportBeans.class) .withPropertyValues( "lingniu.ingest.jt1078.enabled=true", "lingniu.ingest.jt1078.media-stream.enabled=false", @@ -141,6 +143,12 @@ class Jt1078AutoConfigurationTest { }; } + @Bean + VehicleIdentityRegistry vehicleIdentityRegistry() { + return binding -> { + }; + } + @Bean(destroyMethod = "close") DisruptorEventBus disruptorEventBus(CapturingSink sink) { return new DisruptorEventBus(1024, "blocking", List.of(sink));