Added custom serializer/deserializer logic for perimeter definitions
This commit is contained in:
parent
cc3ecfc027
commit
29934d08bd
@ -622,13 +622,9 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
|
|||||||
Device device = createDevice("GF Device", "sn-geo-1");
|
Device device = createDevice("GF Device", "sn-geo-1");
|
||||||
|
|
||||||
// Allowed zone polygon (square)
|
// Allowed zone polygon (square)
|
||||||
String allowedPolygon = """
|
String allowedPolygon = "[[50.472000, 30.504000], [50.472000, 30.506000], [50.474000, 30.506000], [50.474000, 30.504000]]";
|
||||||
{"type":"POLYGON","polygonsDefinition":"[[50.472000, 30.504000], [50.472000, 30.506000], [50.474000, 30.506000], [50.474000, 30.504000]]"}
|
|
||||||
""";
|
|
||||||
// Restricted zone polygon (square)
|
// Restricted zone polygon (square)
|
||||||
String restrictedPolygon = """
|
String restrictedPolygon = "[[50.475000, 30.510000], [50.475000, 30.512000], [50.477000, 30.512000], [50.477000, 30.510000]]";
|
||||||
{"type":"POLYGON","polygonsDefinition":"[[50.475000, 30.510000], [50.475000, 30.512000], [50.477000, 30.512000], [50.477000, 30.510000]]"}
|
|
||||||
""";
|
|
||||||
|
|
||||||
Asset allowedZoneAsset = createAsset("Allowed Zone", null);
|
Asset allowedZoneAsset = createAsset("Allowed Zone", null);
|
||||||
doPost("/api/plugins/telemetry/ASSET/" + allowedZoneAsset.getUuidId() + "/attributes/" + DataConstants.SERVER_SCOPE,
|
doPost("/api/plugins/telemetry/ASSET/" + allowedZoneAsset.getUuidId() + "/attributes/" + DataConstants.SERVER_SCOPE,
|
||||||
@ -768,9 +764,7 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
|
|||||||
Device device = createDevice("GF Device dyn", "sn-geo-dyn-1");
|
Device device = createDevice("GF Device dyn", "sn-geo-dyn-1");
|
||||||
|
|
||||||
// Allowed Zone A: covers initial point (ENTERED)
|
// Allowed Zone A: covers initial point (ENTERED)
|
||||||
String allowedPolygonA = """
|
String allowedPolygonA = "[[50.472000, 30.504000], [50.472000, 30.506000], [50.474000, 30.506000], [50.474000, 30.504000]]";
|
||||||
{"type":"POLYGON","polygonsDefinition":"[[50.472000, 30.504000], [50.472000, 30.506000], [50.474000, 30.506000], [50.474000, 30.504000]]"}
|
|
||||||
""";
|
|
||||||
|
|
||||||
Asset allowedZoneA = createAsset("Allowed Zone A", null);
|
Asset allowedZoneA = createAsset("Allowed Zone A", null);
|
||||||
doPost("/api/plugins/telemetry/ASSET/" + allowedZoneA.getUuidId() + "/attributes/" + DataConstants.SERVER_SCOPE,
|
doPost("/api/plugins/telemetry/ASSET/" + allowedZoneA.getUuidId() + "/attributes/" + DataConstants.SERVER_SCOPE,
|
||||||
@ -863,9 +857,7 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
|
|||||||
});
|
});
|
||||||
|
|
||||||
// --- Create Allowed Zone B covering the CURRENT location ---
|
// --- Create Allowed Zone B covering the CURRENT location ---
|
||||||
String allowedPolygonB = """
|
String allowedPolygonB = "[[50.475500, 30.510500], [50.475500, 30.511500], [50.476500, 30.511500], [50.476500, 30.510500]]";
|
||||||
{"type":"POLYGON","polygonsDefinition":"[[50.475500, 30.510500], [50.475500, 30.511500], [50.476500, 30.511500], [50.476500, 30.510500]]"}
|
|
||||||
""";
|
|
||||||
|
|
||||||
Asset allowedZoneB = createAsset("Allowed Zone B", null);
|
Asset allowedZoneB = createAsset("Allowed Zone B", null);
|
||||||
doPost("/api/plugins/telemetry/ASSET/" + allowedZoneB.getUuidId() + "/attributes/" + DataConstants.SERVER_SCOPE,
|
doPost("/api/plugins/telemetry/ASSET/" + allowedZoneB.getUuidId() + "/attributes/" + DataConstants.SERVER_SCOPE,
|
||||||
|
|||||||
@ -73,13 +73,11 @@ public class GeofencingCalculatedFieldStateTest {
|
|||||||
private final SingleValueArgumentEntry latitudeArgEntry = new SingleValueArgumentEntry(System.currentTimeMillis() - 10, new DoubleDataEntry("latitude", 50.4730), 145L);
|
private final SingleValueArgumentEntry latitudeArgEntry = new SingleValueArgumentEntry(System.currentTimeMillis() - 10, new DoubleDataEntry("latitude", 50.4730), 145L);
|
||||||
private final SingleValueArgumentEntry longitudeArgEntry = new SingleValueArgumentEntry(System.currentTimeMillis() - 6, new DoubleDataEntry("longitude", 30.5050), 165L);
|
private final SingleValueArgumentEntry longitudeArgEntry = new SingleValueArgumentEntry(System.currentTimeMillis() - 6, new DoubleDataEntry("longitude", 30.5050), 165L);
|
||||||
|
|
||||||
private final JsonDataEntry allowedZoneDataEntry = new JsonDataEntry("zone", """
|
private final JsonDataEntry allowedZoneDataEntry = new JsonDataEntry("zone", "[[50.472000, 30.504000], [50.472000, 30.506000], [50.474000, 30.506000], [50.474000, 30.504000]]");
|
||||||
{"type":"POLYGON","polygonsDefinition":"[[50.472000, 30.504000], [50.472000, 30.506000], [50.474000, 30.506000], [50.474000, 30.504000]]"}""");
|
|
||||||
private final BaseAttributeKvEntry allowedZoneAttributeKvEntry = new BaseAttributeKvEntry(allowedZoneDataEntry, System.currentTimeMillis(), 0L);
|
private final BaseAttributeKvEntry allowedZoneAttributeKvEntry = new BaseAttributeKvEntry(allowedZoneDataEntry, System.currentTimeMillis(), 0L);
|
||||||
private final GeofencingArgumentEntry geofencingAllowedZoneArgEntry = new GeofencingArgumentEntry(Map.of(ZONE_1_ID, allowedZoneAttributeKvEntry));
|
private final GeofencingArgumentEntry geofencingAllowedZoneArgEntry = new GeofencingArgumentEntry(Map.of(ZONE_1_ID, allowedZoneAttributeKvEntry));
|
||||||
|
|
||||||
private final JsonDataEntry restrictedZoneDataEntry = new JsonDataEntry("zone", """
|
private final JsonDataEntry restrictedZoneDataEntry = new JsonDataEntry("zone", "[[50.475000, 30.510000], [50.475000, 30.512000], [50.477000, 30.512000], [50.477000, 30.510000]]");
|
||||||
{"type":"POLYGON","polygonsDefinition":"[[50.475000, 30.510000], [50.475000, 30.512000], [50.477000, 30.512000], [50.477000, 30.510000]]"}""");
|
|
||||||
private final BaseAttributeKvEntry restrictedZoneAttributeKvEntry = new BaseAttributeKvEntry(restrictedZoneDataEntry, System.currentTimeMillis(), 0L);
|
private final BaseAttributeKvEntry restrictedZoneAttributeKvEntry = new BaseAttributeKvEntry(restrictedZoneDataEntry, System.currentTimeMillis(), 0L);
|
||||||
private final GeofencingArgumentEntry geofencingRestrictedZoneArgEntry = new GeofencingArgumentEntry(Map.of(ZONE_2_ID, restrictedZoneAttributeKvEntry));
|
private final GeofencingArgumentEntry geofencingRestrictedZoneArgEntry = new GeofencingArgumentEntry(Map.of(ZONE_2_ID, restrictedZoneAttributeKvEntry));
|
||||||
|
|
||||||
@ -219,6 +217,7 @@ public class GeofencingCalculatedFieldStateTest {
|
|||||||
assertThat(state.isReady()).isFalse();
|
assertThat(state.isReady()).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: test different reporting strategies
|
||||||
@Test
|
@Test
|
||||||
void testPerformCalculation() throws ExecutionException, InterruptedException {
|
void testPerformCalculation() throws ExecutionException, InterruptedException {
|
||||||
state.arguments = new HashMap<>(Map.of(
|
state.arguments = new HashMap<>(Map.of(
|
||||||
@ -241,8 +240,9 @@ public class GeofencingCalculatedFieldStateTest {
|
|||||||
assertThat(result.getScope()).isEqualTo(output.getScope());
|
assertThat(result.getScope()).isEqualTo(output.getScope());
|
||||||
assertThat(result.getResult()).isEqualTo(
|
assertThat(result.getResult()).isEqualTo(
|
||||||
JacksonUtil.newObjectNode()
|
JacksonUtil.newObjectNode()
|
||||||
.put("allowedZoneEvent", "ENTERED")
|
.put("allowedZonesEvent", "ENTERED")
|
||||||
.put("restrictedZoneEvent", "OUTSIDE")
|
.put("allowedZonesStatus", "INSIDE")
|
||||||
|
.put("restrictedZonesStatus", "OUTSIDE")
|
||||||
);
|
);
|
||||||
|
|
||||||
SingleValueArgumentEntry newLatitude = new SingleValueArgumentEntry(System.currentTimeMillis(), new DoubleDataEntry("latitude", 50.4760), 146L);
|
SingleValueArgumentEntry newLatitude = new SingleValueArgumentEntry(System.currentTimeMillis(), new DoubleDataEntry("latitude", 50.4760), 146L);
|
||||||
@ -258,8 +258,10 @@ public class GeofencingCalculatedFieldStateTest {
|
|||||||
assertThat(result2.getScope()).isEqualTo(output.getScope());
|
assertThat(result2.getScope()).isEqualTo(output.getScope());
|
||||||
assertThat(result2.getResult()).isEqualTo(
|
assertThat(result2.getResult()).isEqualTo(
|
||||||
JacksonUtil.newObjectNode()
|
JacksonUtil.newObjectNode()
|
||||||
.put("allowedZoneEvent", "LEFT")
|
.put("allowedZonesEvent", "LEFT")
|
||||||
.put("restrictedZoneEvent", "ENTERED")
|
.put("allowedZonesStatus", "OUTSIDE")
|
||||||
|
.put("restrictedZonesEvent", "ENTERED")
|
||||||
|
.put("restrictedZonesStatus", "INSIDE")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -36,12 +36,10 @@ public class GeofencingValueArgumentEntryTest {
|
|||||||
private final AssetId ZONE_1_ID = new AssetId(UUID.fromString("c0e3031c-7df1-45e4-9590-cfd621a4d714"));
|
private final AssetId ZONE_1_ID = new AssetId(UUID.fromString("c0e3031c-7df1-45e4-9590-cfd621a4d714"));
|
||||||
private final AssetId ZONE_2_ID = new AssetId(UUID.fromString("e7da6200-2096-4038-a343-ade9ea4fa3e4"));
|
private final AssetId ZONE_2_ID = new AssetId(UUID.fromString("e7da6200-2096-4038-a343-ade9ea4fa3e4"));
|
||||||
|
|
||||||
private final JsonDataEntry allowedZoneDataEntry = new JsonDataEntry("zone", """
|
private final JsonDataEntry allowedZoneDataEntry = new JsonDataEntry("zone", "[[50.472000, 30.504000], [50.472000, 30.506000], [50.474000, 30.506000], [50.474000, 30.504000]]");
|
||||||
{"type":"POLYGON","polygonsDefinition":"[[50.472000, 30.504000], [50.472000, 30.506000], [50.474000, 30.506000], [50.474000, 30.504000]]"}""");
|
|
||||||
private final BaseAttributeKvEntry allowedZoneAttributeKvEntry = new BaseAttributeKvEntry(allowedZoneDataEntry, 363L, 155L);
|
private final BaseAttributeKvEntry allowedZoneAttributeKvEntry = new BaseAttributeKvEntry(allowedZoneDataEntry, 363L, 155L);
|
||||||
|
|
||||||
private final JsonDataEntry restrictedZoneDataEntry = new JsonDataEntry("zone", """
|
private final JsonDataEntry restrictedZoneDataEntry = new JsonDataEntry("zone", "[[50.475000, 30.510000], [50.475000, 30.512000], [50.477000, 30.512000], [50.477000, 30.510000]]");
|
||||||
{"type":"POLYGON","polygonsDefinition":"[[50.475000, 30.510000], [50.475000, 30.512000], [50.477000, 30.512000], [50.477000, 30.510000]]"}""");
|
|
||||||
private final BaseAttributeKvEntry restrictedZoneAttributeKvEntry = new BaseAttributeKvEntry(restrictedZoneDataEntry, 363L, 155L);
|
private final BaseAttributeKvEntry restrictedZoneAttributeKvEntry = new BaseAttributeKvEntry(restrictedZoneDataEntry, 363L, 155L);
|
||||||
|
|
||||||
private GeofencingArgumentEntry entry;
|
private GeofencingArgumentEntry entry;
|
||||||
@ -72,8 +70,7 @@ public class GeofencingValueArgumentEntryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testUpdateEntryWithTheSameTs() {
|
void testUpdateEntryWithTheSameTs() {
|
||||||
BaseAttributeKvEntry differentValueSameTs = new BaseAttributeKvEntry(new JsonDataEntry("zone", """
|
BaseAttributeKvEntry differentValueSameTs = new BaseAttributeKvEntry(new JsonDataEntry("zone", "[[50.472001, 30.504001], [50.472001, 30.506001], [50.474001, 30.506001], [50.474001, 30.504001]]"), 363L, 156L);
|
||||||
{"type":"POLYGON","polygonsDefinition":"[[50.472001, 30.504001], [50.472001, 30.506001], [50.474001, 30.506001], [50.474001, 30.504001]]"}"""), 363L, 156L);
|
|
||||||
var updated = new GeofencingArgumentEntry(Map.of(ZONE_1_ID, differentValueSameTs, ZONE_2_ID, restrictedZoneAttributeKvEntry));
|
var updated = new GeofencingArgumentEntry(Map.of(ZONE_1_ID, differentValueSameTs, ZONE_2_ID, restrictedZoneAttributeKvEntry));
|
||||||
assertThat(entry.updateEntry(updated)).isFalse();
|
assertThat(entry.updateEntry(updated)).isFalse();
|
||||||
}
|
}
|
||||||
@ -81,8 +78,7 @@ public class GeofencingValueArgumentEntryTest {
|
|||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
void testUpdateEntryWhenNewVersionIsNull() {
|
void testUpdateEntryWhenNewVersionIsNull() {
|
||||||
BaseAttributeKvEntry differentValueNewVersionIsNull = new BaseAttributeKvEntry(new JsonDataEntry("zone", """
|
BaseAttributeKvEntry differentValueNewVersionIsNull = new BaseAttributeKvEntry(new JsonDataEntry("zone", "[[50.472001, 30.504001], [50.472001, 30.506001], [50.474001, 30.506001], [50.474001, 30.504001]]"), 364L, null);
|
||||||
{"type":"POLYGON","polygonsDefinition":"[[50.472001, 30.504001], [50.472001, 30.506001], [50.474001, 30.506001], [50.474001, 30.504001]]"}"""), 364L, null);
|
|
||||||
var updated = new GeofencingArgumentEntry(Map.of(ZONE_1_ID, differentValueNewVersionIsNull, ZONE_2_ID, restrictedZoneAttributeKvEntry));
|
var updated = new GeofencingArgumentEntry(Map.of(ZONE_1_ID, differentValueNewVersionIsNull, ZONE_2_ID, restrictedZoneAttributeKvEntry));
|
||||||
|
|
||||||
assertThat(entry.updateEntry(updated)).isTrue();
|
assertThat(entry.updateEntry(updated)).isTrue();
|
||||||
@ -104,8 +100,7 @@ public class GeofencingValueArgumentEntryTest {
|
|||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
void testUpdateEntryWhenNewVersionIsGreaterThanCurrent() {
|
void testUpdateEntryWhenNewVersionIsGreaterThanCurrent() {
|
||||||
BaseAttributeKvEntry differentValueNewVersionIsSet = new BaseAttributeKvEntry(new JsonDataEntry("zone", """
|
BaseAttributeKvEntry differentValueNewVersionIsSet = new BaseAttributeKvEntry(new JsonDataEntry("zone", "[[50.472001, 30.504001], [50.472001, 30.506001], [50.474001, 30.506001], [50.474001, 30.504001]]"), 364L, 156L);
|
||||||
{"type":"POLYGON","polygonsDefinition":"[[50.472001, 30.504001], [50.472001, 30.506001], [50.474001, 30.506001], [50.474001, 30.504001]]"}"""), 364L, 156L);
|
|
||||||
var updated = new GeofencingArgumentEntry(Map.of(ZONE_1_ID, differentValueNewVersionIsSet, ZONE_2_ID, restrictedZoneAttributeKvEntry));
|
var updated = new GeofencingArgumentEntry(Map.of(ZONE_1_ID, differentValueNewVersionIsSet, ZONE_2_ID, restrictedZoneAttributeKvEntry));
|
||||||
|
|
||||||
assertThat(entry.updateEntry(updated)).isTrue();
|
assertThat(entry.updateEntry(updated)).isTrue();
|
||||||
@ -126,8 +121,7 @@ public class GeofencingValueArgumentEntryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testUpdateEntryWhenNewVersionIsLessThanCurrent() {
|
void testUpdateEntryWhenNewVersionIsLessThanCurrent() {
|
||||||
BaseAttributeKvEntry differentValueNewVersionIsSet = new BaseAttributeKvEntry(new JsonDataEntry("zone", """
|
BaseAttributeKvEntry differentValueNewVersionIsSet = new BaseAttributeKvEntry(new JsonDataEntry("zone", "[[50.472001, 30.504001], [50.472001, 30.506001], [50.474001, 30.506001], [50.474001, 30.504001]]"), 364L, 154L);
|
||||||
{"type":"POLYGON","polygonsDefinition":"[[50.472001, 30.504001], [50.472001, 30.506001], [50.474001, 30.506001], [50.474001, 30.504001]]"}"""), 364L, 154L);
|
|
||||||
var updated = new GeofencingArgumentEntry(Map.of(ZONE_1_ID, differentValueNewVersionIsSet, ZONE_2_ID, restrictedZoneAttributeKvEntry));
|
var updated = new GeofencingArgumentEntry(Map.of(ZONE_1_ID, differentValueNewVersionIsSet, ZONE_2_ID, restrictedZoneAttributeKvEntry));
|
||||||
|
|
||||||
assertThat(entry.updateEntry(updated)).isFalse();
|
assertThat(entry.updateEntry(updated)).isFalse();
|
||||||
@ -152,8 +146,7 @@ public class GeofencingValueArgumentEntryTest {
|
|||||||
@Test
|
@Test
|
||||||
void testUpdateEntryWithNewZone() {
|
void testUpdateEntryWithNewZone() {
|
||||||
final AssetId NEW_ZONE_ID = new AssetId(UUID.fromString("a3eacf1a-6af3-4e9f-87c4-502bb25c7dc3"));
|
final AssetId NEW_ZONE_ID = new AssetId(UUID.fromString("a3eacf1a-6af3-4e9f-87c4-502bb25c7dc3"));
|
||||||
BaseAttributeKvEntry newZone = new BaseAttributeKvEntry(new JsonDataEntry("zone", """
|
BaseAttributeKvEntry newZone = new BaseAttributeKvEntry(new JsonDataEntry("zone", "[[50.472001, 30.504001], [50.472001, 30.506001], [50.474001, 30.506001], [50.474001, 30.504001]]"), 364L, 156L);
|
||||||
{"type":"POLYGON","polygonsDefinition":"[[50.472001, 30.504001], [50.472001, 30.506001], [50.474001, 30.506001], [50.474001, 30.504001]]"}"""), 364L, 156L);
|
|
||||||
var updated = new GeofencingArgumentEntry(Map.of(ZONE_1_ID, allowedZoneAttributeKvEntry, ZONE_2_ID, restrictedZoneAttributeKvEntry, NEW_ZONE_ID, newZone));
|
var updated = new GeofencingArgumentEntry(Map.of(ZONE_1_ID, allowedZoneAttributeKvEntry, ZONE_2_ID, restrictedZoneAttributeKvEntry, NEW_ZONE_ID, newZone));
|
||||||
assertThat(entry.updateEntry(updated)).isTrue();
|
assertThat(entry.updateEntry(updated)).isTrue();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,9 +38,7 @@ public class GeofencingZoneStateTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
String POLYGON = """
|
String POLYGON = "[[50.472000, 30.504000], [50.472000, 30.506000], [50.474000, 30.506000], [50.474000, 30.504000]]";
|
||||||
{"type":"POLYGON","polygonsDefinition":"[[50.472000, 30.504000], [50.472000, 30.506000], [50.474000, 30.506000], [50.474000, 30.504000]]"}
|
|
||||||
""";
|
|
||||||
state = new GeofencingZoneState(ZONE_ID, new BaseAttributeKvEntry(new JsonDataEntry("zone", POLYGON), 100L, 1L));
|
state = new GeofencingZoneState(ZONE_ID, new BaseAttributeKvEntry(new JsonDataEntry("zone", POLYGON), 100L, 1L));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -70,8 +70,8 @@ class CalculatedFieldUtilsTest {
|
|||||||
AssetId z1 = new AssetId(zoneId1);
|
AssetId z1 = new AssetId(zoneId1);
|
||||||
AssetId z2 = new AssetId(zoneId2);
|
AssetId z2 = new AssetId(zoneId2);
|
||||||
|
|
||||||
JsonDataEntry zone1 = new JsonDataEntry("zone", "{\"type\":\"POLYGON\",\"polygonsDefinition\":\"[[50.472000, 30.504000], [50.472000, 30.506000], [50.474000, 30.506000], [50.474000, 30.504000]]\"}");
|
JsonDataEntry zone1 = new JsonDataEntry("zone", "[[50.472000, 30.504000], [50.472000, 30.506000], [50.474000, 30.506000], [50.474000, 30.504000]]");
|
||||||
JsonDataEntry zone2 = new JsonDataEntry("zone", "{\"type\":\"POLYGON\",\"polygonsDefinition\":\"[[50.475000, 30.510000], [50.475000, 30.512000], [50.477000, 30.512000], [50.477000, 30.510000]]\"}");
|
JsonDataEntry zone2 = new JsonDataEntry("zone", "[[50.475000, 30.510000], [50.475000, 30.512000], [50.477000, 30.512000], [50.477000, 30.510000]]");
|
||||||
|
|
||||||
BaseAttributeKvEntry zone1PerimeterAttribute = new BaseAttributeKvEntry(zone1, System.currentTimeMillis(), 0L);
|
BaseAttributeKvEntry zone1PerimeterAttribute = new BaseAttributeKvEntry(zone1, System.currentTimeMillis(), 0L);
|
||||||
BaseAttributeKvEntry zone2PerimeterAttribute = new BaseAttributeKvEntry(zone2, System.currentTimeMillis(), 0L);
|
BaseAttributeKvEntry zone2PerimeterAttribute = new BaseAttributeKvEntry(zone2, System.currentTimeMillis(), 0L);
|
||||||
|
|||||||
@ -83,7 +83,7 @@ public class GeofencingCalculatedFieldConfiguration extends BaseCalculatedFieldC
|
|||||||
|
|
||||||
private void validateZoneGroupConfigurations(Map<String, Argument> zoneGroupsArguments) {
|
private void validateZoneGroupConfigurations(Map<String, Argument> zoneGroupsArguments) {
|
||||||
if (zoneGroupReportStrategies == null || zoneGroupReportStrategies.isEmpty()) {
|
if (zoneGroupReportStrategies == null || zoneGroupReportStrategies.isEmpty()) {
|
||||||
throw new IllegalArgumentException("Zone groups configuration should be specified!");
|
throw new IllegalArgumentException("Zone groups reporting strategies should be specified!");
|
||||||
}
|
}
|
||||||
zoneGroupsArguments.forEach((zoneGroupName, zoneGroupArgument) -> {
|
zoneGroupsArguments.forEach((zoneGroupName, zoneGroupArgument) -> {
|
||||||
GeofencingReportStrategy geofencingReportStrategy = zoneGroupReportStrategies.get(zoneGroupName);
|
GeofencingReportStrategy geofencingReportStrategy = zoneGroupReportStrategies.get(zoneGroupName);
|
||||||
|
|||||||
@ -251,7 +251,7 @@ public class GeofencingCalculatedFieldConfigurationTest {
|
|||||||
|
|
||||||
assertThatThrownBy(cfg::validate)
|
assertThatThrownBy(cfg::validate)
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Zone groups configuration should be specified!");
|
.hasMessage("Zone groups reporting strategies should be specified!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@ -20,10 +20,9 @@ import lombok.Data;
|
|||||||
@Data
|
@Data
|
||||||
public class CirclePerimeterDefinition implements PerimeterDefinition {
|
public class CirclePerimeterDefinition implements PerimeterDefinition {
|
||||||
|
|
||||||
private Double centerLatitude;
|
private final Double latitude;
|
||||||
private Double centerLongitude;
|
private final Double longitude;
|
||||||
private Double range;
|
private final Double radius;
|
||||||
private RangeUnit rangeUnit;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PerimeterType getType() {
|
public PerimeterType getType() {
|
||||||
@ -32,9 +31,8 @@ public class CirclePerimeterDefinition implements PerimeterDefinition {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkMatches(Coordinates entityCoordinates) {
|
public boolean checkMatches(Coordinates entityCoordinates) {
|
||||||
Coordinates perimeterCoordinates = new Coordinates(centerLatitude, centerLongitude);
|
Coordinates perimeterCoordinates = new Coordinates(latitude, longitude);
|
||||||
return range > GeoUtil.distance(entityCoordinates, perimeterCoordinates, rangeUnit);
|
return radius > GeoUtil.distance(entityCoordinates, perimeterCoordinates, RangeUnit.METER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,19 +17,14 @@ package org.thingsboard.common.util.geo;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
@JsonTypeInfo(
|
|
||||||
use = JsonTypeInfo.Id.NAME,
|
|
||||||
include = JsonTypeInfo.As.PROPERTY,
|
|
||||||
property = "type")
|
|
||||||
@JsonSubTypes({
|
|
||||||
@JsonSubTypes.Type(value = PolygonPerimeterDefinition.class, name = "POLYGON"),
|
|
||||||
@JsonSubTypes.Type(value = CirclePerimeterDefinition.class, name = "CIRCLE")})
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@JsonDeserialize(using = PerimeterDefinitionDeserializer.class)
|
||||||
|
@JsonSerialize(using = PerimeterDefinitionSerializer.class)
|
||||||
public interface PerimeterDefinition extends Serializable {
|
public interface PerimeterDefinition extends Serializable {
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
|
|||||||
@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2025 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.common.util.geo;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.core.ObjectCodec;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class PerimeterDefinitionDeserializer extends JsonDeserializer<PerimeterDefinition> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PerimeterDefinition deserialize(JsonParser p, DeserializationContext ctx) throws IOException {
|
||||||
|
ObjectCodec codec = p.getCodec();
|
||||||
|
JsonNode node = codec.readTree(p);
|
||||||
|
|
||||||
|
if (node.isObject()) {
|
||||||
|
double latitude = node.get("latitude").asDouble();
|
||||||
|
double longitude = node.get("longitude").asDouble();
|
||||||
|
double radius = node.get("radius").asDouble();
|
||||||
|
return new CirclePerimeterDefinition(latitude, longitude, radius);
|
||||||
|
}
|
||||||
|
if (node.isArray()) {
|
||||||
|
ObjectMapper mapper = (ObjectMapper) p.getCodec();
|
||||||
|
String polygonStrDefinition = mapper.writeValueAsString(node);
|
||||||
|
return new PolygonPerimeterDefinition(polygonStrDefinition);
|
||||||
|
}
|
||||||
|
throw new IOException("Failed to deserialize PerimeterDefinition from node: " + node);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2025 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.common.util.geo;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||||
|
import org.thingsboard.server.common.data.StringUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class PerimeterDefinitionSerializer extends JsonSerializer<PerimeterDefinition> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(PerimeterDefinition value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||||
|
if (value instanceof CirclePerimeterDefinition c) {
|
||||||
|
gen.writeStartObject();
|
||||||
|
gen.writeNumberField("latitude", c.getLatitude());
|
||||||
|
gen.writeNumberField("longitude", c.getLongitude());
|
||||||
|
gen.writeNumberField("radius", c.getRadius());
|
||||||
|
gen.writeEndObject();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (value instanceof PolygonPerimeterDefinition p) {
|
||||||
|
String raw = p.getPolygonDefinition();
|
||||||
|
if (StringUtils.isBlank(raw)) {
|
||||||
|
throw new IOException("Failed to serialize PolygonPerimeterDefinition with blank: " + value);
|
||||||
|
}
|
||||||
|
ObjectMapper mapper = (ObjectMapper) gen.getCodec();
|
||||||
|
gen.writeTree(mapper.readTree(raw));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new IOException("Failed to serialize PerimeterDefinition from value: " + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,7 +20,7 @@ import lombok.Data;
|
|||||||
@Data
|
@Data
|
||||||
public class PolygonPerimeterDefinition implements PerimeterDefinition {
|
public class PolygonPerimeterDefinition implements PerimeterDefinition {
|
||||||
|
|
||||||
private String polygonsDefinition;
|
private final String polygonDefinition;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PerimeterType getType() {
|
public PerimeterType getType() {
|
||||||
@ -29,7 +29,7 @@ public class PolygonPerimeterDefinition implements PerimeterDefinition {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkMatches(Coordinates entityCoordinates) {
|
public boolean checkMatches(Coordinates entityCoordinates) {
|
||||||
return GeoUtil.contains(polygonsDefinition, entityCoordinates);
|
return GeoUtil.contains(polygonDefinition, entityCoordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2025 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.common.util.geo;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.thingsboard.common.util.JacksonUtil;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
public class PerimeterDefinitionDeserializerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldDeserializeCircle() {
|
||||||
|
String json = """
|
||||||
|
{"latitude":50.45,"longitude":30.52,"radius":100.0}""";
|
||||||
|
|
||||||
|
PerimeterDefinition def = JacksonUtil.fromString(json, PerimeterDefinition.class);
|
||||||
|
|
||||||
|
assertThat(def).isNotNull().isInstanceOf(CirclePerimeterDefinition.class);
|
||||||
|
|
||||||
|
CirclePerimeterDefinition circle = (CirclePerimeterDefinition) def;
|
||||||
|
assertThat(circle.getLatitude()).isEqualTo(50.45);
|
||||||
|
assertThat(circle.getLongitude()).isEqualTo(30.52);
|
||||||
|
assertThat(circle.getRadius()).isEqualTo(100.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldDeserializePolygon() {
|
||||||
|
String json = "[[50.45,30.52],[50.46,30.53],[50.44,30.54]]";
|
||||||
|
|
||||||
|
PerimeterDefinition def = JacksonUtil.fromString(json, PerimeterDefinition.class);
|
||||||
|
|
||||||
|
assertThat(def).isInstanceOf(PolygonPerimeterDefinition.class);
|
||||||
|
PolygonPerimeterDefinition poly = (PolygonPerimeterDefinition) def;
|
||||||
|
assertThat(poly.getPolygonDefinition()).isEqualTo(json);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2025 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.common.util.geo;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.thingsboard.common.util.JacksonUtil;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
public class PerimeterDefinitionSerializerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldSerializeCircle() {
|
||||||
|
PerimeterDefinition circle = new CirclePerimeterDefinition(50.45, 30.52, 120.0);
|
||||||
|
|
||||||
|
String json = JacksonUtil.writeValueAsString(circle);
|
||||||
|
|
||||||
|
JsonNode actual = JacksonUtil.toJsonNode(json);
|
||||||
|
assertThat(actual.get("latitude").asDouble()).isEqualTo(50.45);
|
||||||
|
assertThat(actual.get("longitude").asDouble()).isEqualTo(30.52);
|
||||||
|
assertThat(actual.get("radius").asDouble()).isEqualTo(120.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldSerializePolygon() throws Exception {
|
||||||
|
String rawArray = "[[50.45,30.52],[50.46,30.53],[50.44,30.54]]";
|
||||||
|
PerimeterDefinition polygon = new PolygonPerimeterDefinition(rawArray);
|
||||||
|
|
||||||
|
String json = JacksonUtil.writeValueAsString(polygon);
|
||||||
|
|
||||||
|
JsonNode actual = JacksonUtil.toJsonNode(json);
|
||||||
|
JsonNode expected = JacksonUtil.toJsonNode(rawArray);
|
||||||
|
assertThat(actual).isEqualTo(expected);
|
||||||
|
assertThat(actual.isArray()).isTrue();
|
||||||
|
assertThat(actual.size()).isEqualTo(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user