Compare commits

..

No commits in common. "84922f6c445b4c778f4b416d1e6f3e98dede618c" and "ff12953e0542905a017c8293e7ef7e0b2c4cbf71" have entirely different histories.

42 changed files with 276 additions and 871 deletions

View File

@ -17,12 +17,12 @@ import at.procon.eventhub.processing.eventprocessing.validation.RuntimeMixedSour
import at.procon.eventhub.processing.eventprocessing.validation.RuntimeTachographParityValidationApiRequest; import at.procon.eventhub.processing.eventprocessing.validation.RuntimeTachographParityValidationApiRequest;
import at.procon.eventhub.processing.eventprocessing.validation.RuntimeTachographParityValidationResultDto; import at.procon.eventhub.processing.eventprocessing.validation.RuntimeTachographParityValidationResultDto;
import at.procon.eventhub.processing.eventprocessing.validation.RuntimeTachographParityValidationService; import at.procon.eventhub.processing.eventprocessing.validation.RuntimeTachographParityValidationService;
import at.procon.eventhub.processing.model.RuntimeDriverTimeline;
import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle; import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle;
import at.procon.eventhub.processing.service.UnifiedRuntimeDerivedProjectionService; import at.procon.eventhub.processing.service.UnifiedRuntimeDerivedProjectionService;
import at.procon.eventhub.processing.service.UnifiedRuntimeDriverTimelineService; import at.procon.eventhub.processing.service.UnifiedRuntimeDriverTimelineService;
import at.procon.eventhub.processing.service.UnifiedRuntimeEventAssemblyService; import at.procon.eventhub.processing.service.UnifiedRuntimeEventAssemblyService;
import at.procon.eventhub.processing.service.RuntimeDriverWorkingTimeScopeProcessingService; import at.procon.eventhub.processing.service.RuntimeDriverWorkingTimeScopeProcessingService;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@ -106,7 +106,7 @@ public class UnifiedRuntimeProcessingController {
} }
@PostMapping("/driver-timeline") @PostMapping("/driver-timeline")
public ResponseEntity<RuntimeDriverTimeline> loadDriverTimeline( public ResponseEntity<ResolvedDriverTimeline> loadDriverTimeline(
@RequestBody UnifiedRuntimeProcessingApiRequest request @RequestBody UnifiedRuntimeProcessingApiRequest request
) { ) {
return ResponseEntity.ok(runtimeDriverTimelineService.loadDriverTimeline(request.toRuntimeRequest())); return ResponseEntity.ok(runtimeDriverTimelineService.loadDriverTimeline(request.toRuntimeRequest()));

View File

@ -1,7 +1,7 @@
package at.procon.eventhub.processing.dto; package at.procon.eventhub.processing.dto;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeVehicleUsageInterval; import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeVehicleUsageInterval;
import at.procon.eventhub.processing.model.RuntimeVehicleUsageInterval; import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
public record RuntimeVehicleUsageIntervalDebugDto( public record RuntimeVehicleUsageIntervalDebugDto(
@ -12,7 +12,7 @@ public record RuntimeVehicleUsageIntervalDebugDto(
String vehicleKey, String vehicleKey,
String sourceKind String sourceKind
) { ) {
public static RuntimeVehicleUsageIntervalDebugDto from(RuntimeVehicleUsageInterval interval) { public static RuntimeVehicleUsageIntervalDebugDto from(ResolvedVehicleUsageInterval interval) {
if (interval == null) { if (interval == null) {
return null; return null;
} }

View File

@ -3,6 +3,7 @@ package at.procon.eventhub.processing.dto;
import at.procon.eventhub.processing.model.UnifiedEventSourceFamily; import at.procon.eventhub.processing.model.UnifiedEventSourceFamily;
import at.procon.eventhub.processing.model.UnifiedRuntimeEventBackend; import at.procon.eventhub.processing.model.UnifiedRuntimeEventBackend;
import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest; import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest;
import at.procon.eventhub.processing.model.UnifiedTachographSourceKind;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -15,7 +16,7 @@ public record UnifiedRuntimeProcessingApiRequest(
String tenantKey, String tenantKey,
Set<UnifiedEventSourceFamily> sourceFamilies, Set<UnifiedEventSourceFamily> sourceFamilies,
UnifiedRuntimeEventBackend eventBackend, UnifiedRuntimeEventBackend eventBackend,
Set<String> sourceKinds, Set<UnifiedTachographSourceKind> tachographSourceKinds,
String driverKey, String driverKey,
Set<String> driverKeys, Set<String> driverKeys,
Boolean includeAllDrivers, Boolean includeAllDrivers,
@ -42,7 +43,7 @@ public record UnifiedRuntimeProcessingApiRequest(
String tenantKey, String tenantKey,
Set<UnifiedEventSourceFamily> sourceFamilies, Set<UnifiedEventSourceFamily> sourceFamilies,
UnifiedRuntimeEventBackend eventBackend, UnifiedRuntimeEventBackend eventBackend,
Set<String> sourceKinds, Set<UnifiedTachographSourceKind> tachographSourceKinds,
String driverKey, String driverKey,
Set<String> driverKeys, Set<String> driverKeys,
Boolean includeAllDrivers, Boolean includeAllDrivers,
@ -68,7 +69,7 @@ public record UnifiedRuntimeProcessingApiRequest(
tenantKey, tenantKey,
sourceFamilies, sourceFamilies,
eventBackend, eventBackend,
sourceKinds, tachographSourceKinds,
driverKey, driverKey,
driverKeys, driverKeys,
includeAllDrivers, includeAllDrivers,
@ -98,7 +99,7 @@ public record UnifiedRuntimeProcessingApiRequest(
tenantKey, tenantKey,
sourceFamilies, sourceFamilies,
eventBackend, eventBackend,
sourceKinds, tachographSourceKinds,
driverKey, driverKey,
driverKeys, driverKeys,
includeAllDrivers != null && includeAllDrivers, includeAllDrivers != null && includeAllDrivers,

View File

@ -14,7 +14,7 @@ import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle;
import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest; import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest;
import at.procon.eventhub.processing.service.RuntimeDriverVehicleEvidenceAttachmentService; import at.procon.eventhub.processing.service.RuntimeDriverVehicleEvidenceAttachmentService;
import at.procon.eventhub.processing.support.RuntimeEventIdentityResolver; import at.procon.eventhub.processing.support.RuntimeEventIdentityResolver;
import at.procon.eventhub.processing.support.RuntimeEntityReferenceResolver; import at.procon.eventhub.processing.support.TachographRuntimeIdentityResolver;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
@ -260,7 +260,7 @@ public class VehicleEvidenceAttachmentModule implements RuntimeProcessingModule
} }
private String driverKey(EventHubEventDto event) { private String driverKey(EventHubEventDto event) {
return RuntimeEntityReferenceResolver.driverKey(event); return TachographRuntimeIdentityResolver.driverKey(event);
} }
private JsonNode rawPayload(EventHubEventDto event) { private JsonNode rawPayload(EventHubEventDto event) {

View File

@ -9,7 +9,7 @@ import at.procon.eventhub.processing.eventprocessing.module.RuntimeProcessingMod
import at.procon.eventhub.processing.eventprocessing.module.RuntimeProcessingModuleResult; import at.procon.eventhub.processing.eventprocessing.module.RuntimeProcessingModuleResult;
import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle; import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle;
import at.procon.eventhub.processing.support.RuntimeEventIdentityResolver; import at.procon.eventhub.processing.support.RuntimeEventIdentityResolver;
import at.procon.eventhub.processing.support.RuntimeEntityReferenceResolver; import at.procon.eventhub.processing.support.TachographRuntimeIdentityResolver;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.ArrayList; import java.util.ArrayList;
@ -156,7 +156,7 @@ public final class DriverWorkingTimeEplEventMapper {
JsonNode attributes = attributes(sourceEvent); JsonNode attributes = attributes(sourceEvent);
String intervalId = RuntimeEventIdentityResolver.presentationIntervalId(sourceEvent); String intervalId = RuntimeEventIdentityResolver.presentationIntervalId(sourceEvent);
String runtimeIntervalKey = RuntimeEventIdentityResolver.runtimeIntervalKey(sourceEvent); String runtimeIntervalKey = RuntimeEventIdentityResolver.runtimeIntervalKey(sourceEvent);
String driverKey = RuntimeEntityReferenceResolver.driverKey(sourceEvent); String driverKey = TachographRuntimeIdentityResolver.driverKey(sourceEvent);
if (driverKey == null || intervalId == null || runtimeIntervalKey == null) { if (driverKey == null || intervalId == null || runtimeIntervalKey == null) {
return null; return null;
} }
@ -175,8 +175,8 @@ public final class DriverWorkingTimeEplEventMapper {
event.put("cardSlot", firstNonBlank(text(raw, "cardSlot"), text(attributes, "cardSlot"))); event.put("cardSlot", firstNonBlank(text(raw, "cardSlot"), text(attributes, "cardSlot")));
event.put("cardStatus", firstNonBlank(text(raw, "cardStatus"), text(attributes, "cardStatus"))); event.put("cardStatus", firstNonBlank(text(raw, "cardStatus"), text(attributes, "cardStatus")));
event.put("drivingStatus", firstNonBlank(text(raw, "drivingStatus"), text(attributes, "drivingStatus"))); event.put("drivingStatus", firstNonBlank(text(raw, "drivingStatus"), text(attributes, "drivingStatus")));
event.put("registrationKey", RuntimeEntityReferenceResolver.registrationKey(sourceEvent)); event.put("registrationKey", TachographRuntimeIdentityResolver.registrationKey(sourceEvent));
event.put("vehicleKey", RuntimeEntityReferenceResolver.vehicleKey(sourceEvent)); event.put("vehicleKey", TachographRuntimeIdentityResolver.vehicleKey(sourceEvent));
event.put("sourceKind", firstNonBlank(text(raw, "sourceKind"), sourceKind(sourceEvent))); event.put("sourceKind", firstNonBlank(text(raw, "sourceKind"), sourceKind(sourceEvent)));
event.put("synthetic", booleanValue(raw, "synthetic", false)); event.put("synthetic", booleanValue(raw, "synthetic", false));
event.put("clippedToRequestedPeriod", booleanValue(raw, "clippedToRequestedPeriod", false)); event.put("clippedToRequestedPeriod", booleanValue(raw, "clippedToRequestedPeriod", false));
@ -199,7 +199,7 @@ public final class DriverWorkingTimeEplEventMapper {
JsonNode raw = rawPayload(sourceEvent); JsonNode raw = rawPayload(sourceEvent);
String intervalId = RuntimeEventIdentityResolver.presentationIntervalId(sourceEvent); String intervalId = RuntimeEventIdentityResolver.presentationIntervalId(sourceEvent);
String runtimeIntervalKey = RuntimeEventIdentityResolver.runtimeIntervalKey(sourceEvent); String runtimeIntervalKey = RuntimeEventIdentityResolver.runtimeIntervalKey(sourceEvent);
String driverKey = RuntimeEntityReferenceResolver.driverKey(sourceEvent); String driverKey = TachographRuntimeIdentityResolver.driverKey(sourceEvent);
if (driverKey == null || intervalId == null || runtimeIntervalKey == null) { if (driverKey == null || intervalId == null || runtimeIntervalKey == null) {
return null; return null;
} }
@ -214,8 +214,8 @@ public final class DriverWorkingTimeEplEventMapper {
event.put("lifecycle", sourceEvent.lifecycle().name()); event.put("lifecycle", sourceEvent.lifecycle().name());
event.put("occurredAt", sourceEvent.occurredAt()); event.put("occurredAt", sourceEvent.occurredAt());
event.put("occurredAtEpochSecond", sourceEvent.occurredAt().toEpochSecond()); event.put("occurredAtEpochSecond", sourceEvent.occurredAt().toEpochSecond());
event.put("registrationKey", RuntimeEntityReferenceResolver.registrationKey(sourceEvent)); event.put("registrationKey", TachographRuntimeIdentityResolver.registrationKey(sourceEvent));
event.put("vehicleKey", RuntimeEntityReferenceResolver.vehicleKey(sourceEvent)); event.put("vehicleKey", TachographRuntimeIdentityResolver.vehicleKey(sourceEvent));
event.put("sourceKind", firstNonBlank(text(raw, "sourceKind"), sourceKind(sourceEvent))); event.put("sourceKind", firstNonBlank(text(raw, "sourceKind"), sourceKind(sourceEvent)));
event.put("odometerKm", odometerKm(sourceEvent, raw)); event.put("odometerKm", odometerKm(sourceEvent, raw));
return event; return event;

View File

@ -388,7 +388,7 @@ public class DriverWorkingTimeRuntimeProcessingPlan implements RuntimeProcessing
sourceSelection.tenantKey(), sourceSelection.tenantKey(),
sourceSelection.sourceFamilies(), sourceSelection.sourceFamilies(),
sourceSelection.eventBackend(), sourceSelection.eventBackend(),
sourceSelection.sourceKinds(), sourceSelection.tachographSourceKinds(),
sourceSelection.driverKey(), sourceSelection.driverKey(),
driverKeys, driverKeys,
includeAllDrivers, includeAllDrivers,

View File

@ -8,7 +8,7 @@ import at.procon.eventhub.dto.EventLifecycle;
import at.procon.eventhub.dto.EventType; import at.procon.eventhub.dto.EventType;
import at.procon.eventhub.dto.GeoPointDto; import at.procon.eventhub.dto.GeoPointDto;
import at.procon.eventhub.dto.VehicleRefDto; import at.procon.eventhub.dto.VehicleRefDto;
import at.procon.eventhub.processing.support.RuntimeEntityReferenceResolver; import at.procon.eventhub.processing.support.TachographRuntimeIdentityResolver;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
@ -82,9 +82,9 @@ public class RuntimeSupportEvidenceNormalizer {
event.eventDomain() == null ? null : event.eventDomain().name(), event.eventDomain() == null ? null : event.eventDomain().name(),
event.eventType() == null ? null : event.eventType().name(), event.eventType() == null ? null : event.eventType().name(),
event.lifecycle() == null ? null : event.lifecycle().name(), event.lifecycle() == null ? null : event.lifecycle().name(),
firstNonBlank(RuntimeEntityReferenceResolver.driverKey(event), fallbackDriverKey), firstNonBlank(TachographRuntimeIdentityResolver.driverKey(event), fallbackDriverKey),
RuntimeEntityReferenceResolver.vehicleKey(event), TachographRuntimeIdentityResolver.vehicleKey(event),
RuntimeEntityReferenceResolver.registrationKey(event), TachographRuntimeIdentityResolver.registrationKey(event),
event.occurredAt(), event.occurredAt(),
event.occurredAt() == null ? null : event.occurredAt().toEpochSecond(), event.occurredAt() == null ? null : event.occurredAt().toEpochSecond(),
latitude, latitude,
@ -288,7 +288,7 @@ public class RuntimeSupportEvidenceNormalizer {
} }
private JsonNode rawPayload(EventHubEventDto event) { private JsonNode rawPayload(EventHubEventDto event) {
return RuntimeEntityReferenceResolver.rawPayload(event); return TachographRuntimeIdentityResolver.rawPayload(event);
} }
private String detailText(EventHubEventDto event, String field) { private String detailText(EventHubEventDto event, String field) {

View File

@ -1,99 +0,0 @@
package at.procon.eventhub.processing.model;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.List;
public record RuntimeActivityInterval(
String intervalId,
OffsetDateTime from,
OffsetDateTime to,
long durationSeconds,
String activityType,
String slot,
String cardStatus,
String drivingStatus,
String registrationKey,
String vehicleKey,
String sourceKind,
List<String> sourceIntervalIds,
boolean synthetic,
boolean clippedToRequestedPeriod,
String level
) {
public static RuntimeActivityInterval raw(
String intervalId,
OffsetDateTime from,
OffsetDateTime to,
String activityType,
String slot,
String cardStatus,
String drivingStatus,
String registrationKey,
String vehicleKey,
String sourceKind,
List<String> sourceIntervalIds
) {
return new RuntimeActivityInterval(
intervalId,
from,
to,
Duration.between(from, to).getSeconds(),
activityType,
slot,
cardStatus,
drivingStatus,
registrationKey,
vehicleKey,
sourceKind,
sourceIntervalIds == null ? List.of() : List.copyOf(sourceIntervalIds),
false,
false,
"RAW_INTERVAL"
);
}
public RuntimeActivityInterval withTime(OffsetDateTime newFrom, OffsetDateTime newTo, boolean clipped) {
return new RuntimeActivityInterval(
intervalId,
newFrom,
newTo,
Duration.between(newFrom, newTo).getSeconds(),
activityType,
slot,
cardStatus,
drivingStatus,
registrationKey,
vehicleKey,
sourceKind,
sourceIntervalIds,
synthetic,
clipped,
level
);
}
public RuntimeActivityInterval asMerged(
String mergedIntervalId,
OffsetDateTime newTo,
List<String> mergedSourceIntervalIds
) {
return new RuntimeActivityInterval(
mergedIntervalId,
from,
newTo,
Duration.between(from, newTo).getSeconds(),
activityType,
slot,
cardStatus,
drivingStatus,
registrationKey,
vehicleKey,
sourceKind,
mergedSourceIntervalIds == null ? List.of() : List.copyOf(mergedSourceIntervalIds),
synthetic,
clippedToRequestedPeriod,
"MERGED_ACTIVITY"
);
}
}

View File

@ -1,15 +0,0 @@
package at.procon.eventhub.processing.model;
import java.time.OffsetDateTime;
import java.util.List;
public record RuntimeDriverTimeline(
String sourceKind,
OffsetDateTime loadedFrom,
OffsetDateTime loadedTo,
List<RuntimeVehicleUsageInterval> vehicleUsageIntervals,
List<RuntimeActivityInterval> activityIntervals,
List<RuntimeSupportEvent> supportEvents,
List<RuntimeExtractionWarning> warnings
) {
}

View File

@ -1,8 +0,0 @@
package at.procon.eventhub.processing.model;
public record RuntimeExtractionWarning(
String code,
String message,
String rawRecordPath
) {
}

View File

@ -1,30 +0,0 @@
package at.procon.eventhub.processing.model;
import java.math.BigDecimal;
import java.time.OffsetDateTime;
public record RuntimeSupportEvent(
String eventId,
String driverKey,
OffsetDateTime occurredAt,
String eventDomain,
String eventType,
String eventLifecycle,
String slot,
String registrationKey,
String vehicleKey,
String country,
String region,
String countryFrom,
String countryTo,
String operation,
BigDecimal latitude,
BigDecimal longitude,
String authenticationStatus,
Long odometerKm,
String code,
BigDecimal avgSpeedKmh,
BigDecimal maxSpeedKmh,
String rawRecordPath
) {
}

View File

@ -1,39 +0,0 @@
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

@ -1,50 +0,0 @@
package at.procon.eventhub.processing.model;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.UUID;
public record RuntimeVehicleUsageInterval(
UUID sessionId,
String driverKey,
String intervalId,
OffsetDateTime from,
OffsetDateTime to,
long durationSeconds,
Long odometerBeginKm,
Long odometerEndKm,
String registrationKey,
String vehicleKey,
String sourceKind,
List<String> sourceIntervalIds
) {
public static RuntimeVehicleUsageInterval resolved(
UUID sessionId,
String driverKey,
String intervalId,
OffsetDateTime from,
OffsetDateTime to,
Long odometerBeginKm,
Long odometerEndKm,
String registrationKey,
String vehicleKey,
String sourceKind,
List<String> sourceIntervalIds
) {
return new RuntimeVehicleUsageInterval(
sessionId,
driverKey,
intervalId,
from,
to,
to == null ? 0L : Duration.between(from, to).getSeconds(),
odometerBeginKm,
odometerEndKm,
registrationKey,
vehicleKey,
sourceKind,
sourceIntervalIds == null ? List.of() : List.copyOf(sourceIntervalIds)
);
}
}

View File

@ -3,6 +3,7 @@ package at.procon.eventhub.processing.model;
import at.procon.eventhub.reference.DriverCardNumberNormalizer; import at.procon.eventhub.reference.DriverCardNumberNormalizer;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -16,7 +17,7 @@ public record UnifiedRuntimeProcessingRequest(
String tenantKey, String tenantKey,
Set<UnifiedEventSourceFamily> sourceFamilies, Set<UnifiedEventSourceFamily> sourceFamilies,
UnifiedRuntimeEventBackend eventBackend, UnifiedRuntimeEventBackend eventBackend,
Set<String> sourceKinds, Set<UnifiedTachographSourceKind> tachographSourceKinds,
String driverKey, String driverKey,
Set<String> driverKeys, Set<String> driverKeys,
boolean includeAllDrivers, boolean includeAllDrivers,
@ -39,7 +40,7 @@ public record UnifiedRuntimeProcessingRequest(
String tenantKey, String tenantKey,
Set<UnifiedEventSourceFamily> sourceFamilies, Set<UnifiedEventSourceFamily> sourceFamilies,
UnifiedRuntimeEventBackend eventBackend, UnifiedRuntimeEventBackend eventBackend,
Set<String> sourceKinds, Set<UnifiedTachographSourceKind> tachographSourceKinds,
String driverKey, String driverKey,
Set<String> driverKeys, Set<String> driverKeys,
boolean includeAllDrivers, boolean includeAllDrivers,
@ -61,7 +62,7 @@ public record UnifiedRuntimeProcessingRequest(
tenantKey, tenantKey,
sourceFamilies, sourceFamilies,
eventBackend, eventBackend,
sourceKinds, tachographSourceKinds,
driverKey, driverKey,
driverKeys, driverKeys,
includeAllDrivers, includeAllDrivers,
@ -86,7 +87,7 @@ public record UnifiedRuntimeProcessingRequest(
throw new IllegalArgumentException("sourceFamilies must not be empty"); throw new IllegalArgumentException("sourceFamilies must not be empty");
} }
eventBackend = eventBackend == null ? UnifiedRuntimeEventBackend.SOURCE_DB : eventBackend; eventBackend = eventBackend == null ? UnifiedRuntimeEventBackend.SOURCE_DB : eventBackend;
sourceKinds = normalizeSourceKinds(sourceKinds); tachographSourceKinds = normalizeTachographSourceKinds(tachographSourceKinds);
sessionIds = normalizeSessionIds(sessionId, sessionIds); sessionIds = normalizeSessionIds(sessionId, sessionIds);
if (sessionId == null && !sessionIds.isEmpty()) { if (sessionId == null && !sessionIds.isEmpty()) {
sessionId = sessionIds.get(0); sessionId = sessionIds.get(0);
@ -447,7 +448,7 @@ public record UnifiedRuntimeProcessingRequest(
tenantKey, tenantKey,
Set.of(sourceInput.sourceFamily()), Set.of(sourceInput.sourceFamily()),
sourceInput.eventBackend(), sourceInput.eventBackend(),
sourceKinds, tachographSourceKinds,
driverKey, driverKey,
driverKeys, driverKeys,
includeAllDrivers, includeAllDrivers,
@ -484,7 +485,7 @@ public record UnifiedRuntimeProcessingRequest(
tenantKey, tenantKey,
sourceFamilies, sourceFamilies,
eventBackend, eventBackend,
sourceKinds, tachographSourceKinds,
value, value,
Set.of(), Set.of(),
false, false,
@ -506,15 +507,21 @@ public record UnifiedRuntimeProcessingRequest(
return includeAllDrivers || driverKeys.size() > 1 || (driverKey == null && !driverKeys.isEmpty()); return includeAllDrivers || driverKeys.size() > 1 || (driverKey == null && !driverKeys.isEmpty());
} }
public boolean includesSourceKind(String sourceKind) { public boolean includesTachographSourceKind(String sourceKind) {
if (sourceKind == null || sourceKind.isBlank()) { if (sourceKind == null || sourceKind.isBlank()) {
return true; return true;
} }
return sourceKinds.contains(sourceKind.trim().toUpperCase()); try {
return tachographSourceKinds.contains(UnifiedTachographSourceKind.valueOf(sourceKind.trim().toUpperCase()));
} catch (IllegalArgumentException ex) {
return false;
}
} }
public List<String> sourceKindNames() { public List<String> tachographSourceKindNames() {
return sourceKinds.stream().toList(); return tachographSourceKinds.stream()
.map(UnifiedTachographSourceKind::name)
.toList();
} }
private static Set<UnifiedEventSourceFamily> normalizeSourceFamilies( private static Set<UnifiedEventSourceFamily> normalizeSourceFamilies(
@ -593,20 +600,13 @@ public record UnifiedRuntimeProcessingRequest(
return Set.copyOf(normalized); return Set.copyOf(normalized);
} }
private static Set<String> normalizeSourceKinds( private static Set<UnifiedTachographSourceKind> normalizeTachographSourceKinds(
Set<String> values Set<UnifiedTachographSourceKind> values
) { ) {
if (values == null || values.isEmpty()) { if (values == null || values.isEmpty()) {
return Set.of("DRIVER_CARD", "VEHICLE_UNIT"); return Set.copyOf(Arrays.asList(UnifiedTachographSourceKind.values()));
} }
LinkedHashSet<String> normalized = new LinkedHashSet<>(); return Set.copyOf(values);
for (String value : values) {
String normalizedValue = normalizeUpper(value);
if (normalizedValue != null) {
normalized.add(normalizedValue);
}
}
return normalized.isEmpty() ? Set.of("DRIVER_CARD", "VEHICLE_UNIT") : Set.copyOf(normalized);
} }
private static boolean isExternalDbFamily(UnifiedEventSourceFamily family) { private static boolean isExternalDbFamily(UnifiedEventSourceFamily family) {

View File

@ -0,0 +1,6 @@
package at.procon.eventhub.processing.model;
public enum UnifiedTachographSourceKind {
DRIVER_CARD,
VEHICLE_UNIT
}

View File

@ -71,7 +71,7 @@ public class EventHubRuntimeEventLoader implements RuntimeDriverEventLoader, Run
request.driverCardNumber(), request.driverCardNumber(),
request.occurredFrom(), request.occurredFrom(),
request.occurredTo(), request.occurredTo(),
request.sourceKindNames(), request.tachographSourceKindNames(),
request.includeIntersectingIntervals() request.includeIntersectingIntervals()
); );
case YELLOWFOX_DB -> UnifiedDriverEventsRequest.forYellowFoxDbDriver( case YELLOWFOX_DB -> UnifiedDriverEventsRequest.forYellowFoxDbDriver(
@ -100,7 +100,7 @@ public class EventHubRuntimeEventLoader implements RuntimeDriverEventLoader, Run
vehicleRef.registrationNumber(), vehicleRef.registrationNumber(),
request.vehicleOccurredFrom(), request.vehicleOccurredFrom(),
request.vehicleOccurredTo(), request.vehicleOccurredTo(),
request.sourceKindNames(), request.tachographSourceKindNames(),
request.includeIntersectingIntervals() request.includeIntersectingIntervals()
); );
case YELLOWFOX_DB -> UnifiedVehicleEventsRequest.forYellowFoxDb( case YELLOWFOX_DB -> UnifiedVehicleEventsRequest.forYellowFoxDb(

View File

@ -7,12 +7,12 @@ import at.procon.eventhub.processing.dto.RuntimeVehicleEvidenceAttachmentDecisio
import at.procon.eventhub.processing.dto.RuntimeVehicleUsageIntervalDebugDto; import at.procon.eventhub.processing.dto.RuntimeVehicleUsageIntervalDebugDto;
import at.procon.eventhub.processing.eventprocessing.partition.RuntimeEventScopeClassifier; import at.procon.eventhub.processing.eventprocessing.partition.RuntimeEventScopeClassifier;
import at.procon.eventhub.processing.eventprocessing.partition.RuntimeEventScopeType; import at.procon.eventhub.processing.eventprocessing.partition.RuntimeEventScopeType;
import at.procon.eventhub.processing.model.RuntimeDriverTimeline;
import at.procon.eventhub.processing.model.RuntimeDriverVehicleEvidenceAttachmentResult; import at.procon.eventhub.processing.model.RuntimeDriverVehicleEvidenceAttachmentResult;
import at.procon.eventhub.processing.model.RuntimeVehicleUsageInterval;
import at.procon.eventhub.processing.support.RuntimeDriverWorkingTimeAdapter;
import at.procon.eventhub.processing.support.RuntimeEventIdentityResolver; import at.procon.eventhub.processing.support.RuntimeEventIdentityResolver;
import at.procon.eventhub.processing.support.RuntimeEntityReferenceResolver; import at.procon.eventhub.processing.support.TachographRuntimeIdentityResolver;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval;
import at.procon.eventhub.tachographfilesession.service.TachographDriverWorkingTimeAdapter;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.ArrayList; import java.util.ArrayList;
@ -63,14 +63,14 @@ public class RuntimeDriverVehicleEvidenceAttachmentService {
int vehicleEvidencePaddingMinutes, int vehicleEvidencePaddingMinutes,
boolean includeDebug boolean includeDebug
) { ) {
RuntimeDriverTimeline timeline = timelineReconstructor.reconstruct( ResolvedDriverTimeline timeline = timelineReconstructor.reconstruct(
null, null,
driverKey, driverKey,
directDriverEvents == null ? List.of() : directDriverEvents directDriverEvents == null ? List.of() : directDriverEvents
); );
List<DriverWorkingTimeVehicleUsageInterval> vehicleUsageIntervals = mergeVehicleUsageIntervals(timeline.vehicleUsageIntervals()) List<DriverWorkingTimeVehicleUsageInterval> vehicleUsageIntervals = mergeVehicleUsageIntervals(timeline.vehicleUsageIntervals())
.stream() .stream()
.map(RuntimeDriverWorkingTimeAdapter::toVehicleUsageInterval) .map(TachographDriverWorkingTimeAdapter::toVehicleUsageInterval)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.toList(); .toList();
return attachVehicleEvidence( return attachVehicleEvidence(
@ -277,8 +277,8 @@ public class RuntimeDriverVehicleEvidenceAttachmentService {
private Set<String> vehicleKeys(EventHubEventDto event) { private Set<String> vehicleKeys(EventHubEventDto event) {
LinkedHashSet<String> result = new LinkedHashSet<>(); LinkedHashSet<String> result = new LinkedHashSet<>();
String vehicleKey = RuntimeEntityReferenceResolver.vehicleKey(event); String vehicleKey = TachographRuntimeIdentityResolver.vehicleKey(event);
String registrationKey = RuntimeEntityReferenceResolver.registrationKey(event); String registrationKey = TachographRuntimeIdentityResolver.registrationKey(event);
add(result, vehicleKey); add(result, vehicleKey);
add(result, registrationKey); add(result, registrationKey);
if (vehicleKey != null) { if (vehicleKey != null) {
@ -316,22 +316,22 @@ public class RuntimeDriverVehicleEvidenceAttachmentService {
} }
} }
private List<RuntimeVehicleUsageInterval> mergeVehicleUsageIntervals(List<RuntimeVehicleUsageInterval> intervals) { private List<ResolvedVehicleUsageInterval> mergeVehicleUsageIntervals(List<ResolvedVehicleUsageInterval> intervals) {
if (intervals == null || intervals.isEmpty()) { if (intervals == null || intervals.isEmpty()) {
return List.of(); return List.of();
} }
List<RuntimeVehicleUsageInterval> sorted = intervals.stream() List<ResolvedVehicleUsageInterval> sorted = intervals.stream()
.sorted(Comparator.comparing(RuntimeVehicleUsageInterval::from, Comparator.nullsLast(Comparator.naturalOrder())) .sorted(Comparator.comparing(ResolvedVehicleUsageInterval::from, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(RuntimeVehicleUsageInterval::to, Comparator.nullsLast(Comparator.naturalOrder())) .thenComparing(ResolvedVehicleUsageInterval::to, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(RuntimeVehicleUsageInterval::intervalId, Comparator.nullsLast(String::compareTo))) .thenComparing(ResolvedVehicleUsageInterval::intervalId, Comparator.nullsLast(String::compareTo)))
.toList(); .toList();
List<RuntimeVehicleUsageInterval> merged = new ArrayList<>(); List<ResolvedVehicleUsageInterval> merged = new ArrayList<>();
for (RuntimeVehicleUsageInterval next : sorted) { for (ResolvedVehicleUsageInterval next : sorted) {
if (merged.isEmpty()) { if (merged.isEmpty()) {
merged.add(next); merged.add(next);
continue; continue;
} }
RuntimeVehicleUsageInterval current = merged.get(merged.size() - 1); ResolvedVehicleUsageInterval current = merged.get(merged.size() - 1);
if (canMerge(current, next)) { if (canMerge(current, next)) {
merged.set(merged.size() - 1, merge(current, next)); merged.set(merged.size() - 1, merge(current, next));
} else { } else {
@ -341,7 +341,7 @@ public class RuntimeDriverVehicleEvidenceAttachmentService {
return List.copyOf(merged); return List.copyOf(merged);
} }
private boolean canMerge(RuntimeVehicleUsageInterval left, RuntimeVehicleUsageInterval right) { private boolean canMerge(ResolvedVehicleUsageInterval left, ResolvedVehicleUsageInterval right) {
if (left == null || right == null || left.to() == null || right.from() == null) { if (left == null || right == null || left.to() == null || right.from() == null) {
return false; return false;
} }
@ -351,7 +351,7 @@ public class RuntimeDriverVehicleEvidenceAttachmentService {
&& !right.from().isAfter(left.to().plusSeconds(1)); && !right.from().isAfter(left.to().plusSeconds(1));
} }
private RuntimeVehicleUsageInterval merge(RuntimeVehicleUsageInterval left, RuntimeVehicleUsageInterval right) { private ResolvedVehicleUsageInterval merge(ResolvedVehicleUsageInterval left, ResolvedVehicleUsageInterval right) {
LinkedHashSet<String> sourceIntervalIds = new LinkedHashSet<>(); LinkedHashSet<String> sourceIntervalIds = new LinkedHashSet<>();
if (left.sourceIntervalIds() != null) { if (left.sourceIntervalIds() != null) {
sourceIntervalIds.addAll(left.sourceIntervalIds()); sourceIntervalIds.addAll(left.sourceIntervalIds());
@ -363,7 +363,7 @@ public class RuntimeDriverVehicleEvidenceAttachmentService {
if (right.to() != null && (end == null || right.to().isAfter(end))) { if (right.to() != null && (end == null || right.to().isAfter(end))) {
end = right.to(); end = right.to();
} }
return RuntimeVehicleUsageInterval.resolved( return ResolvedVehicleUsageInterval.resolved(
left.sessionId(), left.sessionId(),
left.driverKey(), left.driverKey(),
left.intervalId(), left.intervalId(),

View File

@ -11,7 +11,7 @@ import at.procon.eventhub.processing.model.RuntimeDriverVehicleEvidenceAttachmen
import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle; import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle;
import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest; import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest;
import at.procon.eventhub.processing.support.RuntimeEventIdentityResolver; import at.procon.eventhub.processing.support.RuntimeEventIdentityResolver;
import at.procon.eventhub.processing.support.RuntimeEntityReferenceResolver; import at.procon.eventhub.processing.support.TachographRuntimeIdentityResolver;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
@ -276,7 +276,7 @@ public class RuntimeDriverWorkingTimeScopeProcessingService {
} }
private String driverKey(EventHubEventDto event) { private String driverKey(EventHubEventDto event) {
return RuntimeEntityReferenceResolver.driverKey(event); return TachographRuntimeIdentityResolver.driverKey(event);
} }
private JsonNode rawPayload(EventHubEventDto event) { private JsonNode rawPayload(EventHubEventDto event) {

View File

@ -3,8 +3,9 @@ package at.procon.eventhub.processing.service;
import at.procon.eventhub.dto.EventHubEventDto; import at.procon.eventhub.dto.EventHubEventDto;
import at.procon.eventhub.dto.EventLifecycle; import at.procon.eventhub.dto.EventLifecycle;
import at.procon.eventhub.dto.EventType; import at.procon.eventhub.dto.EventType;
import at.procon.eventhub.processing.model.RuntimeTimelineEventBundle;
import at.procon.eventhub.processing.support.RuntimeEventIdentityResolver; 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.time.OffsetDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -15,23 +16,23 @@ final class RuntimeIntervalEventWindowSelector {
private RuntimeIntervalEventWindowSelector() { private RuntimeIntervalEventWindowSelector() {
} }
static RuntimeTimelineEventBundle filterBundle( static TachographTimelineEventBundle filterBundle(
RuntimeTimelineEventBundle bundle, TachographTimelineEventBundle bundle,
OffsetDateTime occurredFrom, OffsetDateTime occurredFrom,
OffsetDateTime occurredTo, OffsetDateTime occurredTo,
boolean includeIntersectingIntervals boolean includeIntersectingIntervals
) { ) {
if (bundle == null) { if (bundle == null) {
return RuntimeTimelineEventBundle.empty(); return new TachographTimelineEventBundle(List.of(), List.of(), List.of());
} }
return new RuntimeTimelineEventBundle( return new TachographTimelineEventBundle(
filterIntervalEvents(bundle.activityEvents(), occurredFrom, occurredTo, includeIntersectingIntervals), filterIntervalEvents(bundle.activityEvents(), occurredFrom, occurredTo, includeIntersectingIntervals),
filterIntervalEvents(bundle.vehicleUsageEvents(), occurredFrom, occurredTo, includeIntersectingIntervals), filterIntervalEvents(bundle.vehicleUsageEvents(), occurredFrom, occurredTo, includeIntersectingIntervals),
filterPointEvents(bundle.supportEvents(), occurredFrom, occurredTo) filterPointEvents(bundle.supportEvents(), occurredFrom, occurredTo)
); );
} }
static List<EventHubEventDto> filterIntervalEvents( private static List<EventHubEventDto> filterIntervalEvents(
List<EventHubEventDto> events, List<EventHubEventDto> events,
OffsetDateTime occurredFrom, OffsetDateTime occurredFrom,
OffsetDateTime occurredTo, OffsetDateTime occurredTo,
@ -58,14 +59,11 @@ final class RuntimeIntervalEventWindowSelector {
return List.copyOf(result); return List.copyOf(result);
} }
static List<EventHubEventDto> filterPointEvents( private static List<EventHubEventDto> filterPointEvents(
List<EventHubEventDto> events, List<EventHubEventDto> events,
OffsetDateTime occurredFrom, OffsetDateTime occurredFrom,
OffsetDateTime occurredTo OffsetDateTime occurredTo
) { ) {
if (events == null || events.isEmpty()) {
return List.of();
}
return events.stream() return events.stream()
.filter(event -> withinWindow(event.occurredAt(), occurredFrom, occurredTo)) .filter(event -> withinWindow(event.occurredAt(), occurredFrom, occurredTo))
.toList(); .toList();
@ -89,6 +87,27 @@ final class RuntimeIntervalEventWindowSelector {
return RuntimeEventIdentityResolver.runtimeIntervalKey(event); 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 static final class IntervalGroup {
private final List<EventHubEventDto> events = new ArrayList<>(); private final List<EventHubEventDto> events = new ArrayList<>();
private OffsetDateTime startedAt; private OffsetDateTime startedAt;

View File

@ -121,7 +121,7 @@ public class TachographDbRuntimeEventLoader implements RuntimeDriverEventLoader,
) { ) {
return definitionRegistry.definitions().stream() return definitionRegistry.definitions().stream()
.filter(definition -> !"VEHICLE".equals(definition.entityAxis())) .filter(definition -> !"VEHICLE".equals(definition.entityAxis()))
.filter(definition -> request.includesSourceKind(definition.sourceKind())) .filter(definition -> request.includesTachographSourceKind(definition.sourceKind()))
.toList(); .toList();
} }
@ -130,7 +130,7 @@ public class TachographDbRuntimeEventLoader implements RuntimeDriverEventLoader,
) { ) {
return definitionRegistry.definitions().stream() return definitionRegistry.definitions().stream()
.filter(definition -> !"DRIVER".equals(definition.entityAxis())) .filter(definition -> !"DRIVER".equals(definition.entityAxis()))
.filter(definition -> request.includesSourceKind(definition.sourceKind())) .filter(definition -> request.includesTachographSourceKind(definition.sourceKind()))
.toList(); .toList();
} }

View File

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

View File

@ -1,10 +1,9 @@
package at.procon.eventhub.processing.service; package at.procon.eventhub.processing.service;
import at.procon.eventhub.processing.model.RuntimeDriverTimeline;
import at.procon.eventhub.processing.model.UnifiedDriverTimelineRequest; import at.procon.eventhub.processing.model.UnifiedDriverTimelineRequest;
import at.procon.eventhub.processing.model.UnifiedEventSourceFamily; import at.procon.eventhub.processing.model.UnifiedEventSourceFamily;
import at.procon.eventhub.tachographfilesession.support.RuntimeTimelineCompatibilityAdapter;
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession; import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import at.procon.eventhub.tachographfilesession.model.TachographFileSession; import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
import at.procon.eventhub.tachographfilesession.service.DriverNotFoundInSessionException; import at.procon.eventhub.tachographfilesession.service.DriverNotFoundInSessionException;
import at.procon.eventhub.tachographfilesession.service.EventBackedDriverTimelineBuilder; import at.procon.eventhub.tachographfilesession.service.EventBackedDriverTimelineBuilder;
@ -32,15 +31,13 @@ public class TachographFileSessionUnifiedDriverTimelineSource implements Unified
} }
@Override @Override
public RuntimeDriverTimeline loadDriverTimeline(UnifiedDriverTimelineRequest request) { public ResolvedDriverTimeline loadDriverTimeline(UnifiedDriverTimelineRequest request) {
TachographFileSession session = repository.find(request.sessionId()) TachographFileSession session = repository.find(request.sessionId())
.orElseThrow(() -> new TachographFileSessionNotFoundException(request.sessionId())); .orElseThrow(() -> new TachographFileSessionNotFoundException(request.sessionId()));
DriverExtractionSession driver = session.driversByKey().get(request.driverKey()); DriverExtractionSession driver = session.driversByKey().get(request.driverKey());
if (driver == null) { if (driver == null) {
throw new DriverNotFoundInSessionException(request.sessionId(), request.driverKey()); throw new DriverNotFoundInSessionException(request.sessionId(), request.driverKey());
} }
return RuntimeTimelineCompatibilityAdapter.fromResolvedDriverTimeline( return eventBackedDriverTimelineBuilder.build(session, driver);
eventBackedDriverTimelineBuilder.build(session, driver)
);
} }
} }

View File

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

View File

@ -1,7 +1,7 @@
package at.procon.eventhub.processing.service; package at.procon.eventhub.processing.service;
import at.procon.eventhub.processing.model.RuntimeDriverTimeline;
import at.procon.eventhub.processing.model.UnifiedDriverTimelineRequest; import at.procon.eventhub.processing.model.UnifiedDriverTimelineRequest;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import java.util.List; import java.util.List;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -14,7 +14,7 @@ public class UnifiedDriverTimelineService {
this.timelineSources = List.copyOf(timelineSources); this.timelineSources = List.copyOf(timelineSources);
} }
public RuntimeDriverTimeline loadDriverTimeline(UnifiedDriverTimelineRequest request) { public ResolvedDriverTimeline loadDriverTimeline(UnifiedDriverTimelineRequest request) {
return timelineSources.stream() return timelineSources.stream()
.filter(source -> source.supports(request)) .filter(source -> source.supports(request))
.findFirst() .findFirst()

View File

@ -1,11 +1,11 @@
package at.procon.eventhub.processing.service; package at.procon.eventhub.processing.service;
import at.procon.eventhub.processing.model.RuntimeDriverTimeline;
import at.procon.eventhub.processing.model.UnifiedDriverTimelineRequest; import at.procon.eventhub.processing.model.UnifiedDriverTimelineRequest;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
public interface UnifiedDriverTimelineSource { public interface UnifiedDriverTimelineSource {
boolean supports(UnifiedDriverTimelineRequest request); boolean supports(UnifiedDriverTimelineRequest request);
RuntimeDriverTimeline loadDriverTimeline(UnifiedDriverTimelineRequest request); ResolvedDriverTimeline loadDriverTimeline(UnifiedDriverTimelineRequest request);
} }

View File

@ -4,13 +4,13 @@ import at.procon.eventhub.dto.EventDomain;
import at.procon.eventhub.dto.EventHubEventDto; import at.procon.eventhub.dto.EventHubEventDto;
import at.procon.eventhub.dto.EventLifecycle; import at.procon.eventhub.dto.EventLifecycle;
import at.procon.eventhub.dto.EventType; import at.procon.eventhub.dto.EventType;
import at.procon.eventhub.processing.model.RuntimeActivityInterval;
import at.procon.eventhub.processing.model.RuntimeDriverTimeline;
import at.procon.eventhub.processing.model.RuntimeExtractionWarning;
import at.procon.eventhub.processing.model.RuntimeSupportEvent;
import at.procon.eventhub.processing.model.RuntimeVehicleUsageInterval;
import at.procon.eventhub.processing.support.RuntimeEventIdentityResolver; import at.procon.eventhub.processing.support.RuntimeEventIdentityResolver;
import at.procon.eventhub.processing.support.RuntimeEntityReferenceResolver; import at.procon.eventhub.processing.support.TachographRuntimeIdentityResolver;
import at.procon.eventhub.tachographfilesession.model.ExtractedSupportEvent;
import at.procon.eventhub.tachographfilesession.model.ExtractionWarning;
import at.procon.eventhub.tachographfilesession.model.ResolvedActivityInterval;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.Duration; import java.time.Duration;
@ -27,7 +27,7 @@ import org.springframework.stereotype.Service;
@Service @Service
public class UnifiedEventTimelineReconstructor { public class UnifiedEventTimelineReconstructor {
public RuntimeDriverTimeline reconstruct( public ResolvedDriverTimeline reconstruct(
UUID sessionId, UUID sessionId,
String driverKey, String driverKey,
List<EventHubEventDto> events List<EventHubEventDto> events
@ -35,23 +35,23 @@ public class UnifiedEventTimelineReconstructor {
return reconstruct(sessionId, driverKey, events, List.of(), null); return reconstruct(sessionId, driverKey, events, List.of(), null);
} }
public RuntimeDriverTimeline reconstruct( public ResolvedDriverTimeline reconstruct(
UUID sessionId, UUID sessionId,
String driverKey, String driverKey,
List<EventHubEventDto> events, List<EventHubEventDto> events,
List<RuntimeExtractionWarning> warnings, List<ExtractionWarning> warnings,
String sourceKind String sourceKind
) { ) {
List<EventHubEventDto> safeEvents = events == null ? List.of() : List.copyOf(events); List<EventHubEventDto> safeEvents = events == null ? List.of() : List.copyOf(events);
List<RuntimeActivityInterval> activityIntervals = reconstructActivityIntervals(safeEvents); List<ResolvedActivityInterval> activityIntervals = reconstructActivityIntervals(safeEvents);
List<RuntimeVehicleUsageInterval> vehicleUsageIntervals = List<ResolvedVehicleUsageInterval> vehicleUsageIntervals =
reconstructVehicleUsageIntervals(sessionId, driverKey, safeEvents); reconstructVehicleUsageIntervals(sessionId, driverKey, safeEvents);
List<RuntimeSupportEvent> supportEvents = reconstructSupportEvents(safeEvents); List<ExtractedSupportEvent> supportEvents = reconstructSupportEvents(safeEvents);
List<RuntimeExtractionWarning> mergedWarnings = warnings == null ? List.of() : List.copyOf(new LinkedHashSet<>(warnings)); List<ExtractionWarning> mergedWarnings = warnings == null ? List.of() : List.copyOf(new LinkedHashSet<>(warnings));
OffsetDateTime loadedFrom = minTimestamp(activityIntervals, vehicleUsageIntervals, supportEvents); OffsetDateTime loadedFrom = minTimestamp(activityIntervals, vehicleUsageIntervals, supportEvents);
OffsetDateTime loadedTo = maxTimestamp(activityIntervals, vehicleUsageIntervals, supportEvents); OffsetDateTime loadedTo = maxTimestamp(activityIntervals, vehicleUsageIntervals, supportEvents);
return new RuntimeDriverTimeline( return new ResolvedDriverTimeline(
resolveSourceKind(safeEvents, sourceKind), resolveSourceKind(safeEvents, sourceKind),
loadedFrom, loadedFrom,
loadedTo, loadedTo,
@ -62,7 +62,7 @@ public class UnifiedEventTimelineReconstructor {
); );
} }
private List<RuntimeActivityInterval> reconstructActivityIntervals(List<EventHubEventDto> events) { private List<ResolvedActivityInterval> reconstructActivityIntervals(List<EventHubEventDto> events) {
Map<String, ActivityAccumulator> byIntervalId = new LinkedHashMap<>(); Map<String, ActivityAccumulator> byIntervalId = new LinkedHashMap<>();
for (EventHubEventDto event : events) { for (EventHubEventDto event : events) {
if (event.eventDomain() != EventDomain.DRIVER_ACTIVITY) { if (event.eventDomain() != EventDomain.DRIVER_ACTIVITY) {
@ -83,13 +83,13 @@ public class UnifiedEventTimelineReconstructor {
return byIntervalId.values().stream() return byIntervalId.values().stream()
.map(ActivityAccumulator::finish) .map(ActivityAccumulator::finish)
.filter(interval -> interval != null) .filter(interval -> interval != null)
.sorted(Comparator.comparing(RuntimeActivityInterval::from) .sorted(Comparator.comparing(ResolvedActivityInterval::from)
.thenComparing(RuntimeActivityInterval::to) .thenComparing(ResolvedActivityInterval::to)
.thenComparing(RuntimeActivityInterval::activityType, Comparator.nullsLast(String::compareTo))) .thenComparing(ResolvedActivityInterval::activityType, Comparator.nullsLast(String::compareTo)))
.toList(); .toList();
} }
private List<RuntimeVehicleUsageInterval> reconstructVehicleUsageIntervals( private List<ResolvedVehicleUsageInterval> reconstructVehicleUsageIntervals(
UUID sessionId, UUID sessionId,
String driverKey, String driverKey,
List<EventHubEventDto> events List<EventHubEventDto> events
@ -117,13 +117,13 @@ public class UnifiedEventTimelineReconstructor {
return byIntervalId.values().stream() return byIntervalId.values().stream()
.map(VehicleUsageAccumulator::finish) .map(VehicleUsageAccumulator::finish)
.filter(interval -> interval != null) .filter(interval -> interval != null)
.sorted(Comparator.comparing(RuntimeVehicleUsageInterval::from) .sorted(Comparator.comparing(ResolvedVehicleUsageInterval::from)
.thenComparing(RuntimeVehicleUsageInterval::to, Comparator.nullsLast(Comparator.naturalOrder()))) .thenComparing(ResolvedVehicleUsageInterval::to, Comparator.nullsLast(Comparator.naturalOrder())))
.toList(); .toList();
} }
private List<RuntimeSupportEvent> reconstructSupportEvents(List<EventHubEventDto> events) { private List<ExtractedSupportEvent> reconstructSupportEvents(List<EventHubEventDto> events) {
List<RuntimeSupportEvent> result = new ArrayList<>(); List<ExtractedSupportEvent> result = new ArrayList<>();
for (EventHubEventDto event : events) { for (EventHubEventDto event : events) {
if (event.eventDomain() == EventDomain.DRIVER_ACTIVITY) { if (event.eventDomain() == EventDomain.DRIVER_ACTIVITY) {
continue; continue;
@ -136,16 +136,16 @@ public class UnifiedEventTimelineReconstructor {
String eventId = firstNonBlank(text(raw, "supportEventId"), event.externalSourceEventId()); String eventId = firstNonBlank(text(raw, "supportEventId"), event.externalSourceEventId());
BigDecimal latitude = event.position() == null ? null : event.position().latitude(); BigDecimal latitude = event.position() == null ? null : event.position().latitude();
BigDecimal longitude = event.position() == null ? null : event.position().longitude(); BigDecimal longitude = event.position() == null ? null : event.position().longitude();
result.add(new RuntimeSupportEvent( result.add(new ExtractedSupportEvent(
eventId, eventId,
RuntimeEntityReferenceResolver.driverKey(event), TachographRuntimeIdentityResolver.driverKey(event),
event.occurredAt(), event.occurredAt(),
event.eventDomain().name(), event.eventDomain().name(),
text(raw, "supportEventType") == null ? event.eventType().name() : text(raw, "supportEventType"), text(raw, "supportEventType") == null ? event.eventType().name() : text(raw, "supportEventType"),
event.lifecycle().name(), event.lifecycle().name(),
text(raw, "slot"), text(raw, "slot"),
RuntimeEntityReferenceResolver.registrationKey(event), TachographRuntimeIdentityResolver.registrationKey(event),
RuntimeEntityReferenceResolver.vehicleKey(event), TachographRuntimeIdentityResolver.vehicleKey(event),
firstNonBlank(text(raw, "country"), detailText(event, "country")), firstNonBlank(text(raw, "country"), detailText(event, "country")),
text(raw, "region"), text(raw, "region"),
firstNonBlank(text(raw, "countryFrom"), detailText(event, "countryFrom")), firstNonBlank(text(raw, "countryFrom"), detailText(event, "countryFrom")),
@ -161,9 +161,9 @@ public class UnifiedEventTimelineReconstructor {
text(raw, "rawRecordPath") text(raw, "rawRecordPath")
)); ));
} }
result.sort(Comparator.comparing(RuntimeSupportEvent::occurredAt) result.sort(Comparator.comparing(ExtractedSupportEvent::occurredAt)
.thenComparing(RuntimeSupportEvent::eventDomain, Comparator.nullsLast(String::compareTo)) .thenComparing(ExtractedSupportEvent::eventDomain, Comparator.nullsLast(String::compareTo))
.thenComparing(RuntimeSupportEvent::eventId, Comparator.nullsLast(String::compareTo))); .thenComparing(ExtractedSupportEvent::eventId, Comparator.nullsLast(String::compareTo)));
return List.copyOf(result); return List.copyOf(result);
} }
@ -189,36 +189,36 @@ public class UnifiedEventTimelineReconstructor {
} }
private OffsetDateTime minTimestamp( private OffsetDateTime minTimestamp(
List<RuntimeActivityInterval> activityIntervals, List<ResolvedActivityInterval> activityIntervals,
List<RuntimeVehicleUsageInterval> vehicleUsageIntervals, List<ResolvedVehicleUsageInterval> vehicleUsageIntervals,
List<RuntimeSupportEvent> supportEvents List<ExtractedSupportEvent> supportEvents
) { ) {
OffsetDateTime min = null; OffsetDateTime min = null;
for (RuntimeActivityInterval interval : activityIntervals) { for (ResolvedActivityInterval interval : activityIntervals) {
min = min(min, interval.from()); min = min(min, interval.from());
} }
for (RuntimeVehicleUsageInterval interval : vehicleUsageIntervals) { for (ResolvedVehicleUsageInterval interval : vehicleUsageIntervals) {
min = min(min, interval.from()); min = min(min, interval.from());
} }
for (RuntimeSupportEvent supportEvent : supportEvents) { for (ExtractedSupportEvent supportEvent : supportEvents) {
min = min(min, supportEvent.occurredAt()); min = min(min, supportEvent.occurredAt());
} }
return min; return min;
} }
private OffsetDateTime maxTimestamp( private OffsetDateTime maxTimestamp(
List<RuntimeActivityInterval> activityIntervals, List<ResolvedActivityInterval> activityIntervals,
List<RuntimeVehicleUsageInterval> vehicleUsageIntervals, List<ResolvedVehicleUsageInterval> vehicleUsageIntervals,
List<RuntimeSupportEvent> supportEvents List<ExtractedSupportEvent> supportEvents
) { ) {
OffsetDateTime max = null; OffsetDateTime max = null;
for (RuntimeActivityInterval interval : activityIntervals) { for (ResolvedActivityInterval interval : activityIntervals) {
max = max(max, interval.to()); max = max(max, interval.to());
} }
for (RuntimeVehicleUsageInterval interval : vehicleUsageIntervals) { for (ResolvedVehicleUsageInterval interval : vehicleUsageIntervals) {
max = max(max, interval.to()); max = max(max, interval.to());
} }
for (RuntimeSupportEvent supportEvent : supportEvents) { for (ExtractedSupportEvent supportEvent : supportEvents) {
max = max(max, supportEvent.occurredAt()); max = max(max, supportEvent.occurredAt());
} }
return max; return max;
@ -370,11 +370,11 @@ public class UnifiedEventTimelineReconstructor {
} }
} }
private RuntimeActivityInterval finish() { private ResolvedActivityInterval finish() {
if (sample == null || startedAt == null || endedAt == null || !endedAt.isAfter(startedAt)) { if (sample == null || startedAt == null || endedAt == null || !endedAt.isAfter(startedAt)) {
return null; return null;
} }
return new RuntimeActivityInterval( return new ResolvedActivityInterval(
intervalId, intervalId,
startedAt, startedAt,
endedAt, endedAt,
@ -383,8 +383,8 @@ public class UnifiedEventTimelineReconstructor {
detailText(sample, "cardSlot"), detailText(sample, "cardSlot"),
detailText(sample, "cardStatus"), detailText(sample, "cardStatus"),
detailText(sample, "drivingStatus"), detailText(sample, "drivingStatus"),
RuntimeEntityReferenceResolver.registrationKey(sample), TachographRuntimeIdentityResolver.registrationKey(sample),
RuntimeEntityReferenceResolver.vehicleKey(sample), TachographRuntimeIdentityResolver.vehicleKey(sample),
text(raw, "sourceKind"), text(raw, "sourceKind"),
stringList(raw, "sourceRowIds"), stringList(raw, "sourceRowIds"),
booleanValue(raw, "synthetic"), booleanValue(raw, "synthetic"),
@ -427,11 +427,11 @@ public class UnifiedEventTimelineReconstructor {
} }
} }
private RuntimeVehicleUsageInterval finish() { private ResolvedVehicleUsageInterval finish() {
if (startedAt == null) { if (startedAt == null) {
return null; return null;
} }
return RuntimeVehicleUsageInterval.resolved( return ResolvedVehicleUsageInterval.resolved(
sessionId, sessionId,
driverKey, driverKey,
intervalId, intervalId,
@ -439,8 +439,8 @@ public class UnifiedEventTimelineReconstructor {
endedAt, endedAt,
odometerBeginKm, odometerBeginKm,
odometerEndKm, odometerEndKm,
sample == null ? null : RuntimeEntityReferenceResolver.registrationKey(sample), sample == null ? null : TachographRuntimeIdentityResolver.registrationKey(sample),
sample == null ? null : RuntimeEntityReferenceResolver.vehicleKey(sample), sample == null ? null : TachographRuntimeIdentityResolver.vehicleKey(sample),
text(raw, "sourceKind"), text(raw, "sourceKind"),
stringList(raw, "sourceRowIds") stringList(raw, "sourceRowIds")
); );

View File

@ -13,13 +13,14 @@ import at.procon.eventhub.processing.driverworkingtime.service.DriverWorkingTime
import at.procon.eventhub.processing.driverworkingtime.service.DriverWorkingTimeProcessingCore; import at.procon.eventhub.processing.driverworkingtime.service.DriverWorkingTimeProcessingCore;
import at.procon.eventhub.processing.driverworkingtime.service.DriverWorkingTimeReusableProjectionBuilder; import at.procon.eventhub.processing.driverworkingtime.service.DriverWorkingTimeReusableProjectionBuilder;
import at.procon.eventhub.processing.eventprocessing.support.RuntimeSupportEvidenceNormalizationResult; import at.procon.eventhub.processing.eventprocessing.support.RuntimeSupportEvidenceNormalizationResult;
import at.procon.eventhub.processing.eventprocessing.support.RuntimeSupportEvidenceEvent;
import at.procon.eventhub.processing.eventprocessing.support.RuntimeSupportEvidenceNormalizer; import at.procon.eventhub.processing.eventprocessing.support.RuntimeSupportEvidenceNormalizer;
import at.procon.eventhub.processing.model.RuntimeDriverTimeline;
import at.procon.eventhub.processing.model.RuntimeSupportEvent;
import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle; import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle;
import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest; import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest;
import at.procon.eventhub.processing.driverworkingtime.dto.DriverWorkingTimeProcessingResultDto; import at.procon.eventhub.processing.driverworkingtime.dto.DriverWorkingTimeProcessingResultDto;
import at.procon.eventhub.processing.support.RuntimeDriverWorkingTimeAdapter; import at.procon.eventhub.tachographfilesession.service.TachographDriverWorkingTimeAdapter;
import at.procon.eventhub.tachographfilesession.model.ExtractedSupportEvent;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent; import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent; import at.procon.eventhub.tachographfilesession.model.TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingDerivedProjectionBundle; import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingDerivedProjectionBundle;
@ -30,7 +31,7 @@ import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialIn
import at.procon.eventhub.tachographfilesession.model.TachographEsperSupportGeoEvent; import at.procon.eventhub.tachographfilesession.model.TachographEsperSupportGeoEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent; import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent; import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
import at.procon.eventhub.processing.support.RuntimeEntityReferenceResolver; import at.procon.eventhub.processing.support.TachographRuntimeIdentityResolver;
import java.time.Duration; import java.time.Duration;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.time.ZoneOffset; import java.time.ZoneOffset;
@ -106,7 +107,7 @@ public class UnifiedRuntimeDerivedProjectionService {
eventBundle.mergedEvents() eventBundle.mergedEvents()
); );
List<EventHubEventDto> normalizedEvents = normalizationResult.normalizedEvents(); List<EventHubEventDto> normalizedEvents = normalizationResult.normalizedEvents();
RuntimeDriverTimeline timeline = timelineReconstructor.reconstruct( ResolvedDriverTimeline timeline = timelineReconstructor.reconstruct(
runtimeSessionId(request), runtimeSessionId(request),
driverKey, driverKey,
normalizedEvents normalizedEvents
@ -149,7 +150,7 @@ public class UnifiedRuntimeDerivedProjectionService {
significantDrivingMinutes, significantDrivingMinutes,
minimumRestPeriodMinutes, minimumRestPeriodMinutes,
timeline.activityIntervals().stream() timeline.activityIntervals().stream()
.map(interval -> RuntimeDriverWorkingTimeAdapter.toActivityInterval( .map(interval -> TachographDriverWorkingTimeAdapter.toActivityInterval(
runtimeSessionId(request), runtimeSessionId(request),
driverKey, driverKey,
interval interval
@ -157,11 +158,11 @@ public class UnifiedRuntimeDerivedProjectionService {
.filter(Objects::nonNull) .filter(Objects::nonNull)
.toList(), .toList(),
timeline.vehicleUsageIntervals().stream() timeline.vehicleUsageIntervals().stream()
.map(RuntimeDriverWorkingTimeAdapter::toVehicleUsageInterval) .map(TachographDriverWorkingTimeAdapter::toVehicleUsageInterval)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.toList(), .toList(),
timeline.supportEvents().stream() timeline.supportEvents().stream()
.map(RuntimeDriverWorkingTimeAdapter::toSupportEvidenceEvent) .map(this::toSupportEvidenceEvent)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.toList(), .toList(),
notes notes
@ -206,11 +207,41 @@ public class UnifiedRuntimeDerivedProjectionService {
return request.sessionIds().size() == 1 ? request.sessionIds().get(0) : request.sessionId(); return request.sessionIds().size() == 1 ? request.sessionIds().get(0) : request.sessionId();
} }
private RuntimeSupportEvidenceEvent toSupportEvidenceEvent(ExtractedSupportEvent supportEvent) {
if (supportEvent == null || supportEvent.occurredAt() == null) {
return null;
}
return new RuntimeSupportEvidenceEvent(
supportEvent.eventId(),
null,
null,
supportEvent.eventDomain(),
supportEvent.eventType(),
supportEvent.eventLifecycle(),
supportEvent.driverKey(),
supportEvent.vehicleKey(),
supportEvent.registrationKey(),
supportEvent.occurredAt(),
supportEvent.occurredAt().toEpochSecond(),
supportEvent.latitude(),
supportEvent.longitude(),
supportEvent.country(),
supportEvent.region(),
supportEvent.countryFrom(),
supportEvent.countryTo(),
supportEvent.operation(),
supportEvent.odometerKm(),
supportEvent.avgSpeedKmh(),
supportEvent.maxSpeedKmh(),
java.util.Map.of("rawRecordPath", supportEvent.rawRecordPath())
);
}
private String resolveDriverKey( private String resolveDriverKey(
UnifiedRuntimeProcessingRequest request, UnifiedRuntimeProcessingRequest request,
List<EventHubEventDto> events List<EventHubEventDto> events
) { ) {
return RuntimeEntityReferenceResolver.requestDriverKey(request, events); return TachographRuntimeIdentityResolver.requestDriverKey(request, events);
} }
@ -405,12 +436,12 @@ public class UnifiedRuntimeDerivedProjectionService {
} }
private List<TachographEsperSupportGeoEvent> clipSupportGeoEvents( private List<TachographEsperSupportGeoEvent> clipSupportGeoEvents(
List<RuntimeSupportEvent> supportEvents, List<ExtractedSupportEvent> supportEvents,
String driverKey, String driverKey,
OffsetDateTime requestedFrom, OffsetDateTime requestedFrom,
OffsetDateTime requestedTo OffsetDateTime requestedTo
) { ) {
return (supportEvents == null ? List.<RuntimeSupportEvent>of() : supportEvents).stream() return (supportEvents == null ? List.<ExtractedSupportEvent>of() : supportEvents).stream()
.filter(event -> event.occurredAt() != null) .filter(event -> event.occurredAt() != null)
.filter(event -> driverKey == null || event.driverKey() == null || Objects.equals(driverKey, event.driverKey())) .filter(event -> driverKey == null || event.driverKey() == null || Objects.equals(driverKey, event.driverKey()))
.filter(event -> requestedFrom == null || !event.occurredAt().isBefore(requestedFrom)) .filter(event -> requestedFrom == null || !event.occurredAt().isBefore(requestedFrom))

View File

@ -1,10 +1,10 @@
package at.procon.eventhub.processing.service; package at.procon.eventhub.processing.service;
import at.procon.eventhub.dto.EventHubEventDto; import at.procon.eventhub.dto.EventHubEventDto;
import at.procon.eventhub.processing.model.RuntimeDriverTimeline;
import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle; import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle;
import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest; import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest;
import at.procon.eventhub.processing.support.RuntimeEntityReferenceResolver; import at.procon.eventhub.processing.support.TachographRuntimeIdentityResolver;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import java.util.List; import java.util.List;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -22,7 +22,7 @@ public class UnifiedRuntimeDriverTimelineService {
this.timelineReconstructor = timelineReconstructor; this.timelineReconstructor = timelineReconstructor;
} }
public RuntimeDriverTimeline loadDriverTimeline(UnifiedRuntimeProcessingRequest request) { public ResolvedDriverTimeline loadDriverTimeline(UnifiedRuntimeProcessingRequest request) {
UnifiedRuntimeEventBundle bundle = runtimeEventAssemblyService.assembleDriverScopedEvents(request); UnifiedRuntimeEventBundle bundle = runtimeEventAssemblyService.assembleDriverScopedEvents(request);
return timelineReconstructor.reconstruct( return timelineReconstructor.reconstruct(
null, null,
@ -35,6 +35,6 @@ public class UnifiedRuntimeDriverTimelineService {
UnifiedRuntimeProcessingRequest request, UnifiedRuntimeProcessingRequest request,
List<EventHubEventDto> events List<EventHubEventDto> events
) { ) {
return RuntimeEntityReferenceResolver.requestDriverKey(request, events); return TachographRuntimeIdentityResolver.requestDriverKey(request, events);
} }
} }

View File

@ -1,123 +0,0 @@
package at.procon.eventhub.processing.support;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeActivityInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeVehicleUsageInterval;
import at.procon.eventhub.processing.eventprocessing.support.RuntimeSupportEvidenceEvent;
import at.procon.eventhub.processing.model.RuntimeActivityInterval;
import at.procon.eventhub.processing.model.RuntimeSupportEvent;
import at.procon.eventhub.processing.model.RuntimeVehicleUsageInterval;
import java.util.List;
import java.util.UUID;
public final class RuntimeDriverWorkingTimeAdapter {
private RuntimeDriverWorkingTimeAdapter() {
}
public static DriverWorkingTimeActivityInterval toActivityInterval(
UUID sessionId,
String driverKey,
RuntimeActivityInterval interval
) {
if (interval == null || interval.from() == null || interval.to() == null) {
return null;
}
return new DriverWorkingTimeActivityInterval(
sessionId,
driverKey,
interval.intervalId(),
interval.activityType(),
interval.slot(),
interval.cardStatus(),
interval.drivingStatus(),
interval.registrationKey(),
interval.vehicleKey(),
interval.sourceKind(),
firstSourceIntervalId(interval),
lastSourceIntervalId(interval),
interval.from(),
interval.to(),
interval.from().toEpochSecond(),
interval.to().toEpochSecond(),
interval.durationSeconds(),
interval.sourceIntervalIds(),
interval.synthetic(),
interval.clippedToRequestedPeriod(),
interval.level()
);
}
public static DriverWorkingTimeVehicleUsageInterval toVehicleUsageInterval(RuntimeVehicleUsageInterval interval) {
if (interval == null || interval.from() == null) {
return null;
}
return new DriverWorkingTimeVehicleUsageInterval(
interval.sessionId(),
interval.driverKey(),
interval.intervalId(),
firstSourceIntervalId(interval),
lastSourceIntervalId(interval),
interval.from(),
interval.to(),
interval.from().toEpochSecond(),
interval.to() == null ? null : interval.to().toEpochSecond(),
interval.durationSeconds(),
interval.odometerBeginKm(),
interval.odometerEndKm(),
interval.registrationKey(),
interval.vehicleKey(),
interval.sourceKind(),
interval.sourceIntervalIds()
);
}
public static RuntimeSupportEvidenceEvent toSupportEvidenceEvent(RuntimeSupportEvent supportEvent) {
if (supportEvent == null || supportEvent.occurredAt() == null) {
return null;
}
return new RuntimeSupportEvidenceEvent(
supportEvent.eventId(),
null,
null,
supportEvent.eventDomain(),
supportEvent.eventType(),
supportEvent.eventLifecycle(),
supportEvent.driverKey(),
supportEvent.vehicleKey(),
supportEvent.registrationKey(),
supportEvent.occurredAt(),
supportEvent.occurredAt().toEpochSecond(),
supportEvent.latitude(),
supportEvent.longitude(),
supportEvent.country(),
supportEvent.region(),
supportEvent.countryFrom(),
supportEvent.countryTo(),
supportEvent.operation(),
supportEvent.odometerKm(),
supportEvent.avgSpeedKmh(),
supportEvent.maxSpeedKmh(),
java.util.Map.of("rawRecordPath", supportEvent.rawRecordPath())
);
}
private static String firstSourceIntervalId(RuntimeActivityInterval interval) {
return safe(interval.sourceIntervalIds()).isEmpty() ? interval.intervalId() : safe(interval.sourceIntervalIds()).getFirst();
}
private static String lastSourceIntervalId(RuntimeActivityInterval interval) {
return safe(interval.sourceIntervalIds()).isEmpty() ? interval.intervalId() : safe(interval.sourceIntervalIds()).getLast();
}
private static String firstSourceIntervalId(RuntimeVehicleUsageInterval interval) {
return safe(interval.sourceIntervalIds()).isEmpty() ? interval.intervalId() : safe(interval.sourceIntervalIds()).getFirst();
}
private static String lastSourceIntervalId(RuntimeVehicleUsageInterval interval) {
return safe(interval.sourceIntervalIds()).isEmpty() ? interval.intervalId() : safe(interval.sourceIntervalIds()).getLast();
}
private static <T> List<T> safe(List<T> values) {
return values == null ? List.of() : values;
}
}

View File

@ -29,9 +29,9 @@ public final class RuntimeEventIdentityResolver {
parts.add(nullToEmpty(event.eventType() == null ? null : event.eventType().name())); parts.add(nullToEmpty(event.eventType() == null ? null : event.eventType().name()));
parts.add(nullToEmpty(event.lifecycle() == null ? null : event.lifecycle().name())); parts.add(nullToEmpty(event.lifecycle() == null ? null : event.lifecycle().name()));
parts.add(normalizeTime(event.occurredAt())); parts.add(normalizeTime(event.occurredAt()));
parts.add(nullToEmpty(RuntimeEntityReferenceResolver.driverKey(event))); parts.add(nullToEmpty(TachographRuntimeIdentityResolver.driverKey(event)));
parts.add(nullToEmpty(RuntimeEntityReferenceResolver.registrationKey(event))); parts.add(nullToEmpty(TachographRuntimeIdentityResolver.registrationKey(event)));
parts.add(nullToEmpty(RuntimeEntityReferenceResolver.vehicleKey(event))); parts.add(nullToEmpty(TachographRuntimeIdentityResolver.vehicleKey(event)));
parts.add(isIntervalPointEvent(event) ? nullToEmpty(runtimeIntervalKey(event)) : ""); parts.add(isIntervalPointEvent(event) ? nullToEmpty(runtimeIntervalKey(event)) : "");
parts.add(nullToEmpty(firstNonBlank(text(raw, "activityType"), event.eventType() == null ? null : event.eventType().name()))); parts.add(nullToEmpty(firstNonBlank(text(raw, "activityType"), event.eventType() == null ? null : event.eventType().name())));
parts.add(nullToEmpty(firstNonBlank(text(raw, "slot"), text(raw, "cardSlot"), text(details, "cardSlot")))); parts.add(nullToEmpty(firstNonBlank(text(raw, "slot"), text(raw, "cardSlot"), text(details, "cardSlot"))));
@ -72,9 +72,9 @@ public final class RuntimeEventIdentityResolver {
parts.add("INTERVAL"); parts.add("INTERVAL");
parts.add(nullToEmpty(event.eventDomain() == null ? null : event.eventDomain().name())); parts.add(nullToEmpty(event.eventDomain() == null ? null : event.eventDomain().name()));
parts.add(nullToEmpty(intervalSemanticType(event, raw))); parts.add(nullToEmpty(intervalSemanticType(event, raw)));
parts.add(nullToEmpty(RuntimeEntityReferenceResolver.driverKey(event))); parts.add(nullToEmpty(TachographRuntimeIdentityResolver.driverKey(event)));
parts.add(nullToEmpty(RuntimeEntityReferenceResolver.registrationKey(event))); parts.add(nullToEmpty(TachographRuntimeIdentityResolver.registrationKey(event)));
parts.add(nullToEmpty(RuntimeEntityReferenceResolver.vehicleKey(event))); parts.add(nullToEmpty(TachographRuntimeIdentityResolver.vehicleKey(event)));
parts.add(nullToEmpty(intervalCardSlot(event, raw, details))); parts.add(nullToEmpty(intervalCardSlot(event, raw, details)));
parts.add(nullToEmpty(intervalCardStatus(event, raw, details))); parts.add(nullToEmpty(intervalCardStatus(event, raw, details)));
parts.add(nullToEmpty(intervalDrivingStatus(event, raw, details))); parts.add(nullToEmpty(intervalDrivingStatus(event, raw, details)));
@ -152,7 +152,7 @@ public final class RuntimeEventIdentityResolver {
} }
private static JsonNode rawPayload(EventHubEventDto event) { private static JsonNode rawPayload(EventHubEventDto event) {
return RuntimeEntityReferenceResolver.rawPayload(event); return TachographRuntimeIdentityResolver.rawPayload(event);
} }
private static JsonNode detailAttributes(EventHubEventDto event) { private static JsonNode detailAttributes(EventHubEventDto event) {

View File

@ -9,9 +9,9 @@ import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import java.util.List; import java.util.List;
public final class RuntimeEntityReferenceResolver { public final class TachographRuntimeIdentityResolver {
private RuntimeEntityReferenceResolver() { private TachographRuntimeIdentityResolver() {
} }
public static String driverKey(EventHubEventDto event) { public static String driverKey(EventHubEventDto event) {

View File

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

View File

@ -1,6 +1,5 @@
package at.procon.eventhub.tachographfilesession.service; package at.procon.eventhub.tachographfilesession.service;
import at.procon.eventhub.tachographfilesession.support.RuntimeTimelineCompatibilityAdapter;
import at.procon.eventhub.processing.service.UnifiedEventTimelineReconstructor; import at.procon.eventhub.processing.service.UnifiedEventTimelineReconstructor;
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession; import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
import at.procon.eventhub.tachographfilesession.model.ExtractionWarning; import at.procon.eventhub.tachographfilesession.model.ExtractionWarning;
@ -36,16 +35,12 @@ public class EventBackedDriverTimelineBuilder {
DriverExtractionSession driverSession DriverExtractionSession driverSession
) { ) {
TachographTimelineEventBundle bundle = eventBuilder.buildEventBundle(session, driverSession); TachographTimelineEventBundle bundle = eventBuilder.buildEventBundle(session, driverSession);
return RuntimeTimelineCompatibilityAdapter.toResolvedDriverTimeline( return timelineReconstructor.reconstruct(
timelineReconstructor.reconstruct(
session.sessionId(), session.sessionId(),
driverSession.driverKey(), driverSession.driverKey(),
bundle.allEvents(), bundle.allEvents(),
mergeWarnings(session.warnings(), driverSession.warnings()).stream() mergeWarnings(session.warnings(), driverSession.warnings()),
.map(RuntimeTimelineCompatibilityAdapter::fromExtractionWarning)
.toList(),
fallbackSourceKind(session) fallbackSourceKind(session)
)
); );
} }

View File

@ -2,7 +2,6 @@ package at.procon.eventhub.tachographfilesession.service;
import at.procon.eventhub.dto.EventHubEventDto; import at.procon.eventhub.dto.EventHubEventDto;
import at.procon.eventhub.processing.service.UnifiedEventTimelineReconstructor; import at.procon.eventhub.processing.service.UnifiedEventTimelineReconstructor;
import at.procon.eventhub.tachographfilesession.support.RuntimeTimelineCompatibilityAdapter;
import at.procon.eventhub.service.EventAcquisitionRecordKeyService; import at.procon.eventhub.service.EventAcquisitionRecordKeyService;
import at.procon.eventhub.service.EventHubEventSorter; import at.procon.eventhub.service.EventHubEventSorter;
import at.procon.eventhub.tachographfilesession.dto.CreateTachographCompositeSessionRequest; import at.procon.eventhub.tachographfilesession.dto.CreateTachographCompositeSessionRequest;
@ -120,16 +119,12 @@ public class TachographCompositeSessionService {
throw new DriverNotFoundInCompositeSessionException(compositeSessionId, driverKey); throw new DriverNotFoundInCompositeSessionException(compositeSessionId, driverKey);
} }
List<EventHubEventDto> mergedEvents = mergeDriverEvents(sourceSessions, driverKey); List<EventHubEventDto> mergedEvents = mergeDriverEvents(sourceSessions, driverKey);
return RuntimeTimelineCompatibilityAdapter.toResolvedDriverTimeline( return timelineReconstructor.reconstruct(
timelineReconstructor.reconstruct(
compositeSessionId, compositeSessionId,
driverKey, driverKey,
mergedEvents, mergedEvents,
mergeWarnings(sourceSessions, driverKey).stream() mergeWarnings(sourceSessions, driverKey),
.map(RuntimeTimelineCompatibilityAdapter::fromExtractionWarning)
.toList(),
"COMPOSITE_TACHOGRAPH_FILE_SESSION" "COMPOSITE_TACHOGRAPH_FILE_SESSION"
)
); );
} }

View File

@ -3,7 +3,6 @@ package at.procon.eventhub.tachographfilesession.service;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import at.procon.eventhub.dto.EventHubEventDto; import at.procon.eventhub.dto.EventHubEventDto;
import at.procon.eventhub.processing.service.UnifiedEventTimelineReconstructor; import at.procon.eventhub.processing.service.UnifiedEventTimelineReconstructor;
import at.procon.eventhub.tachographfilesession.support.RuntimeTimelineCompatibilityAdapter;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline; import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval; import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
@ -52,12 +51,10 @@ public class TachographEventTimelineReconstructionHelper {
String fallbackDriverKey, String fallbackDriverKey,
List<EventHubEventDto> events List<EventHubEventDto> events
) { ) {
ResolvedDriverTimeline reconstructed = RuntimeTimelineCompatibilityAdapter.toResolvedDriverTimeline( ResolvedDriverTimeline reconstructed = timelineReconstructor.reconstruct(
timelineReconstructor.reconstruct(
fallbackSessionId == null ? new UUID(0L, 0L) : fallbackSessionId, fallbackSessionId == null ? new UUID(0L, 0L) : fallbackSessionId,
fallbackDriverKey, fallbackDriverKey,
safe(events) safe(events)
)
); );
return new ResolvedDriverTimeline( return new ResolvedDriverTimeline(
reconstructed.sourceKind(), reconstructed.sourceKind(),

View File

@ -1,237 +0,0 @@
package at.procon.eventhub.tachographfilesession.support;
import at.procon.eventhub.processing.model.RuntimeActivityInterval;
import at.procon.eventhub.processing.model.RuntimeDriverTimeline;
import at.procon.eventhub.processing.model.RuntimeExtractionWarning;
import at.procon.eventhub.processing.model.RuntimeSupportEvent;
import at.procon.eventhub.processing.model.RuntimeVehicleUsageInterval;
import at.procon.eventhub.tachographfilesession.model.ExtractedSupportEvent;
import at.procon.eventhub.tachographfilesession.model.ExtractionWarning;
import at.procon.eventhub.tachographfilesession.model.ResolvedActivityInterval;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval;
import java.util.List;
public final class RuntimeTimelineCompatibilityAdapter {
private RuntimeTimelineCompatibilityAdapter() {
}
public static RuntimeDriverTimeline fromResolvedDriverTimeline(ResolvedDriverTimeline timeline) {
if (timeline == null) {
return null;
}
return new RuntimeDriverTimeline(
timeline.sourceKind(),
timeline.loadedFrom(),
timeline.loadedTo(),
safe(timeline.vehicleUsageIntervals()).stream()
.map(RuntimeTimelineCompatibilityAdapter::fromResolvedVehicleUsageInterval)
.toList(),
safe(timeline.activityIntervals()).stream()
.map(RuntimeTimelineCompatibilityAdapter::fromResolvedActivityInterval)
.toList(),
safe(timeline.supportEvents()).stream()
.map(RuntimeTimelineCompatibilityAdapter::fromExtractedSupportEvent)
.toList(),
safe(timeline.warnings()).stream()
.map(RuntimeTimelineCompatibilityAdapter::fromExtractionWarning)
.toList()
);
}
public static ResolvedDriverTimeline toResolvedDriverTimeline(RuntimeDriverTimeline timeline) {
if (timeline == null) {
return null;
}
return new ResolvedDriverTimeline(
timeline.sourceKind(),
timeline.loadedFrom(),
timeline.loadedTo(),
safe(timeline.vehicleUsageIntervals()).stream()
.map(RuntimeTimelineCompatibilityAdapter::toResolvedVehicleUsageInterval)
.toList(),
safe(timeline.activityIntervals()).stream()
.map(RuntimeTimelineCompatibilityAdapter::toResolvedActivityInterval)
.toList(),
safe(timeline.supportEvents()).stream()
.map(RuntimeTimelineCompatibilityAdapter::toExtractedSupportEvent)
.toList(),
safe(timeline.warnings()).stream()
.map(RuntimeTimelineCompatibilityAdapter::toExtractionWarning)
.toList()
);
}
public static RuntimeActivityInterval fromResolvedActivityInterval(ResolvedActivityInterval interval) {
if (interval == null) {
return null;
}
return new RuntimeActivityInterval(
interval.intervalId(),
interval.from(),
interval.to(),
interval.durationSeconds(),
interval.activityType(),
interval.slot(),
interval.cardStatus(),
interval.drivingStatus(),
interval.registrationKey(),
interval.vehicleKey(),
interval.sourceKind(),
interval.sourceIntervalIds(),
interval.synthetic(),
interval.clippedToRequestedPeriod(),
interval.level()
);
}
public static ResolvedActivityInterval toResolvedActivityInterval(RuntimeActivityInterval interval) {
if (interval == null) {
return null;
}
return new ResolvedActivityInterval(
interval.intervalId(),
interval.from(),
interval.to(),
interval.durationSeconds(),
interval.activityType(),
interval.slot(),
interval.cardStatus(),
interval.drivingStatus(),
interval.registrationKey(),
interval.vehicleKey(),
interval.sourceKind(),
interval.sourceIntervalIds(),
interval.synthetic(),
interval.clippedToRequestedPeriod(),
interval.level()
);
}
public static RuntimeVehicleUsageInterval fromResolvedVehicleUsageInterval(ResolvedVehicleUsageInterval interval) {
if (interval == null) {
return null;
}
return new RuntimeVehicleUsageInterval(
interval.sessionId(),
interval.driverKey(),
interval.intervalId(),
interval.from(),
interval.to(),
interval.durationSeconds(),
interval.odometerBeginKm(),
interval.odometerEndKm(),
interval.registrationKey(),
interval.vehicleKey(),
interval.sourceKind(),
interval.sourceIntervalIds()
);
}
public static ResolvedVehicleUsageInterval toResolvedVehicleUsageInterval(RuntimeVehicleUsageInterval interval) {
if (interval == null) {
return null;
}
return new ResolvedVehicleUsageInterval(
interval.sessionId(),
interval.driverKey(),
interval.intervalId(),
interval.from(),
interval.to(),
interval.durationSeconds(),
interval.odometerBeginKm(),
interval.odometerEndKm(),
interval.registrationKey(),
interval.vehicleKey(),
interval.sourceKind(),
interval.sourceIntervalIds()
);
}
public static RuntimeSupportEvent fromExtractedSupportEvent(ExtractedSupportEvent supportEvent) {
if (supportEvent == null) {
return null;
}
return new RuntimeSupportEvent(
supportEvent.eventId(),
supportEvent.driverKey(),
supportEvent.occurredAt(),
supportEvent.eventDomain(),
supportEvent.eventType(),
supportEvent.eventLifecycle(),
supportEvent.slot(),
supportEvent.registrationKey(),
supportEvent.vehicleKey(),
supportEvent.country(),
supportEvent.region(),
supportEvent.countryFrom(),
supportEvent.countryTo(),
supportEvent.operation(),
supportEvent.latitude(),
supportEvent.longitude(),
supportEvent.authenticationStatus(),
supportEvent.odometerKm(),
supportEvent.code(),
supportEvent.avgSpeedKmh(),
supportEvent.maxSpeedKmh(),
supportEvent.rawRecordPath()
);
}
public static ExtractedSupportEvent toExtractedSupportEvent(RuntimeSupportEvent supportEvent) {
if (supportEvent == null) {
return null;
}
return new ExtractedSupportEvent(
supportEvent.eventId(),
supportEvent.driverKey(),
supportEvent.occurredAt(),
supportEvent.eventDomain(),
supportEvent.eventType(),
supportEvent.eventLifecycle(),
supportEvent.slot(),
supportEvent.registrationKey(),
supportEvent.vehicleKey(),
supportEvent.country(),
supportEvent.region(),
supportEvent.countryFrom(),
supportEvent.countryTo(),
supportEvent.operation(),
supportEvent.latitude(),
supportEvent.longitude(),
supportEvent.authenticationStatus(),
supportEvent.odometerKm(),
supportEvent.code(),
supportEvent.avgSpeedKmh(),
supportEvent.maxSpeedKmh(),
supportEvent.rawRecordPath()
);
}
public static RuntimeExtractionWarning fromExtractionWarning(ExtractionWarning warning) {
if (warning == null) {
return null;
}
return new RuntimeExtractionWarning(
warning.code(),
warning.message(),
warning.rawRecordPath()
);
}
public static ExtractionWarning toExtractionWarning(RuntimeExtractionWarning warning) {
if (warning == null) {
return null;
}
return new ExtractionWarning(
warning.code(),
warning.message(),
warning.rawRecordPath()
);
}
private static <T> List<T> safe(List<T> values) {
return values == null ? List.of() : values;
}
}

View File

@ -33,14 +33,14 @@ import at.procon.eventhub.processing.model.UnifiedDiscoveredVehicleRef;
import at.procon.eventhub.processing.model.UnifiedEventSourceFamily; import at.procon.eventhub.processing.model.UnifiedEventSourceFamily;
import at.procon.eventhub.processing.model.UnifiedRuntimeEventBackend; import at.procon.eventhub.processing.model.UnifiedRuntimeEventBackend;
import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle; import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle;
import at.procon.eventhub.processing.model.RuntimeActivityInterval;
import at.procon.eventhub.processing.model.RuntimeDriverTimeline;
import at.procon.eventhub.processing.model.RuntimeVehicleUsageInterval;
import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest; import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest;
import at.procon.eventhub.processing.service.UnifiedRuntimeDerivedProjectionService; import at.procon.eventhub.processing.service.UnifiedRuntimeDerivedProjectionService;
import at.procon.eventhub.processing.service.UnifiedRuntimeDriverTimelineService; import at.procon.eventhub.processing.service.UnifiedRuntimeDriverTimelineService;
import at.procon.eventhub.processing.service.UnifiedRuntimeEventAssemblyService; import at.procon.eventhub.processing.service.UnifiedRuntimeEventAssemblyService;
import at.procon.eventhub.tachographfilesession.dto.TachographEsperDriverProcessingResultDto; import at.procon.eventhub.tachographfilesession.dto.TachographEsperDriverProcessingResultDto;
import at.procon.eventhub.tachographfilesession.model.ResolvedActivityInterval;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval;
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
@ -123,11 +123,11 @@ class UnifiedRuntimeProcessingControllerTest {
.build(); .build();
when(timelineService.loadDriverTimeline(any())) when(timelineService.loadDriverTimeline(any()))
.thenReturn(new RuntimeDriverTimeline( .thenReturn(new ResolvedDriverTimeline(
"UNIFIED_EVENT_STREAM", "UNIFIED_EVENT_STREAM",
OffsetDateTime.parse("2026-05-01T08:00:00Z"), OffsetDateTime.parse("2026-05-01T08:00:00Z"),
OffsetDateTime.parse("2026-05-01T10:00:00Z"), OffsetDateTime.parse("2026-05-01T10:00:00Z"),
List.of(RuntimeVehicleUsageInterval.resolved( List.of(ResolvedVehicleUsageInterval.resolved(
null, null,
"DRIVER:42", "DRIVER:42",
"CVU-1", "CVU-1",
@ -140,7 +140,7 @@ class UnifiedRuntimeProcessingControllerTest {
"DRIVER_CARD", "DRIVER_CARD",
List.of("CVU-1") List.of("CVU-1")
)), )),
List.of(new RuntimeActivityInterval( List.of(new ResolvedActivityInterval(
"ACT-1", "ACT-1",
OffsetDateTime.parse("2026-05-01T08:30:00Z"), OffsetDateTime.parse("2026-05-01T08:30:00Z"),
OffsetDateTime.parse("2026-05-01T09:00:00Z"), OffsetDateTime.parse("2026-05-01T09:00:00Z"),
@ -181,6 +181,7 @@ class UnifiedRuntimeProcessingControllerTest {
.andExpect(jsonPath("$.vehicleUsageIntervals[0].intervalId").value("CVU-1")); .andExpect(jsonPath("$.vehicleUsageIntervals[0].intervalId").value("CVU-1"));
} }
@Test @Test
void loadsDriverDerivedProjectionsViaRuntimeApi() throws Exception { void loadsDriverDerivedProjectionsViaRuntimeApi() throws Exception {
UnifiedRuntimeEventAssemblyService eventAssemblyService = org.mockito.Mockito.mock(UnifiedRuntimeEventAssemblyService.class); UnifiedRuntimeEventAssemblyService eventAssemblyService = org.mockito.Mockito.mock(UnifiedRuntimeEventAssemblyService.class);

View File

@ -67,12 +67,12 @@ class UnifiedRuntimeProcessingRequestTest {
OffsetDateTime.parse("2026-05-02T00:00:00Z") OffsetDateTime.parse("2026-05-02T00:00:00Z")
); );
assertThat(defaultRequest.sourceKinds()).containsExactlyInAnyOrder( assertThat(defaultRequest.tachographSourceKinds()).containsExactlyInAnyOrder(
"DRIVER_CARD", UnifiedTachographSourceKind.DRIVER_CARD,
"VEHICLE_UNIT" UnifiedTachographSourceKind.VEHICLE_UNIT
); );
assertThat(defaultRequest.includesSourceKind("DRIVER_CARD")).isTrue(); assertThat(defaultRequest.includesTachographSourceKind("DRIVER_CARD")).isTrue();
assertThat(defaultRequest.includesSourceKind("VEHICLE_UNIT")).isTrue(); assertThat(defaultRequest.includesTachographSourceKind("VEHICLE_UNIT")).isTrue();
UnifiedRuntimeProcessingRequest driverCardOnlyRequest = new UnifiedRuntimeProcessingRequest( UnifiedRuntimeProcessingRequest driverCardOnlyRequest = new UnifiedRuntimeProcessingRequest(
null, null,
@ -81,7 +81,7 @@ class UnifiedRuntimeProcessingRequestTest {
"default", "default",
Set.of(UnifiedEventSourceFamily.TACHOGRAPH_DB), Set.of(UnifiedEventSourceFamily.TACHOGRAPH_DB),
UnifiedRuntimeEventBackend.SOURCE_DB, UnifiedRuntimeEventBackend.SOURCE_DB,
Set.of("DRIVER_CARD"), Set.of(UnifiedTachographSourceKind.DRIVER_CARD),
null, null,
Set.of(), Set.of(),
false, false,
@ -97,9 +97,9 @@ class UnifiedRuntimeProcessingRequestTest {
true true
); );
assertThat(driverCardOnlyRequest.sourceKinds()).containsExactly("DRIVER_CARD"); assertThat(driverCardOnlyRequest.tachographSourceKinds()).containsExactly(UnifiedTachographSourceKind.DRIVER_CARD);
assertThat(driverCardOnlyRequest.includesSourceKind("DRIVER_CARD")).isTrue(); assertThat(driverCardOnlyRequest.includesTachographSourceKind("DRIVER_CARD")).isTrue();
assertThat(driverCardOnlyRequest.includesSourceKind("VEHICLE_UNIT")).isFalse(); assertThat(driverCardOnlyRequest.includesTachographSourceKind("VEHICLE_UNIT")).isFalse();
} }
@Test @Test

View File

@ -3,7 +3,6 @@ package at.procon.eventhub.processing.service;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import at.procon.eventhub.config.EventHubProperties; import at.procon.eventhub.config.EventHubProperties;
import at.procon.eventhub.processing.model.RuntimeDriverTimeline;
import at.procon.eventhub.processing.model.UnifiedDriverTimelineRequest; import at.procon.eventhub.processing.model.UnifiedDriverTimelineRequest;
import at.procon.eventhub.service.EventDetailsFactory; import at.procon.eventhub.service.EventDetailsFactory;
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession; import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
@ -15,6 +14,7 @@ import at.procon.eventhub.tachographfilesession.model.ExtractedSupportEvent;
import at.procon.eventhub.tachographfilesession.model.ExtractedVehicle; import at.procon.eventhub.tachographfilesession.model.ExtractedVehicle;
import at.procon.eventhub.tachographfilesession.model.ExtractedVehicleRegistration; import at.procon.eventhub.tachographfilesession.model.ExtractedVehicleRegistration;
import at.procon.eventhub.tachographfilesession.model.ExtractionStats; import at.procon.eventhub.tachographfilesession.model.ExtractionStats;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import at.procon.eventhub.tachographfilesession.model.TachographFileSession; import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
import at.procon.eventhub.tachographfilesession.model.TachographFileSessionMetadata; import at.procon.eventhub.tachographfilesession.model.TachographFileSessionMetadata;
import at.procon.eventhub.tachographfilesession.service.DriverKeyFactory; import at.procon.eventhub.tachographfilesession.service.DriverKeyFactory;
@ -55,7 +55,7 @@ class UnifiedDriverTimelineServiceTest {
TachographFileSession session = session(driver); TachographFileSession session = session(driver);
repository.save(session); repository.save(session);
RuntimeDriverTimeline timeline = service.loadDriverTimeline( ResolvedDriverTimeline timeline = service.loadDriverTimeline(
UnifiedDriverTimelineRequest.forTachographFileSession(session.sessionId(), driver.driverKey()) UnifiedDriverTimelineRequest.forTachographFileSession(session.sessionId(), driver.driverKey())
); );

View File

@ -14,7 +14,7 @@ import at.procon.eventhub.dto.GeoPointDto;
import at.procon.eventhub.dto.ImportScopeDto; import at.procon.eventhub.dto.ImportScopeDto;
import at.procon.eventhub.dto.VehicleRefDto; import at.procon.eventhub.dto.VehicleRefDto;
import at.procon.eventhub.dto.VehicleRegistrationRefDto; import at.procon.eventhub.dto.VehicleRegistrationRefDto;
import at.procon.eventhub.processing.model.RuntimeDriverTimeline; import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -38,7 +38,7 @@ class UnifiedEventTimelineReconstructorTest {
supportEvent("SUP-1", "2026-05-01T08:30:00Z") supportEvent("SUP-1", "2026-05-01T08:30:00Z")
); );
RuntimeDriverTimeline timeline = reconstructor.reconstruct( ResolvedDriverTimeline timeline = reconstructor.reconstruct(
UUID.randomUUID(), UUID.randomUUID(),
"DRIVER:42", "DRIVER:42",
events events
@ -68,7 +68,7 @@ class UnifiedEventTimelineReconstructorTest {
activityEvent("VU-ACT-99", EventLifecycle.END, "2026-05-01T09:00:00Z", "2026-05-01T08:00:00Z", "2026-05-01T09:00:00Z") activityEvent("VU-ACT-99", EventLifecycle.END, "2026-05-01T09:00:00Z", "2026-05-01T08:00:00Z", "2026-05-01T09:00:00Z")
); );
RuntimeDriverTimeline timeline = reconstructor.reconstruct( ResolvedDriverTimeline timeline = reconstructor.reconstruct(
UUID.randomUUID(), UUID.randomUUID(),
"DRIVER:42", "DRIVER:42",
events events
@ -105,7 +105,7 @@ class UnifiedEventTimelineReconstructorTest {
) )
); );
RuntimeDriverTimeline timeline = reconstructor.reconstruct( ResolvedDriverTimeline timeline = reconstructor.reconstruct(
UUID.randomUUID(), UUID.randomUUID(),
"DRIVER:42", "DRIVER:42",
events events

View File

@ -16,8 +16,8 @@ import at.procon.eventhub.dto.VehicleRegistrationRefDto;
import at.procon.eventhub.processing.model.UnifiedDiscoveredVehicleRef; import at.procon.eventhub.processing.model.UnifiedDiscoveredVehicleRef;
import at.procon.eventhub.processing.model.UnifiedEventSourceFamily; import at.procon.eventhub.processing.model.UnifiedEventSourceFamily;
import at.procon.eventhub.processing.model.UnifiedRuntimeEventBackend; import at.procon.eventhub.processing.model.UnifiedRuntimeEventBackend;
import at.procon.eventhub.processing.model.RuntimeDriverTimeline;
import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest; import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import java.time.LocalDate; import java.time.LocalDate;
@ -40,7 +40,7 @@ class UnifiedRuntimeDriverTimelineServiceTest {
new UnifiedEventTimelineReconstructor() new UnifiedEventTimelineReconstructor()
); );
RuntimeDriverTimeline timeline = service.loadDriverTimeline( ResolvedDriverTimeline timeline = service.loadDriverTimeline(
new UnifiedRuntimeProcessingRequest( new UnifiedRuntimeProcessingRequest(
null, null,
List.of(), List.of(),

View File

@ -15,8 +15,6 @@ import at.procon.eventhub.dto.EventLifecycle;
import at.procon.eventhub.dto.EventType; import at.procon.eventhub.dto.EventType;
import at.procon.eventhub.dto.VehicleRefDto; import at.procon.eventhub.dto.VehicleRefDto;
import at.procon.eventhub.dto.VehicleRegistrationRefDto; import at.procon.eventhub.dto.VehicleRegistrationRefDto;
import at.procon.eventhub.processing.model.RuntimeDriverTimeline;
import at.procon.eventhub.processing.model.RuntimeExtractionWarning;
import at.procon.eventhub.processing.service.UnifiedEventTimelineReconstructor; import at.procon.eventhub.processing.service.UnifiedEventTimelineReconstructor;
import at.procon.eventhub.service.EventAcquisitionRecordKeyService; import at.procon.eventhub.service.EventAcquisitionRecordKeyService;
import at.procon.eventhub.service.EventHubEventSorter; import at.procon.eventhub.service.EventHubEventSorter;
@ -177,7 +175,7 @@ class TachographCompositeSessionServiceTest {
when(eventBuilder.buildEvents(first, firstDriver)).thenReturn(List.of(event("a", occurredAt, EventType.WORK))); when(eventBuilder.buildEvents(first, firstDriver)).thenReturn(List.of(event("a", occurredAt, EventType.WORK)));
when(eventBuilder.buildEvents(second, secondDriver)).thenReturn(List.of(event("b", occurredAt.plusHours(1), EventType.DRIVE))); when(eventBuilder.buildEvents(second, secondDriver)).thenReturn(List.of(event("b", occurredAt.plusHours(1), EventType.DRIVE)));
RuntimeDriverTimeline reconstructed = new RuntimeDriverTimeline( ResolvedDriverTimeline expected = new ResolvedDriverTimeline(
"COMPOSITE_TACHOGRAPH_FILE_SESSION", "COMPOSITE_TACHOGRAPH_FILE_SESSION",
occurredAt, occurredAt,
occurredAt.plusHours(1), occurredAt.plusHours(1),
@ -187,22 +185,14 @@ class TachographCompositeSessionServiceTest {
List.of() List.of()
); );
when(reconstructor.reconstruct(any(), eq("12:123"), any(), any(), eq("COMPOSITE_TACHOGRAPH_FILE_SESSION"))) when(reconstructor.reconstruct(any(), eq("12:123"), any(), any(), eq("COMPOSITE_TACHOGRAPH_FILE_SESSION")))
.thenReturn(reconstructed); .thenReturn(expected);
ResolvedDriverTimeline actual = ResolvedDriverTimeline actual =
service.getMergedDriverTimeline(created.session().compositeSessionId(), "12:123"); service.getMergedDriverTimeline(created.session().compositeSessionId(), "12:123");
assertThat(actual).isEqualTo(new ResolvedDriverTimeline( assertThat(actual).isSameAs(expected);
"COMPOSITE_TACHOGRAPH_FILE_SESSION",
occurredAt,
occurredAt.plusHours(1),
List.of(),
List.of(),
List.of(),
List.of()
));
ArgumentCaptor<List<EventHubEventDto>> eventsCaptor = ArgumentCaptor.forClass(List.class); ArgumentCaptor<List<EventHubEventDto>> eventsCaptor = ArgumentCaptor.forClass(List.class);
ArgumentCaptor<List<RuntimeExtractionWarning>> warningsCaptor = ArgumentCaptor.forClass(List.class); ArgumentCaptor<List<ExtractionWarning>> warningsCaptor = ArgumentCaptor.forClass(List.class);
verify(reconstructor).reconstruct( verify(reconstructor).reconstruct(
eq(created.session().compositeSessionId()), eq(created.session().compositeSessionId()),
eq("12:123"), eq("12:123"),
@ -213,10 +203,10 @@ class TachographCompositeSessionServiceTest {
assertThat(eventsCaptor.getValue()).extracting(EventHubEventDto::externalSourceEventId) assertThat(eventsCaptor.getValue()).extracting(EventHubEventDto::externalSourceEventId)
.containsExactly("a", "b"); .containsExactly("a", "b");
assertThat(warningsCaptor.getValue()).containsExactly( assertThat(warningsCaptor.getValue()).containsExactly(
new RuntimeExtractionWarning("SESSION_A", "warn-a", "s1"), new ExtractionWarning("SESSION_A", "warn-a", "s1"),
new RuntimeExtractionWarning("CARD_GAP", "gap", "p1"), new ExtractionWarning("CARD_GAP", "gap", "p1"),
new RuntimeExtractionWarning("SESSION_B", "warn-b", "s2"), new ExtractionWarning("SESSION_B", "warn-b", "s2"),
new RuntimeExtractionWarning("DUPLICATE", "duplicate", "p2") new ExtractionWarning("DUPLICATE", "duplicate", "p2")
); );
} }