diff --git a/modules/core/vehicle-identity/src/main/java/com/lingniu/ingest/identity/MySqlVehicleIdentityService.java b/modules/core/vehicle-identity/src/main/java/com/lingniu/ingest/identity/MySqlVehicleIdentityService.java index 5785304b..41b8548d 100644 --- a/modules/core/vehicle-identity/src/main/java/com/lingniu/ingest/identity/MySqlVehicleIdentityService.java +++ b/modules/core/vehicle-identity/src/main/java/com/lingniu/ingest/identity/MySqlVehicleIdentityService.java @@ -131,12 +131,7 @@ public final class MySqlVehicleIdentityService implements VehicleIdentityResolve PreparedStatement statement = connection.prepareStatement(sql); ResultSet resultSet = statement.executeQuery()) { while (resultSet.next()) { - loaded.bind(new VehicleIdentityBinding( - ProtocolId.JT808, - resultSet.getString("vin"), - "", - "", - resultSet.getString("plate"))); + bindGlobalPlate(loaded, resultSet.getString("vin"), resultSet.getString("plate")); } loadRegistrationIndex(loaded, connection); return loaded; @@ -145,6 +140,17 @@ public final class MySqlVehicleIdentityService implements VehicleIdentityResolve } } + private static void bindGlobalPlate(InMemoryVehicleIdentityService loaded, String vin, String plate) { + for (ProtocolId protocol : new ProtocolId[]{ + ProtocolId.GB32960, + ProtocolId.JT808, + ProtocolId.MQTT_YUTONG, + ProtocolId.XINDA_PUSH + }) { + loaded.bind(new VehicleIdentityBinding(protocol, vin, "", "", plate)); + } + } + private void loadRegistrationIndex(InMemoryVehicleIdentityService loaded, Connection connection) throws SQLException { String sql = "SELECT r.protocol, r.phone, r.device_id, r.plate, b.vin FROM " + registrationTable + " r " + "JOIN " + table + " b ON b.plate = r.plate " diff --git a/modules/core/vehicle-identity/src/test/java/com/lingniu/ingest/identity/MySqlVehicleIdentityServiceTest.java b/modules/core/vehicle-identity/src/test/java/com/lingniu/ingest/identity/MySqlVehicleIdentityServiceTest.java index e7815d41..b1ca6a11 100644 --- a/modules/core/vehicle-identity/src/test/java/com/lingniu/ingest/identity/MySqlVehicleIdentityServiceTest.java +++ b/modules/core/vehicle-identity/src/test/java/com/lingniu/ingest/identity/MySqlVehicleIdentityServiceTest.java @@ -83,6 +83,22 @@ class MySqlVehicleIdentityServiceTest { assertThat(jdbc.lookupSelects).isZero(); } + @Test + void resolvesGlobalPlateBindingForXindaPush() { + RecordingIdentityJdbc jdbc = new RecordingIdentityJdbc(); + jdbc.seed("浙F00780F", "LA9GG68L8PBAF4776"); + MySqlVehicleIdentityService service = new MySqlVehicleIdentityService(jdbc.dataSource(), "vehicle_identity_binding"); + + VehicleIdentity byPlate = service.resolve(new VehicleIdentityLookup( + ProtocolId.XINDA_PUSH, "", "", "", "浙F00780F")); + + assertThat(byPlate.vin()).isEqualTo("LA9GG68L8PBAF4776"); + assertThat(byPlate.resolved()).isTrue(); + assertThat(byPlate.source()).isEqualTo(VehicleIdentitySource.BOUND_PLATE); + assertThat(jdbc.loadAllSelects).isEqualTo(1); + assertThat(jdbc.lookupSelects).isZero(); + } + @Test void refreshLoadsExternallyInsertedBindingWithoutPerFrameDatabaseLookup() { RecordingIdentityJdbc jdbc = new RecordingIdentityJdbc(); diff --git a/modules/inbound/inbound-xinda-push/src/main/java/com/lingniu/ingest/inbound/xinda/XindaPushEventMapper.java b/modules/inbound/inbound-xinda-push/src/main/java/com/lingniu/ingest/inbound/xinda/XindaPushEventMapper.java index 49ff8213..d40141fc 100644 --- a/modules/inbound/inbound-xinda-push/src/main/java/com/lingniu/ingest/inbound/xinda/XindaPushEventMapper.java +++ b/modules/inbound/inbound-xinda-push/src/main/java/com/lingniu/ingest/inbound/xinda/XindaPushEventMapper.java @@ -143,9 +143,9 @@ public final class XindaPushEventMapper implements EventMapper return IdentityResolution.ok(identityResolver.resolve(new VehicleIdentityLookup( ProtocolId.XINDA_PUSH, firstNonBlank(json, "vin"), - firstNonBlank(json, "sim", "phone", "mobile"), - firstNonBlank(json, "deviceId", "terminalId", "imei"), - firstNonBlank(json, "plateNo", "carNo")))); + firstNonBlank(json, "sim", "phone", "mobile", "simCode"), + firstNonBlank(json, "deviceId", "terminalId", "imei", "tmnKey", "tmnCode"), + plateNo(json)))); } catch (RuntimeException e) { return new IdentityResolution( new VehicleIdentity("unknown", false, VehicleIdentitySource.UNKNOWN), @@ -172,9 +172,9 @@ public final class XindaPushEventMapper implements EventMapper out.put("rawJson", message.json()); out.put("vin", normalizedVin(identity)); out.put("externalVin", firstNonBlank(json, "vin")); - out.put("phone", firstNonBlank(json, "sim", "phone", "mobile")); - out.put("deviceId", firstNonBlank(json, "deviceId", "terminalId", "imei")); - out.put("plateNo", firstNonBlank(json, "plateNo", "carNo")); + out.put("phone", firstNonBlank(json, "sim", "phone", "mobile", "simCode")); + out.put("deviceId", firstNonBlank(json, "deviceId", "terminalId", "imei", "tmnKey", "tmnCode")); + out.put("plateNo", plateNo(json)); out.put("identityResolved", Boolean.toString(identity.identity().resolved())); out.put("identitySource", identity.identity().source().name()); if (identity.errorMessage() != null) { @@ -243,6 +243,10 @@ public final class XindaPushEventMapper implements EventMapper return ""; } + private static String plateNo(JSONObject node) { + return firstNonBlank(node, "plateNo", "carNo", "carName"); + } + private static double asDouble(JSONObject node, String... keys) { Double value = optionalDouble(node, keys); return value == null ? 0.0 : value; diff --git a/modules/inbound/inbound-xinda-push/src/test/java/com/lingniu/ingest/inbound/xinda/XindaPushEventMapperTest.java b/modules/inbound/inbound-xinda-push/src/test/java/com/lingniu/ingest/inbound/xinda/XindaPushEventMapperTest.java index e9d51f12..6b9776f6 100644 --- a/modules/inbound/inbound-xinda-push/src/test/java/com/lingniu/ingest/inbound/xinda/XindaPushEventMapperTest.java +++ b/modules/inbound/inbound-xinda-push/src/test/java/com/lingniu/ingest/inbound/xinda/XindaPushEventMapperTest.java @@ -113,6 +113,27 @@ class XindaPushEventMapperTest { }); } + @Test + void resolvesVehicleIdentityByCarNamePlateFromXindaPayload() { + identity.bind(new VehicleIdentityBinding( + ProtocolId.XINDA_PUSH, "LNVIN000000000203", "", "", "浙F00780F")); + + List events = mapper.toEvents(new XindaPushMessage("0200", + "{\"carName\":\"浙F00780F\",\"tmnKey\":\"13307811342\",\"simCode\":\"8986062582008805648\"," + + "\"lng\":121.075223,\"lat\":30.583753}")); + + assertThat(events).singleElement() + .satisfies(event -> { + assertThat(event.vin()).isEqualTo("LNVIN000000000203"); + assertThat(event.metadata()) + .containsEntry("vin", "LNVIN000000000203") + .containsEntry("plateNo", "浙F00780F") + .containsEntry("phone", "8986062582008805648") + .containsEntry("deviceId", "13307811342") + .containsEntry("identityResolved", "true"); + }); + } + @Test void identityResolverFailureStillProducesLocationEventWithUnknownVin() { XindaPushEventMapper mapperWithFailingIdentity = new XindaPushEventMapper(lookup -> {