|
@@ -7,6 +7,8 @@ import cz.senslog.telemetry.database.domain.UnitLocation;
|
|
|
import cz.senslog.telemetry.database.domain.UnitTelemetry;
|
|
import cz.senslog.telemetry.database.domain.UnitTelemetry;
|
|
|
import cz.senslog.telemetry.database.repository.SensLogRepository;
|
|
import cz.senslog.telemetry.database.repository.SensLogRepository;
|
|
|
import cz.senslog.telemetry.database.domain.Filter;
|
|
import cz.senslog.telemetry.database.domain.Filter;
|
|
|
|
|
+import cz.senslog.telemetry.database.validation.UnitTelemetryValidation;
|
|
|
|
|
+import cz.senslog.telemetry.utils.FluentInvoke;
|
|
|
import cz.senslog.telemetry.utils.TernaryCondition;
|
|
import cz.senslog.telemetry.utils.TernaryCondition;
|
|
|
import io.vertx.core.http.HttpServerRequest;
|
|
import io.vertx.core.http.HttpServerRequest;
|
|
|
import io.vertx.core.json.JsonArray;
|
|
import io.vertx.core.json.JsonArray;
|
|
@@ -20,47 +22,23 @@ import java.util.*;
|
|
|
import java.util.function.*;
|
|
import java.util.function.*;
|
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
-import static cz.senslog.telemetry.server.ws.OpenAPIHandler.ContentType.GEOJSON;
|
|
|
|
|
-import static cz.senslog.telemetry.server.ws.OpenAPIHandler.ContentType.JSON;
|
|
|
|
|
|
|
+import static cz.senslog.telemetry.database.validation.UnitTelemetryValidation.telemetriesWithinCampaign;
|
|
|
|
|
+import static cz.senslog.telemetry.server.ws.ContentType.GEOJSON;
|
|
|
|
|
+import static cz.senslog.telemetry.server.ws.ContentType.JSON;
|
|
|
|
|
+import static cz.senslog.telemetry.utils.ComparisonOperators.*;
|
|
|
|
|
+import static cz.senslog.telemetry.utils.FluentInvoke.fluentlyOf;
|
|
|
|
|
+import static cz.senslog.telemetry.utils.TernaryCondition.ternaryIf;
|
|
|
import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE;
|
|
import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE;
|
|
|
import static java.lang.Boolean.parseBoolean;
|
|
import static java.lang.Boolean.parseBoolean;
|
|
|
import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME;
|
|
import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME;
|
|
|
import static java.util.Collections.emptyList;
|
|
import static java.util.Collections.emptyList;
|
|
|
|
|
+import static java.util.Comparator.comparing;
|
|
|
import static java.util.Optional.ofNullable;
|
|
import static java.util.Optional.ofNullable;
|
|
|
import static java.util.stream.Collectors.groupingBy;
|
|
import static java.util.stream.Collectors.groupingBy;
|
|
|
import static java.util.stream.Collectors.toList;
|
|
import static java.util.stream.Collectors.toList;
|
|
|
|
|
|
|
|
public class OpenAPIHandler {
|
|
public class OpenAPIHandler {
|
|
|
|
|
|
|
|
- protected enum ContentType {
|
|
|
|
|
- JSON ("application/json"),
|
|
|
|
|
- GEOJSON ("application/geo+json")
|
|
|
|
|
- ;
|
|
|
|
|
-
|
|
|
|
|
- private final String contentType;
|
|
|
|
|
-
|
|
|
|
|
- ContentType(String contentType) {
|
|
|
|
|
- this.contentType = contentType;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public static ContentType of(String format) {
|
|
|
|
|
- return valueOf(format.toUpperCase());
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public static ContentType ofType(String contentType) {
|
|
|
|
|
- for (ContentType value : values()) {
|
|
|
|
|
- if (value.contentType.equalsIgnoreCase(contentType)) {
|
|
|
|
|
- return value;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- throw new IllegalArgumentException(String.format("No enum constant %s for the type '%s'.", ContentType.class.getName(), contentType));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public String contentType() {
|
|
|
|
|
- return contentType;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
private static final int DEFAULT_MAX_DATA_LIMIT = 500;
|
|
private static final int DEFAULT_MAX_DATA_LIMIT = 500;
|
|
|
private static final ZoneId DEFAULT_ZONE_ID = ZoneId.of("UTC");
|
|
private static final ZoneId DEFAULT_ZONE_ID = ZoneId.of("UTC");
|
|
|
private static final boolean DEFAULT_NAVIGATION_LINKS = true;
|
|
private static final boolean DEFAULT_NAVIGATION_LINKS = true;
|
|
@@ -1544,49 +1522,56 @@ public class OpenAPIHandler {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public void campaignIdUnitsObservationsPOST(RoutingContext rc) {
|
|
public void campaignIdUnitsObservationsPOST(RoutingContext rc) {
|
|
|
|
|
+ long campaignId = Long.parseLong(rc.pathParam("campaignId"));
|
|
|
|
|
+
|
|
|
switch (ContentType.ofType(rc.request().getHeader(CONTENT_TYPE))) {
|
|
switch (ContentType.ofType(rc.request().getHeader(CONTENT_TYPE))) {
|
|
|
- case JSON -> Optional.of(rc.body().asJsonArray()).map(jsonArray -> jsonArray.stream().filter(JsonObject.class::isInstance).map(JsonObject.class::cast)
|
|
|
|
|
- .map(f -> UnitTelemetry.of(
|
|
|
|
|
- f.getLong("unitId"),
|
|
|
|
|
- OffsetDateTime.parse(f.getString("timestamp")),
|
|
|
|
|
- Location.of(
|
|
|
|
|
- f.getJsonObject("location").getFloat("longitude"),
|
|
|
|
|
- f.getJsonObject("location").getFloat("latitude"),
|
|
|
|
|
- f.getJsonObject("location").getFloat("altitude")
|
|
|
|
|
- ),
|
|
|
|
|
- f.getInteger("speed"),
|
|
|
|
|
- f.getJsonObject("observedValues")
|
|
|
|
|
- )).collect(toList()))
|
|
|
|
|
- .ifPresent(telemetries -> repo.saveAllTelemetry(telemetries)
|
|
|
|
|
- .onSuccess(count -> rc.response()
|
|
|
|
|
- .end(JsonObject.of(
|
|
|
|
|
- "saved", count,
|
|
|
|
|
- "errors", telemetries.size() - count
|
|
|
|
|
- ).encode()))
|
|
|
|
|
- .onFailure(rc::fail)
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ case JSON -> Optional.of(rc.body().asJsonArray())
|
|
|
|
|
+ .map(jsonArray -> jsonArray.stream().filter(JsonObject.class::isInstance).map(JsonObject.class::cast)
|
|
|
|
|
+ .map(f -> UnitTelemetry.of(
|
|
|
|
|
+ f.getLong("unitId"),
|
|
|
|
|
+ OffsetDateTime.parse(f.getString("timestamp")),
|
|
|
|
|
+ Location.of(
|
|
|
|
|
+ f.getJsonObject("location").getFloat("longitude"),
|
|
|
|
|
+ f.getJsonObject("location").getFloat("latitude"),
|
|
|
|
|
+ f.getJsonObject("location").getFloat("altitude")
|
|
|
|
|
+ ),
|
|
|
|
|
+ f.getInteger("speed"),
|
|
|
|
|
+ f.getJsonObject("observedValues")
|
|
|
|
|
+ )).sorted(comparing(UnitTelemetry::getTimestamp)).collect(toList()))
|
|
|
|
|
+ .ifPresent(orgTels -> repo.findCampaignById(campaignId)
|
|
|
|
|
+ .onSuccess(campaign -> fluentlyOf(telemetriesWithinCampaign(campaign, orgTels))
|
|
|
|
|
+ .then(flTels -> repo.saveAllTelemetry(flTels)
|
|
|
|
|
+ .onSuccess(count -> rc.response().end(JsonObject.of(
|
|
|
|
|
+ "saved", count,
|
|
|
|
|
+ "errors", orgTels.size() - count
|
|
|
|
|
+ ).encode()))
|
|
|
|
|
+ .onFailure(rc::fail))
|
|
|
|
|
+ )
|
|
|
|
|
+ .onFailure(rc::fail));
|
|
|
|
|
|
|
|
case GEOJSON -> Optional.of(rc.body().asJsonObject()).map(j -> j.getJsonArray("features"))
|
|
case GEOJSON -> Optional.of(rc.body().asJsonObject()).map(j -> j.getJsonArray("features"))
|
|
|
.map(jsonArray -> jsonArray.stream().filter(JsonObject.class::isInstance).map(JsonObject.class::cast)
|
|
.map(jsonArray -> jsonArray.stream().filter(JsonObject.class::isInstance).map(JsonObject.class::cast)
|
|
|
.map(f -> UnitTelemetry.of(
|
|
.map(f -> UnitTelemetry.of(
|
|
|
- f.getJsonObject("properties").getLong("unitId"),
|
|
|
|
|
- OffsetDateTime.parse(f.getJsonObject("properties").getString("timestamp")),
|
|
|
|
|
- Location.of(
|
|
|
|
|
- f.getJsonObject("geometry").getJsonArray("coordinates").getFloat(0),
|
|
|
|
|
- f.getJsonObject("geometry").getJsonArray("coordinates").getFloat(1),
|
|
|
|
|
- f.getJsonObject("geometry").getJsonArray("coordinates").getFloat(2)
|
|
|
|
|
- ),
|
|
|
|
|
- f.getJsonObject("properties").getInteger("speed"),
|
|
|
|
|
- f.getJsonObject("observations")
|
|
|
|
|
- )).collect(toList()))
|
|
|
|
|
- .ifPresent(telemetries -> repo.saveAllTelemetry(telemetries)
|
|
|
|
|
- .onSuccess(count -> rc.response()
|
|
|
|
|
- .end(JsonObject.of(
|
|
|
|
|
- "saved", count,
|
|
|
|
|
- "errors", telemetries.size() - count
|
|
|
|
|
- ).encode()))
|
|
|
|
|
- .onFailure(rc::fail)
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ f.getJsonObject("properties").getLong("unitId"),
|
|
|
|
|
+ OffsetDateTime.parse(f.getJsonObject("properties").getString("timestamp")),
|
|
|
|
|
+ Location.of(
|
|
|
|
|
+ f.getJsonObject("geometry").getJsonArray("coordinates").getFloat(0),
|
|
|
|
|
+ f.getJsonObject("geometry").getJsonArray("coordinates").getFloat(1),
|
|
|
|
|
+ f.getJsonObject("geometry").getJsonArray("coordinates").getFloat(2)
|
|
|
|
|
+ ),
|
|
|
|
|
+ f.getJsonObject("properties").getInteger("speed"),
|
|
|
|
|
+ f.getJsonObject("observations")
|
|
|
|
|
+ )).sorted(comparing(UnitTelemetry::getTimestamp)).collect(toList()))
|
|
|
|
|
+ .ifPresent(orgTels -> repo.findCampaignById(campaignId)
|
|
|
|
|
+ .onSuccess(campaign -> fluentlyOf(telemetriesWithinCampaign(campaign, orgTels))
|
|
|
|
|
+ .then(flTels -> repo.saveAllTelemetry(flTels)
|
|
|
|
|
+ .onSuccess(count -> rc.response().end(JsonObject.of(
|
|
|
|
|
+ "saved", count,
|
|
|
|
|
+ "errors", orgTels.size() - count
|
|
|
|
|
+ ).encode()))
|
|
|
|
|
+ .onFailure(rc::fail))
|
|
|
|
|
+ )
|
|
|
|
|
+ .onFailure(rc::fail));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|