|
|
@@ -1,221 +0,0 @@
|
|
|
-package cz.senslog.analyzer.server.handler;
|
|
|
-
|
|
|
-import com.google.gson.Gson;
|
|
|
-import com.google.gson.GsonBuilder;
|
|
|
-import com.google.gson.JsonSerializer;
|
|
|
-import cz.senslog.analyzer.domain.*;
|
|
|
-import cz.senslog.analyzer.storage.permanent.repository.StatisticsConfigRepository;
|
|
|
-import cz.senslog.analyzer.storage.permanent.repository.StatisticsRepository;
|
|
|
-import cz.senslog.analyzer.server.vertx.AbstractRestHandler;
|
|
|
-import cz.senslog.common.util.TimeRange;
|
|
|
-import cz.senslog.common.util.Tuple;
|
|
|
-import io.vertx.core.MultiMap;
|
|
|
-import io.vertx.core.http.HttpServerResponse;
|
|
|
-import io.vertx.core.json.JsonArray;
|
|
|
-import io.vertx.core.json.JsonObject;
|
|
|
-import org.apache.logging.log4j.LogManager;
|
|
|
-import org.apache.logging.log4j.Logger;
|
|
|
-
|
|
|
-import javax.inject.Inject;
|
|
|
-import java.time.Instant;
|
|
|
-import java.time.format.DateTimeFormatter;
|
|
|
-import java.time.format.DateTimeParseException;
|
|
|
-import java.time.temporal.ChronoUnit;
|
|
|
-import java.util.*;
|
|
|
-
|
|
|
-import static cz.senslog.analyzer.domain.AttributeValue.*;
|
|
|
-import static cz.senslog.common.http.HttpContentType.APPLICATION_JSON;
|
|
|
-import static cz.senslog.common.http.HttpHeader.CONTENT_TYPE;
|
|
|
-import static java.time.format.DateTimeFormatter.ofPattern;
|
|
|
-import static java.util.Collections.singletonList;
|
|
|
-
|
|
|
-public class StatisticsHandler extends AbstractRestHandler {
|
|
|
-
|
|
|
- private static final Logger logger = LogManager.getLogger(StatisticsHandler.class);
|
|
|
-
|
|
|
- private final StatisticsRepository statisticsRepository;
|
|
|
- private final StatisticsConfigRepository configRepository;
|
|
|
-
|
|
|
- private static final Gson gson = new GsonBuilder()
|
|
|
- .registerTypeAdapter(DoubleStatistics.class, (JsonSerializer<DoubleStatistics>) (src, typeOfSrc, context1) -> {
|
|
|
- com.google.gson.JsonObject js = new com.google.gson.JsonObject();
|
|
|
-// js.addProperty("time", src.getTimestamp().timeFormat());
|
|
|
- // js.addProperty("date", src.getTimestamp().dateFormat());
|
|
|
- js.addProperty("timestamp", src.getTimestamp().format());
|
|
|
-
|
|
|
- js.addProperty(MIN.name().toLowerCase(), src.getMin());
|
|
|
- js.addProperty(MAX.name().toLowerCase(), src.getMax());
|
|
|
- js.addProperty(AVG.name().toLowerCase(), src.getAverage());
|
|
|
- return js;
|
|
|
- })
|
|
|
- .create();
|
|
|
-
|
|
|
- @Inject
|
|
|
- public StatisticsHandler(
|
|
|
- StatisticsRepository statisticsRepository,
|
|
|
- StatisticsConfigRepository configRepository
|
|
|
- ) {
|
|
|
- this.statisticsRepository = statisticsRepository;
|
|
|
- this.configRepository = configRepository;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void start() {
|
|
|
-
|
|
|
- router().get("/analyticsByUnitSensor").handler(ctx -> {
|
|
|
- logger.info("Handling '{}' with the params '{}'.", ctx.request().path(), ctx.request().params().entries());
|
|
|
-
|
|
|
- HttpServerResponse response = ctx.response();
|
|
|
- response.putHeader(CONTENT_TYPE, APPLICATION_JSON);
|
|
|
- MultiMap params = ctx.request().params();
|
|
|
-
|
|
|
- long unitIdParam;
|
|
|
- Long sensorIdParam;
|
|
|
- TimeRange<Instant> timeRangeParam;
|
|
|
- GroupBy groupByParam;
|
|
|
- Interval intervalParam;
|
|
|
-
|
|
|
- try {
|
|
|
- unitIdParam = Long.parseLong(params.get("unit_id"));
|
|
|
- sensorIdParam = params.contains("sensor_id") ? Long.parseLong(params.get("sensor_id")) : null;
|
|
|
-
|
|
|
- Timestamp fromParam = Timestamp.parse(params.get("from"));
|
|
|
- Timestamp toParam = Timestamp.parse(params.get("to"));
|
|
|
- timeRangeParam = TimeRange.of(fromParam.toInstant(), toParam.toInstant());
|
|
|
-
|
|
|
- groupByParam = GroupBy.parse(params.get("group_by"));
|
|
|
- intervalParam = Interval.parse(params.get("interval"));
|
|
|
- } catch (NumberFormatException | DateTimeParseException e) {
|
|
|
- response.setStatusCode(404).end(new JsonObject()
|
|
|
- .put("message", e.getMessage()).encode()); return;
|
|
|
- }
|
|
|
-
|
|
|
- long timeDiffSec = timeRangeParam.difference(ChronoUnit.SECONDS);
|
|
|
- StatisticsConfigRepository.Special specialRepository = configRepository.special();
|
|
|
- // List<Tuple<GroupId, SensorId>>
|
|
|
- List<Tuple<Long, Long>> sensorInGroup;
|
|
|
- if (sensorIdParam != null) {
|
|
|
- long groupId = specialRepository.getGroupIdByUnitSensor(unitIdParam, sensorIdParam, timeDiffSec);
|
|
|
- sensorInGroup = singletonList(Tuple.of(groupId, sensorIdParam));
|
|
|
- } else {
|
|
|
- sensorInGroup = specialRepository.getGroupsByUnit(unitIdParam, timeDiffSec);
|
|
|
- }
|
|
|
-
|
|
|
- Map<Long, List<DoubleStatistics>> statisticsBySensor = new HashMap<>(sensorInGroup.size());
|
|
|
- for (Tuple<Long, Long> groupEntry : sensorInGroup) {
|
|
|
- long groupId = groupEntry.getItem1();
|
|
|
- long sensorId = groupEntry.getItem2();
|
|
|
- List<DoubleStatistics> statistics = statisticsRepository.getByTimeRange(groupId, timeRangeParam);
|
|
|
- statisticsBySensor.put(sensorId, statistics);
|
|
|
- }
|
|
|
-
|
|
|
- JsonObject result = new JsonObject();
|
|
|
- for (Map.Entry<Long, List<DoubleStatistics>> sensorEntry : statisticsBySensor.entrySet()) {
|
|
|
- String sensorIdStr = sensorEntry.getKey().toString();
|
|
|
- List<DoubleStatistics> statistics = sensorEntry.getValue();
|
|
|
-
|
|
|
- if (groupByParam == null) {
|
|
|
- DoubleStatistics mergedSt = MergeStatistics.mergeToOne(statistics);
|
|
|
- if (mergedSt != null) {
|
|
|
- result.put(sensorIdStr, new JsonObject()
|
|
|
- .put("min", mergedSt.getMin())
|
|
|
- .put("max", mergedSt.getMax())
|
|
|
- .put("avg", mergedSt.getAverage())
|
|
|
- );
|
|
|
- }
|
|
|
- } else {
|
|
|
- Map<String, List<DoubleStatistics>> grouped = MergeStatistics.mergeByGroup(groupByParam, statistics);
|
|
|
- if (!grouped.isEmpty()) {
|
|
|
- JsonObject groupJson = new JsonObject();
|
|
|
- for (Map.Entry<String, List<DoubleStatistics>> entry : grouped.entrySet()) {
|
|
|
- JsonArray sensorsSt = new JsonArray();
|
|
|
- for (DoubleStatistics st : entry.getValue()) {
|
|
|
- sensorsSt.add(new JsonObject()
|
|
|
- .put("min", st.getMin())
|
|
|
- .put("max", st.getMax())
|
|
|
- .put("avg", st.getAverage())
|
|
|
- .put("timestamp", st.getTimestamp().format())
|
|
|
- .put("interval", st.getSource().getInterval())
|
|
|
- );
|
|
|
- }
|
|
|
- groupJson.put(entry.getKey(), sensorsSt);
|
|
|
- }
|
|
|
- result.put(sensorIdStr, groupJson);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- response.end(result.encode());
|
|
|
- });
|
|
|
-
|
|
|
- router().get("/analyticsByUser").handler(ctx -> {
|
|
|
- HttpServerResponse response = ctx.response();
|
|
|
- response.putHeader(CONTENT_TYPE, APPLICATION_JSON);
|
|
|
- MultiMap params = ctx.request().params();
|
|
|
-
|
|
|
- long userId = Long.parseLong(params.get("user_id"));
|
|
|
- Timestamp from = Timestamp.parse(params.get("from"));
|
|
|
- Timestamp to = Timestamp.parse(params.get("to"));
|
|
|
- GroupBy groupBy = GroupBy.parse(params.get("group_by"));
|
|
|
- TimeRange<Instant> timeRange = TimeRange.of(from.toInstant(), to.toInstant());
|
|
|
-
|
|
|
- response.setStatusCode(501).end(new JsonObject()
|
|
|
- .put("message", "not implemented yet")
|
|
|
- .encode());
|
|
|
- });
|
|
|
-
|
|
|
- router().get("/analyticsByGroup").handler(ctx -> {
|
|
|
- HttpServerResponse response = ctx.response();
|
|
|
- response.putHeader(CONTENT_TYPE, APPLICATION_JSON);
|
|
|
- MultiMap params = ctx.request().params();
|
|
|
-
|
|
|
- long groupId = Long.parseLong(params.get("group_id"));
|
|
|
- Timestamp from = Timestamp.parse(params.get("from"));
|
|
|
- Timestamp to = Timestamp.parse(params.get("to"));
|
|
|
- GroupBy groupBy = GroupBy.parse(params.get("group_by"));
|
|
|
- TimeRange<Instant> timeRange = TimeRange.of(from.toInstant(), to.toInstant());
|
|
|
-
|
|
|
- List<DoubleStatistics> statistics = statisticsRepository.getByTimeRange(groupId, timeRange);
|
|
|
- Object result;
|
|
|
- if (groupBy == null) {
|
|
|
- result = MergeStatistics.mergeToOne(statistics);
|
|
|
- } else {
|
|
|
- result = MergeStatistics.mergeByGroup(groupBy, statistics);
|
|
|
- }
|
|
|
-
|
|
|
- response.end(gson.toJson(result));
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- private static class MergeStatistics {
|
|
|
-
|
|
|
- public static Map<String, List<DoubleStatistics>> mergeByGroup(GroupBy groupBy, List<DoubleStatistics> statistics) {
|
|
|
- Map<String, List<DoubleStatistics>> result = new HashMap<>();
|
|
|
- DateTimeFormatter formatter = null;
|
|
|
-
|
|
|
- switch (groupBy) {
|
|
|
- case DAY: formatter = ofPattern("yyyy-MM-dd"); break;
|
|
|
- case MONTH: formatter = ofPattern("yyyy-MM"); break;
|
|
|
- case YEAR: formatter = ofPattern("yyyy"); break;
|
|
|
- }
|
|
|
-
|
|
|
- for (DoubleStatistics st : statistics) {
|
|
|
- String time = st.getTimestamp().get().format(formatter);
|
|
|
- result.computeIfAbsent(time, k -> new ArrayList<>()).add(st);
|
|
|
- }
|
|
|
-
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- public static DoubleStatistics mergeToOne(List<DoubleStatistics> statistics) {
|
|
|
- if (statistics == null || statistics.isEmpty()) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- DoubleStatistics first = statistics.get(0);
|
|
|
- for (int i = 1; i < statistics.size(); i++) {
|
|
|
- first.accept(statistics.get(i));
|
|
|
- }
|
|
|
- return first;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|