chore: remove in-memory identity store
This commit is contained in:
@@ -1,82 +0,0 @@
|
|||||||
package com.lingniu.ingest.identity;
|
|
||||||
|
|
||||||
import com.lingniu.ingest.api.ProtocolId;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
|
|
||||||
public final class InMemoryVehicleIdentityService implements VehicleIdentityResolver, VehicleIdentityRegistry {
|
|
||||||
|
|
||||||
private final ConcurrentMap<String, String> phoneToVin = new ConcurrentHashMap<>();
|
|
||||||
private final ConcurrentMap<String, String> deviceIdToVin = new ConcurrentHashMap<>();
|
|
||||||
private final ConcurrentMap<String, String> plateToVin = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bind(VehicleIdentityBinding binding) {
|
|
||||||
if (binding == null || !binding.hasResolvedVin()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!binding.phone().isBlank()) {
|
|
||||||
phoneToVin.put(key(binding.protocol(), binding.phone()), binding.vin());
|
|
||||||
}
|
|
||||||
if (!binding.deviceId().isBlank()) {
|
|
||||||
deviceIdToVin.put(key(binding.protocol(), binding.deviceId()), binding.vin());
|
|
||||||
}
|
|
||||||
if (!binding.plate().isBlank()) {
|
|
||||||
plateToVin.put(key(binding.protocol(), binding.plate()), binding.vin());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VehicleIdentity resolve(VehicleIdentityLookup lookup) {
|
|
||||||
if (lookup == null) {
|
|
||||||
return new VehicleIdentity("unknown", false, VehicleIdentitySource.UNKNOWN);
|
|
||||||
}
|
|
||||||
if (!lookup.vin().isBlank()) {
|
|
||||||
// 协议报文已经携带可信 VIN 时直接采用;绑定表主要服务 JT808/MQTT/信达这类外部 ID。
|
|
||||||
return new VehicleIdentity(lookup.vin(), true, VehicleIdentitySource.EXPLICIT_VIN);
|
|
||||||
}
|
|
||||||
// 绑定优先级:phone > deviceId > plate。顺序要稳定,否则同一车辆多外部号会产生不同内部 VIN。
|
|
||||||
VehicleIdentity phone = resolveBound(phoneToVin, lookup.protocol(), lookup.phone(), VehicleIdentitySource.BOUND_PHONE);
|
|
||||||
if (phone != null) return phone;
|
|
||||||
|
|
||||||
VehicleIdentity device = resolveBound(deviceIdToVin, lookup.protocol(), lookup.deviceId(), VehicleIdentitySource.BOUND_DEVICE_ID);
|
|
||||||
if (device != null) return device;
|
|
||||||
|
|
||||||
VehicleIdentity plate = resolveBound(plateToVin, lookup.protocol(), lookup.plate(), VehicleIdentitySource.BOUND_PLATE);
|
|
||||||
if (plate != null) return plate;
|
|
||||||
|
|
||||||
if (!lookup.deviceId().isBlank()) {
|
|
||||||
// fallback 不是已确认绑定,只用于不中断接收和冷存;metadata.identityResolved=false 会保留这个事实。
|
|
||||||
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 new VehicleIdentity("unknown", false, VehicleIdentitySource.UNKNOWN);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static VehicleIdentity resolveBound(ConcurrentMap<String, String> map,
|
|
||||||
ProtocolId protocol,
|
|
||||||
String externalId,
|
|
||||||
VehicleIdentitySource source) {
|
|
||||||
if (externalId == null || externalId.isBlank()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String vin = map.get(key(protocol, externalId));
|
|
||||||
if (vin == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new VehicleIdentity(vin, true, source);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String key(ProtocolId protocol, String value) {
|
|
||||||
String p = protocol == null ? "UNKNOWN" : protocol.name();
|
|
||||||
// 绑定 key 带协议前缀,避免 JT808 phone 与 MQTT deviceId 数值相同时互相覆盖。
|
|
||||||
return p + ":" + value.trim().toUpperCase(Locale.ROOT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
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 InMemoryVehicleIdentityServiceTest {
|
|
||||||
|
|
||||||
private final InMemoryVehicleIdentityService service = new InMemoryVehicleIdentityService();
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void explicitVinWinsOverExternalIdentifiers() {
|
|
||||||
VehicleIdentity identity = service.resolve(new VehicleIdentityLookup(
|
|
||||||
ProtocolId.JT808, "LNVIN000000000001", "13900000000", "DEV001", "粤B12345"));
|
|
||||||
|
|
||||||
assertThat(identity.vin()).isEqualTo("LNVIN000000000001");
|
|
||||||
assertThat(identity.resolved()).isTrue();
|
|
||||||
assertThat(identity.source()).isEqualTo(VehicleIdentitySource.EXPLICIT_VIN);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void resolvesBoundPhoneDeviceIdAndPlateToVin() {
|
|
||||||
service.bind(new VehicleIdentityBinding(
|
|
||||||
ProtocolId.JT808, "LNVIN000000000002", "13900000001", "DEV002", "粤B22222"));
|
|
||||||
|
|
||||||
assertThat(service.resolve(new VehicleIdentityLookup(
|
|
||||||
ProtocolId.JT808, "", "13900000001", "", "")).vin())
|
|
||||||
.isEqualTo("LNVIN000000000002");
|
|
||||||
assertThat(service.resolve(new VehicleIdentityLookup(
|
|
||||||
ProtocolId.JT808, "", "", "DEV002", "")).vin())
|
|
||||||
.isEqualTo("LNVIN000000000002");
|
|
||||||
assertThat(service.resolve(new VehicleIdentityLookup(
|
|
||||||
ProtocolId.JT808, "", "", "", "粤B22222")).vin())
|
|
||||||
.isEqualTo("LNVIN000000000002");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void fallsBackToStableExternalIdentifierWhenNoBindingExists() {
|
|
||||||
VehicleIdentity identity = service.resolve(new VehicleIdentityLookup(
|
|
||||||
ProtocolId.JT808, "", "13900000003", "DEV003", "粤B33333"));
|
|
||||||
|
|
||||||
assertThat(identity.vin()).isEqualTo("DEV003");
|
|
||||||
assertThat(identity.resolved()).isFalse();
|
|
||||||
assertThat(identity.source()).isEqualTo(VehicleIdentitySource.FALLBACK_DEVICE_ID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,9 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
class VehicleIdentityAutoConfigurationTest {
|
class VehicleIdentityAutoConfigurationTest {
|
||||||
@@ -69,4 +72,13 @@ class VehicleIdentityAutoConfigurationTest {
|
|||||||
.hasMessageContaining("identity.store supports only mysql")
|
.hasMessageContaining("identity.store supports only mysql")
|
||||||
.hasMessageContaining("sqlite"));
|
.hasMessageContaining("sqlite"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void moduleDoesNotKeepAlternativeStoreImplementations() {
|
||||||
|
Path sourceRoot = Path.of("src/main/java/com/lingniu/ingest/identity");
|
||||||
|
|
||||||
|
assertThat(Files.exists(sourceRoot.resolve("InMemoryVehicleIdentityService.java")))
|
||||||
|
.as("identity store is mysql-only; in-memory implementation must not be shipped")
|
||||||
|
.isFalse();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user