Decouple runtime event window bundle selection

This commit is contained in:
trifonovt 2026-06-05 14:39:00 +02:00
parent ff12953e05
commit aa360c9f02
5 changed files with 86 additions and 40 deletions

View File

@ -0,0 +1,39 @@
package at.procon.eventhub.processing.model;
import at.procon.eventhub.dto.EventHubEventDto;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public record RuntimeTimelineEventBundle(
List<EventHubEventDto> activityEvents,
List<EventHubEventDto> vehicleUsageEvents,
List<EventHubEventDto> supportEvents
) {
public RuntimeTimelineEventBundle {
activityEvents = copy(activityEvents);
vehicleUsageEvents = copy(vehicleUsageEvents);
supportEvents = copy(supportEvents);
}
public static RuntimeTimelineEventBundle empty() {
return new RuntimeTimelineEventBundle(List.of(), List.of(), List.of());
}
public List<EventHubEventDto> allEvents() {
List<EventHubEventDto> result = new ArrayList<>(activityEvents.size() + vehicleUsageEvents.size() + supportEvents.size());
result.addAll(activityEvents);
result.addAll(vehicleUsageEvents);
result.addAll(supportEvents);
result.sort(Comparator.comparing(EventHubEventDto::occurredAt)
.thenComparing(event -> event.eventDomain().name())
.thenComparing(event -> event.eventType().name())
.thenComparing(event -> event.lifecycle().name())
.thenComparing(EventHubEventDto::externalSourceEventId));
return List.copyOf(result);
}
private static List<EventHubEventDto> copy(List<EventHubEventDto> events) {
return events == null ? List.of() : List.copyOf(events);
}
}

View File

@ -3,9 +3,8 @@ package at.procon.eventhub.processing.service;
import at.procon.eventhub.dto.EventHubEventDto;
import at.procon.eventhub.dto.EventLifecycle;
import at.procon.eventhub.dto.EventType;
import at.procon.eventhub.processing.model.RuntimeTimelineEventBundle;
import at.procon.eventhub.processing.support.RuntimeEventIdentityResolver;
import com.fasterxml.jackson.databind.JsonNode;
import at.procon.eventhub.tachographfilesession.model.TachographTimelineEventBundle;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
@ -16,23 +15,23 @@ final class RuntimeIntervalEventWindowSelector {
private RuntimeIntervalEventWindowSelector() {
}
static TachographTimelineEventBundle filterBundle(
TachographTimelineEventBundle bundle,
static RuntimeTimelineEventBundle filterBundle(
RuntimeTimelineEventBundle bundle,
OffsetDateTime occurredFrom,
OffsetDateTime occurredTo,
boolean includeIntersectingIntervals
) {
if (bundle == null) {
return new TachographTimelineEventBundle(List.of(), List.of(), List.of());
return RuntimeTimelineEventBundle.empty();
}
return new TachographTimelineEventBundle(
return new RuntimeTimelineEventBundle(
filterIntervalEvents(bundle.activityEvents(), occurredFrom, occurredTo, includeIntersectingIntervals),
filterIntervalEvents(bundle.vehicleUsageEvents(), occurredFrom, occurredTo, includeIntersectingIntervals),
filterPointEvents(bundle.supportEvents(), occurredFrom, occurredTo)
);
}
private static List<EventHubEventDto> filterIntervalEvents(
static List<EventHubEventDto> filterIntervalEvents(
List<EventHubEventDto> events,
OffsetDateTime occurredFrom,
OffsetDateTime occurredTo,
@ -59,11 +58,14 @@ final class RuntimeIntervalEventWindowSelector {
return List.copyOf(result);
}
private static List<EventHubEventDto> filterPointEvents(
static List<EventHubEventDto> filterPointEvents(
List<EventHubEventDto> events,
OffsetDateTime occurredFrom,
OffsetDateTime occurredTo
) {
if (events == null || events.isEmpty()) {
return List.of();
}
return events.stream()
.filter(event -> withinWindow(event.occurredAt(), occurredFrom, occurredTo))
.toList();
@ -87,27 +89,6 @@ final class RuntimeIntervalEventWindowSelector {
return RuntimeEventIdentityResolver.runtimeIntervalKey(event);
}
private static JsonNode raw(EventHubEventDto event) {
JsonNode payload = event == null ? null : event.payload();
if (payload == null || payload.isNull() || payload.isMissingNode()) {
return null;
}
JsonNode raw = payload.get("raw");
return raw == null || raw.isNull() ? payload : raw;
}
private static String text(JsonNode node, String field) {
if (node == null || field == null) {
return null;
}
JsonNode value = node.get(field);
if (value == null || value.isNull()) {
return null;
}
String text = value.asText(null);
return text == null || text.isBlank() ? null : text.trim();
}
private static final class IntervalGroup {
private final List<EventHubEventDto> events = new ArrayList<>();
private OffsetDateTime startedAt;

View File

@ -54,11 +54,14 @@ public class TachographFileSessionUnifiedDriverEventSource implements UnifiedDri
DriverExtractionSession driver,
UnifiedDriverEventsRequest request
) {
return RuntimeIntervalEventWindowSelector.filterBundle(
eventBuilder.buildEventBundle(session, driver),
TachographTimelineEventBundle bundle = eventBuilder.buildEventBundle(session, driver);
return TachographTimelineEventBundle.fromRuntimeBundle(
RuntimeIntervalEventWindowSelector.filterBundle(
bundle == null ? null : bundle.toRuntimeBundle(),
request.occurredFrom(),
request.occurredTo(),
request.includeIntersectingIntervals()
)
);
}
}

View File

@ -5,6 +5,7 @@ import at.procon.eventhub.dto.VehicleRefDto;
import at.procon.eventhub.processing.model.UnifiedEventSourceFamily;
import at.procon.eventhub.processing.model.UnifiedVehicleEventsRequest;
import at.procon.eventhub.reference.TachographNationRegistry;
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
import at.procon.eventhub.tachographfilesession.model.TachographTimelineEventBundle;
import at.procon.eventhub.tachographfilesession.service.DriverTimelineEventBuilder;
@ -37,18 +38,29 @@ public class TachographFileSessionUnifiedVehicleEventSource implements UnifiedVe
TachographFileSession session = repository.find(request.sessionId())
.orElseThrow(() -> new TachographFileSessionNotFoundException(request.sessionId()));
return session.driversByKey().values().stream()
.map(driver -> RuntimeIntervalEventWindowSelector.filterBundle(
eventBuilder.buildEventBundle(session, driver),
request.occurredFrom(),
request.occurredTo(),
request.includeIntersectingIntervals()
).allEvents())
.map(driver -> filterBundle(session, driver, request).allEvents())
.flatMap(List::stream)
.filter(event -> matchesVehicle(event.vehicleRef(), request))
.distinct()
.toList();
}
private TachographTimelineEventBundle filterBundle(
TachographFileSession session,
DriverExtractionSession driver,
UnifiedVehicleEventsRequest request
) {
TachographTimelineEventBundle bundle = eventBuilder.buildEventBundle(session, driver);
return TachographTimelineEventBundle.fromRuntimeBundle(
RuntimeIntervalEventWindowSelector.filterBundle(
bundle == null ? null : bundle.toRuntimeBundle(),
request.occurredFrom(),
request.occurredTo(),
request.includeIntersectingIntervals()
)
);
}
private boolean matchesVehicle(VehicleRefDto vehicleRef, UnifiedVehicleEventsRequest request) {
if (vehicleRef == null || !vehicleRef.hasAnyReference()) {
return false;

View File

@ -1,6 +1,7 @@
package at.procon.eventhub.tachographfilesession.model;
import at.procon.eventhub.dto.EventHubEventDto;
import at.procon.eventhub.processing.model.RuntimeTimelineEventBundle;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@ -29,6 +30,16 @@ public record TachographTimelineEventBundle(
return List.copyOf(result);
}
public RuntimeTimelineEventBundle toRuntimeBundle() {
return new RuntimeTimelineEventBundle(activityEvents, vehicleUsageEvents, supportEvents);
}
public static TachographTimelineEventBundle fromRuntimeBundle(RuntimeTimelineEventBundle bundle) {
return bundle == null
? new TachographTimelineEventBundle(List.of(), List.of(), List.of())
: new TachographTimelineEventBundle(bundle.activityEvents(), bundle.vehicleUsageEvents(), bundle.supportEvents());
}
private static List<EventHubEventDto> copy(List<EventHubEventDto> events) {
return events == null ? List.of() : List.copyOf(events);
}