fix: resolve xinda vehicles by mysql plate binding
This commit is contained in:
@@ -131,12 +131,7 @@ public final class MySqlVehicleIdentityService implements VehicleIdentityResolve
|
|||||||
PreparedStatement statement = connection.prepareStatement(sql);
|
PreparedStatement statement = connection.prepareStatement(sql);
|
||||||
ResultSet resultSet = statement.executeQuery()) {
|
ResultSet resultSet = statement.executeQuery()) {
|
||||||
while (resultSet.next()) {
|
while (resultSet.next()) {
|
||||||
loaded.bind(new VehicleIdentityBinding(
|
bindGlobalPlate(loaded, resultSet.getString("vin"), resultSet.getString("plate"));
|
||||||
ProtocolId.JT808,
|
|
||||||
resultSet.getString("vin"),
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
resultSet.getString("plate")));
|
|
||||||
}
|
}
|
||||||
loadRegistrationIndex(loaded, connection);
|
loadRegistrationIndex(loaded, connection);
|
||||||
return loaded;
|
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 {
|
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 "
|
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 "
|
+ "JOIN " + table + " b ON b.plate = r.plate "
|
||||||
|
|||||||
@@ -83,6 +83,22 @@ class MySqlVehicleIdentityServiceTest {
|
|||||||
assertThat(jdbc.lookupSelects).isZero();
|
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
|
@Test
|
||||||
void refreshLoadsExternallyInsertedBindingWithoutPerFrameDatabaseLookup() {
|
void refreshLoadsExternallyInsertedBindingWithoutPerFrameDatabaseLookup() {
|
||||||
RecordingIdentityJdbc jdbc = new RecordingIdentityJdbc();
|
RecordingIdentityJdbc jdbc = new RecordingIdentityJdbc();
|
||||||
|
|||||||
@@ -143,9 +143,9 @@ public final class XindaPushEventMapper implements EventMapper<XindaPushMessage>
|
|||||||
return IdentityResolution.ok(identityResolver.resolve(new VehicleIdentityLookup(
|
return IdentityResolution.ok(identityResolver.resolve(new VehicleIdentityLookup(
|
||||||
ProtocolId.XINDA_PUSH,
|
ProtocolId.XINDA_PUSH,
|
||||||
firstNonBlank(json, "vin"),
|
firstNonBlank(json, "vin"),
|
||||||
firstNonBlank(json, "sim", "phone", "mobile"),
|
firstNonBlank(json, "sim", "phone", "mobile", "simCode"),
|
||||||
firstNonBlank(json, "deviceId", "terminalId", "imei"),
|
firstNonBlank(json, "deviceId", "terminalId", "imei", "tmnKey", "tmnCode"),
|
||||||
firstNonBlank(json, "plateNo", "carNo"))));
|
plateNo(json))));
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
return new IdentityResolution(
|
return new IdentityResolution(
|
||||||
new VehicleIdentity("unknown", false, VehicleIdentitySource.UNKNOWN),
|
new VehicleIdentity("unknown", false, VehicleIdentitySource.UNKNOWN),
|
||||||
@@ -172,9 +172,9 @@ public final class XindaPushEventMapper implements EventMapper<XindaPushMessage>
|
|||||||
out.put("rawJson", message.json());
|
out.put("rawJson", message.json());
|
||||||
out.put("vin", normalizedVin(identity));
|
out.put("vin", normalizedVin(identity));
|
||||||
out.put("externalVin", firstNonBlank(json, "vin"));
|
out.put("externalVin", firstNonBlank(json, "vin"));
|
||||||
out.put("phone", firstNonBlank(json, "sim", "phone", "mobile"));
|
out.put("phone", firstNonBlank(json, "sim", "phone", "mobile", "simCode"));
|
||||||
out.put("deviceId", firstNonBlank(json, "deviceId", "terminalId", "imei"));
|
out.put("deviceId", firstNonBlank(json, "deviceId", "terminalId", "imei", "tmnKey", "tmnCode"));
|
||||||
out.put("plateNo", firstNonBlank(json, "plateNo", "carNo"));
|
out.put("plateNo", plateNo(json));
|
||||||
out.put("identityResolved", Boolean.toString(identity.identity().resolved()));
|
out.put("identityResolved", Boolean.toString(identity.identity().resolved()));
|
||||||
out.put("identitySource", identity.identity().source().name());
|
out.put("identitySource", identity.identity().source().name());
|
||||||
if (identity.errorMessage() != null) {
|
if (identity.errorMessage() != null) {
|
||||||
@@ -243,6 +243,10 @@ public final class XindaPushEventMapper implements EventMapper<XindaPushMessage>
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String plateNo(JSONObject node) {
|
||||||
|
return firstNonBlank(node, "plateNo", "carNo", "carName");
|
||||||
|
}
|
||||||
|
|
||||||
private static double asDouble(JSONObject node, String... keys) {
|
private static double asDouble(JSONObject node, String... keys) {
|
||||||
Double value = optionalDouble(node, keys);
|
Double value = optionalDouble(node, keys);
|
||||||
return value == null ? 0.0 : value;
|
return value == null ? 0.0 : value;
|
||||||
|
|||||||
@@ -113,6 +113,27 @@ class XindaPushEventMapperTest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void resolvesVehicleIdentityByCarNamePlateFromXindaPayload() {
|
||||||
|
identity.bind(new VehicleIdentityBinding(
|
||||||
|
ProtocolId.XINDA_PUSH, "LNVIN000000000203", "", "", "浙F00780F"));
|
||||||
|
|
||||||
|
List<VehicleEvent> 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
|
@Test
|
||||||
void identityResolverFailureStillProducesLocationEventWithUnknownVin() {
|
void identityResolverFailureStillProducesLocationEventWithUnknownVin() {
|
||||||
XindaPushEventMapper mapperWithFailingIdentity = new XindaPushEventMapper(lookup -> {
|
XindaPushEventMapper mapperWithFailingIdentity = new XindaPushEventMapper(lookup -> {
|
||||||
|
|||||||
Reference in New Issue
Block a user