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

View File

@ -1,7 +1,7 @@
package at.procon.eventhub.processing.dto;
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;
public record RuntimeVehicleUsageIntervalDebugDto(
@ -12,7 +12,7 @@ public record RuntimeVehicleUsageIntervalDebugDto(
String vehicleKey,
String sourceKind
) {
public static RuntimeVehicleUsageIntervalDebugDto from(RuntimeVehicleUsageInterval interval) {
public static RuntimeVehicleUsageIntervalDebugDto from(ResolvedVehicleUsageInterval interval) {
if (interval == 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.UnifiedRuntimeEventBackend;
import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest;
import at.procon.eventhub.processing.model.UnifiedTachographSourceKind;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.Set;
@ -15,7 +16,7 @@ public record UnifiedRuntimeProcessingApiRequest(
String tenantKey,
Set<UnifiedEventSourceFamily> sourceFamilies,
UnifiedRuntimeEventBackend eventBackend,
Set<String> sourceKinds,
Set<UnifiedTachographSourceKind> tachographSourceKinds,
String driverKey,
Set<String> driverKeys,
Boolean includeAllDrivers,
@ -42,7 +43,7 @@ public record UnifiedRuntimeProcessingApiRequest(
String tenantKey,
Set<UnifiedEventSourceFamily> sourceFamilies,
UnifiedRuntimeEventBackend eventBackend,
Set<String> sourceKinds,
Set<UnifiedTachographSourceKind> tachographSourceKinds,
String driverKey,
Set<String> driverKeys,
Boolean includeAllDrivers,
@ -68,7 +69,7 @@ public record UnifiedRuntimeProcessingApiRequest(
tenantKey,
sourceFamilies,
eventBackend,
sourceKinds,
tachographSourceKinds,
driverKey,
driverKeys,
includeAllDrivers,
@ -98,7 +99,7 @@ public record UnifiedRuntimeProcessingApiRequest(
tenantKey,
sourceFamilies,
eventBackend,
sourceKinds,
tachographSourceKinds,
driverKey,
driverKeys,
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.service.RuntimeDriverVehicleEvidenceAttachmentService;
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 java.util.ArrayList;
import java.util.Comparator;
@ -260,7 +260,7 @@ public class VehicleEvidenceAttachmentModule implements RuntimeProcessingModule
}
private String driverKey(EventHubEventDto event) {
return RuntimeEntityReferenceResolver.driverKey(event);
return TachographRuntimeIdentityResolver.driverKey(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.model.UnifiedRuntimeEventBundle;
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 java.time.OffsetDateTime;
import java.util.ArrayList;
@ -156,7 +156,7 @@ public final class DriverWorkingTimeEplEventMapper {
JsonNode attributes = attributes(sourceEvent);
String intervalId = RuntimeEventIdentityResolver.presentationIntervalId(sourceEvent);
String runtimeIntervalKey = RuntimeEventIdentityResolver.runtimeIntervalKey(sourceEvent);
String driverKey = RuntimeEntityReferenceResolver.driverKey(sourceEvent);
String driverKey = TachographRuntimeIdentityResolver.driverKey(sourceEvent);
if (driverKey == null || intervalId == null || runtimeIntervalKey == null) {
return null;
}
@ -175,8 +175,8 @@ public final class DriverWorkingTimeEplEventMapper {
event.put("cardSlot", firstNonBlank(text(raw, "cardSlot"), text(attributes, "cardSlot")));
event.put("cardStatus", firstNonBlank(text(raw, "cardStatus"), text(attributes, "cardStatus")));
event.put("drivingStatus", firstNonBlank(text(raw, "drivingStatus"), text(attributes, "drivingStatus")));
event.put("registrationKey", RuntimeEntityReferenceResolver.registrationKey(sourceEvent));
event.put("vehicleKey", RuntimeEntityReferenceResolver.vehicleKey(sourceEvent));
event.put("registrationKey", TachographRuntimeIdentityResolver.registrationKey(sourceEvent));
event.put("vehicleKey", TachographRuntimeIdentityResolver.vehicleKey(sourceEvent));
event.put("sourceKind", firstNonBlank(text(raw, "sourceKind"), sourceKind(sourceEvent)));
event.put("synthetic", booleanValue(raw, "synthetic", false));
event.put("clippedToRequestedPeriod", booleanValue(raw, "clippedToRequestedPeriod", false));
@ -199,7 +199,7 @@ public final class DriverWorkingTimeEplEventMapper {
JsonNode raw = rawPayload(sourceEvent);
String intervalId = RuntimeEventIdentityResolver.presentationIntervalId(sourceEvent);
String runtimeIntervalKey = RuntimeEventIdentityResolver.runtimeIntervalKey(sourceEvent);
String driverKey = RuntimeEntityReferenceResolver.driverKey(sourceEvent);
String driverKey = TachographRuntimeIdentityResolver.driverKey(sourceEvent);
if (driverKey == null || intervalId == null || runtimeIntervalKey == null) {
return null;
}
@ -214,8 +214,8 @@ public final class DriverWorkingTimeEplEventMapper {
event.put("lifecycle", sourceEvent.lifecycle().name());
event.put("occurredAt", sourceEvent.occurredAt());
event.put("occurredAtEpochSecond", sourceEvent.occurredAt().toEpochSecond());
event.put("registrationKey", RuntimeEntityReferenceResolver.registrationKey(sourceEvent));
event.put("vehicleKey", RuntimeEntityReferenceResolver.vehicleKey(sourceEvent));
event.put("registrationKey", TachographRuntimeIdentityResolver.registrationKey(sourceEvent));
event.put("vehicleKey", TachographRuntimeIdentityResolver.vehicleKey(sourceEvent));
event.put("sourceKind", firstNonBlank(text(raw, "sourceKind"), sourceKind(sourceEvent)));
event.put("odometerKm", odometerKm(sourceEvent, raw));
return event;

View File

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

View File

@ -8,7 +8,7 @@ import at.procon.eventhub.dto.EventLifecycle;
import at.procon.eventhub.dto.EventType;
import at.procon.eventhub.dto.GeoPointDto;
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.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
@ -82,9 +82,9 @@ public class RuntimeSupportEvidenceNormalizer {
event.eventDomain() == null ? null : event.eventDomain().name(),
event.eventType() == null ? null : event.eventType().name(),
event.lifecycle() == null ? null : event.lifecycle().name(),
firstNonBlank(RuntimeEntityReferenceResolver.driverKey(event), fallbackDriverKey),
RuntimeEntityReferenceResolver.vehicleKey(event),
RuntimeEntityReferenceResolver.registrationKey(event),
firstNonBlank(TachographRuntimeIdentityResolver.driverKey(event), fallbackDriverKey),
TachographRuntimeIdentityResolver.vehicleKey(event),
TachographRuntimeIdentityResolver.registrationKey(event),
event.occurredAt(),
event.occurredAt() == null ? null : event.occurredAt().toEpochSecond(),
latitude,
@ -288,7 +288,7 @@ public class RuntimeSupportEvidenceNormalizer {
}
private JsonNode rawPayload(EventHubEventDto event) {
return RuntimeEntityReferenceResolver.rawPayload(event);
return TachographRuntimeIdentityResolver.rawPayload(event);
}
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 java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
@ -16,7 +17,7 @@ public record UnifiedRuntimeProcessingRequest(
String tenantKey,
Set<UnifiedEventSourceFamily> sourceFamilies,
UnifiedRuntimeEventBackend eventBackend,
Set<String> sourceKinds,
Set<UnifiedTachographSourceKind> tachographSourceKinds,
String driverKey,
Set<String> driverKeys,
boolean includeAllDrivers,
@ -39,7 +40,7 @@ public record UnifiedRuntimeProcessingRequest(
String tenantKey,
Set<UnifiedEventSourceFamily> sourceFamilies,
UnifiedRuntimeEventBackend eventBackend,
Set<String> sourceKinds,
Set<UnifiedTachographSourceKind> tachographSourceKinds,
String driverKey,
Set<String> driverKeys,
boolean includeAllDrivers,
@ -61,7 +62,7 @@ public record UnifiedRuntimeProcessingRequest(
tenantKey,
sourceFamilies,
eventBackend,
sourceKinds,
tachographSourceKinds,
driverKey,
driverKeys,
includeAllDrivers,
@ -86,7 +87,7 @@ public record UnifiedRuntimeProcessingRequest(
throw new IllegalArgumentException("sourceFamilies must not be empty");
}
eventBackend = eventBackend == null ? UnifiedRuntimeEventBackend.SOURCE_DB : eventBackend;
sourceKinds = normalizeSourceKinds(sourceKinds);
tachographSourceKinds = normalizeTachographSourceKinds(tachographSourceKinds);
sessionIds = normalizeSessionIds(sessionId, sessionIds);
if (sessionId == null && !sessionIds.isEmpty()) {
sessionId = sessionIds.get(0);
@ -447,7 +448,7 @@ public record UnifiedRuntimeProcessingRequest(
tenantKey,
Set.of(sourceInput.sourceFamily()),
sourceInput.eventBackend(),
sourceKinds,
tachographSourceKinds,
driverKey,
driverKeys,
includeAllDrivers,
@ -484,7 +485,7 @@ public record UnifiedRuntimeProcessingRequest(
tenantKey,
sourceFamilies,
eventBackend,
sourceKinds,
tachographSourceKinds,
value,
Set.of(),
false,
@ -506,15 +507,21 @@ public record UnifiedRuntimeProcessingRequest(
return includeAllDrivers || driverKeys.size() > 1 || (driverKey == null && !driverKeys.isEmpty());
}
public boolean includesSourceKind(String sourceKind) {
public boolean includesTachographSourceKind(String sourceKind) {
if (sourceKind == null || sourceKind.isBlank()) {
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() {
return sourceKinds.stream().toList();
public List<String> tachographSourceKindNames() {
return tachographSourceKinds.stream()
.map(UnifiedTachographSourceKind::name)
.toList();
}
private static Set<UnifiedEventSourceFamily> normalizeSourceFamilies(
@ -593,20 +600,13 @@ public record UnifiedRuntimeProcessingRequest(
return Set.copyOf(normalized);
}
private static Set<String> normalizeSourceKinds(
Set<String> values
private static Set<UnifiedTachographSourceKind> normalizeTachographSourceKinds(
Set<UnifiedTachographSourceKind> values
) {
if (values == null || values.isEmpty()) {
return Set.of("DRIVER_CARD", "VEHICLE_UNIT");
return Set.copyOf(Arrays.asList(UnifiedTachographSourceKind.values()));
}
LinkedHashSet<String> normalized = new LinkedHashSet<>();
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);
return Set.copyOf(values);
}
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.occurredFrom(),
request.occurredTo(),
request.sourceKindNames(),
request.tachographSourceKindNames(),
request.includeIntersectingIntervals()
);
case YELLOWFOX_DB -> UnifiedDriverEventsRequest.forYellowFoxDbDriver(
@ -100,7 +100,7 @@ public class EventHubRuntimeEventLoader implements RuntimeDriverEventLoader, Run
vehicleRef.registrationNumber(),
request.vehicleOccurredFrom(),
request.vehicleOccurredTo(),
request.sourceKindNames(),
request.tachographSourceKindNames(),
request.includeIntersectingIntervals()
);
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.eventprocessing.partition.RuntimeEventScopeClassifier;
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.RuntimeVehicleUsageInterval;
import at.procon.eventhub.processing.support.RuntimeDriverWorkingTimeAdapter;
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 java.time.OffsetDateTime;
import java.util.ArrayList;
@ -63,14 +63,14 @@ public class RuntimeDriverVehicleEvidenceAttachmentService {
int vehicleEvidencePaddingMinutes,
boolean includeDebug
) {
RuntimeDriverTimeline timeline = timelineReconstructor.reconstruct(
ResolvedDriverTimeline timeline = timelineReconstructor.reconstruct(
null,
driverKey,
directDriverEvents == null ? List.of() : directDriverEvents
);
List<DriverWorkingTimeVehicleUsageInterval> vehicleUsageIntervals = mergeVehicleUsageIntervals(timeline.vehicleUsageIntervals())
.stream()
.map(RuntimeDriverWorkingTimeAdapter::toVehicleUsageInterval)
.map(TachographDriverWorkingTimeAdapter::toVehicleUsageInterval)
.filter(Objects::nonNull)
.toList();
return attachVehicleEvidence(
@ -277,8 +277,8 @@ public class RuntimeDriverVehicleEvidenceAttachmentService {
private Set<String> vehicleKeys(EventHubEventDto event) {
LinkedHashSet<String> result = new LinkedHashSet<>();
String vehicleKey = RuntimeEntityReferenceResolver.vehicleKey(event);
String registrationKey = RuntimeEntityReferenceResolver.registrationKey(event);
String vehicleKey = TachographRuntimeIdentityResolver.vehicleKey(event);
String registrationKey = TachographRuntimeIdentityResolver.registrationKey(event);
add(result, vehicleKey);
add(result, registrationKey);
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()) {
return List.of();
}
List<RuntimeVehicleUsageInterval> sorted = intervals.stream()
.sorted(Comparator.comparing(RuntimeVehicleUsageInterval::from, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(RuntimeVehicleUsageInterval::to, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(RuntimeVehicleUsageInterval::intervalId, Comparator.nullsLast(String::compareTo)))
List<ResolvedVehicleUsageInterval> sorted = intervals.stream()
.sorted(Comparator.comparing(ResolvedVehicleUsageInterval::from, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(ResolvedVehicleUsageInterval::to, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(ResolvedVehicleUsageInterval::intervalId, Comparator.nullsLast(String::compareTo)))
.toList();
List<RuntimeVehicleUsageInterval> merged = new ArrayList<>();
for (RuntimeVehicleUsageInterval next : sorted) {
List<ResolvedVehicleUsageInterval> merged = new ArrayList<>();
for (ResolvedVehicleUsageInterval next : sorted) {
if (merged.isEmpty()) {
merged.add(next);
continue;
}
RuntimeVehicleUsageInterval current = merged.get(merged.size() - 1);
ResolvedVehicleUsageInterval current = merged.get(merged.size() - 1);
if (canMerge(current, next)) {
merged.set(merged.size() - 1, merge(current, next));
} else {
@ -341,7 +341,7 @@ public class RuntimeDriverVehicleEvidenceAttachmentService {
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) {
return false;
}
@ -351,7 +351,7 @@ public class RuntimeDriverVehicleEvidenceAttachmentService {
&& !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<>();
if (left.sourceIntervalIds() != null) {
sourceIntervalIds.addAll(left.sourceIntervalIds());
@ -363,7 +363,7 @@ public class RuntimeDriverVehicleEvidenceAttachmentService {
if (right.to() != null && (end == null || right.to().isAfter(end))) {
end = right.to();
}
return RuntimeVehicleUsageInterval.resolved(
return ResolvedVehicleUsageInterval.resolved(
left.sessionId(),
left.driverKey(),
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.UnifiedRuntimeProcessingRequest;
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 java.util.ArrayList;
import java.util.Comparator;
@ -276,7 +276,7 @@ public class RuntimeDriverWorkingTimeScopeProcessingService {
}
private String driverKey(EventHubEventDto event) {
return RuntimeEntityReferenceResolver.driverKey(event);
return TachographRuntimeIdentityResolver.driverKey(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.EventLifecycle;
import at.procon.eventhub.dto.EventType;
import at.procon.eventhub.processing.model.RuntimeTimelineEventBundle;
import at.procon.eventhub.processing.support.RuntimeEventIdentityResolver;
import com.fasterxml.jackson.databind.JsonNode;
import at.procon.eventhub.tachographfilesession.model.TachographTimelineEventBundle;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
@ -15,23 +16,23 @@ final class RuntimeIntervalEventWindowSelector {
private RuntimeIntervalEventWindowSelector() {
}
static RuntimeTimelineEventBundle filterBundle(
RuntimeTimelineEventBundle bundle,
static TachographTimelineEventBundle filterBundle(
TachographTimelineEventBundle bundle,
OffsetDateTime occurredFrom,
OffsetDateTime occurredTo,
boolean includeIntersectingIntervals
) {
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.vehicleUsageEvents(), occurredFrom, occurredTo, includeIntersectingIntervals),
filterPointEvents(bundle.supportEvents(), occurredFrom, occurredTo)
);
}
static List<EventHubEventDto> filterIntervalEvents(
private static List<EventHubEventDto> filterIntervalEvents(
List<EventHubEventDto> events,
OffsetDateTime occurredFrom,
OffsetDateTime occurredTo,
@ -58,14 +59,11 @@ final class RuntimeIntervalEventWindowSelector {
return List.copyOf(result);
}
static List<EventHubEventDto> filterPointEvents(
private static List<EventHubEventDto> filterPointEvents(
List<EventHubEventDto> events,
OffsetDateTime occurredFrom,
OffsetDateTime occurredTo
) {
if (events == null || events.isEmpty()) {
return List.of();
}
return events.stream()
.filter(event -> withinWindow(event.occurredAt(), occurredFrom, occurredTo))
.toList();
@ -89,6 +87,27 @@ final class RuntimeIntervalEventWindowSelector {
return RuntimeEventIdentityResolver.runtimeIntervalKey(event);
}
private static JsonNode raw(EventHubEventDto event) {
JsonNode payload = event == null ? null : event.payload();
if (payload == null || payload.isNull() || payload.isMissingNode()) {
return null;
}
JsonNode raw = payload.get("raw");
return raw == null || raw.isNull() ? payload : raw;
}
private static String text(JsonNode node, String field) {
if (node == null || field == null) {
return null;
}
JsonNode value = node.get(field);
if (value == null || value.isNull()) {
return null;
}
String text = value.asText(null);
return text == null || text.isBlank() ? null : text.trim();
}
private static final class IntervalGroup {
private final List<EventHubEventDto> events = new ArrayList<>();
private OffsetDateTime startedAt;

View File

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

View File

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

View File

@ -1,10 +1,9 @@
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.UnifiedEventSourceFamily;
import at.procon.eventhub.tachographfilesession.support.RuntimeTimelineCompatibilityAdapter;
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.service.DriverNotFoundInSessionException;
import at.procon.eventhub.tachographfilesession.service.EventBackedDriverTimelineBuilder;
@ -32,15 +31,13 @@ public class TachographFileSessionUnifiedDriverTimelineSource implements Unified
}
@Override
public RuntimeDriverTimeline loadDriverTimeline(UnifiedDriverTimelineRequest request) {
public ResolvedDriverTimeline loadDriverTimeline(UnifiedDriverTimelineRequest request) {
TachographFileSession session = repository.find(request.sessionId())
.orElseThrow(() -> new TachographFileSessionNotFoundException(request.sessionId()));
DriverExtractionSession driver = session.driversByKey().get(request.driverKey());
if (driver == null) {
throw new DriverNotFoundInSessionException(request.sessionId(), request.driverKey());
}
return RuntimeTimelineCompatibilityAdapter.fromResolvedDriverTimeline(
eventBackedDriverTimelineBuilder.build(session, driver)
);
return 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.UnifiedVehicleEventsRequest;
import at.procon.eventhub.reference.TachographNationRegistry;
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
import at.procon.eventhub.tachographfilesession.model.TachographTimelineEventBundle;
import at.procon.eventhub.tachographfilesession.service.DriverTimelineEventBuilder;
@ -38,29 +37,18 @@ public class TachographFileSessionUnifiedVehicleEventSource implements UnifiedVe
TachographFileSession session = repository.find(request.sessionId())
.orElseThrow(() -> new TachographFileSessionNotFoundException(request.sessionId()));
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)
.filter(event -> matchesVehicle(event.vehicleRef(), request))
.distinct()
.toList();
}
private TachographTimelineEventBundle filterBundle(
TachographFileSession session,
DriverExtractionSession driver,
UnifiedVehicleEventsRequest request
) {
TachographTimelineEventBundle bundle = eventBuilder.buildEventBundle(session, driver);
return TachographTimelineEventBundle.fromRuntimeBundle(
RuntimeIntervalEventWindowSelector.filterBundle(
bundle == null ? null : bundle.toRuntimeBundle(),
request.occurredFrom(),
request.occurredTo(),
request.includeIntersectingIntervals()
)
);
}
private boolean matchesVehicle(VehicleRefDto vehicleRef, UnifiedVehicleEventsRequest request) {
if (vehicleRef == null || !vehicleRef.hasAnyReference()) {
return false;

View File

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

View File

@ -1,11 +1,11 @@
package at.procon.eventhub.processing.service;
import at.procon.eventhub.processing.model.RuntimeDriverTimeline;
import at.procon.eventhub.processing.model.UnifiedDriverTimelineRequest;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
public interface UnifiedDriverTimelineSource {
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.EventLifecycle;
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.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 java.math.BigDecimal;
import java.time.Duration;
@ -27,7 +27,7 @@ import org.springframework.stereotype.Service;
@Service
public class UnifiedEventTimelineReconstructor {
public RuntimeDriverTimeline reconstruct(
public ResolvedDriverTimeline reconstruct(
UUID sessionId,
String driverKey,
List<EventHubEventDto> events
@ -35,23 +35,23 @@ public class UnifiedEventTimelineReconstructor {
return reconstruct(sessionId, driverKey, events, List.of(), null);
}
public RuntimeDriverTimeline reconstruct(
public ResolvedDriverTimeline reconstruct(
UUID sessionId,
String driverKey,
List<EventHubEventDto> events,
List<RuntimeExtractionWarning> warnings,
List<ExtractionWarning> warnings,
String sourceKind
) {
List<EventHubEventDto> safeEvents = events == null ? List.of() : List.copyOf(events);
List<RuntimeActivityInterval> activityIntervals = reconstructActivityIntervals(safeEvents);
List<RuntimeVehicleUsageInterval> vehicleUsageIntervals =
List<ResolvedActivityInterval> activityIntervals = reconstructActivityIntervals(safeEvents);
List<ResolvedVehicleUsageInterval> vehicleUsageIntervals =
reconstructVehicleUsageIntervals(sessionId, driverKey, safeEvents);
List<RuntimeSupportEvent> supportEvents = reconstructSupportEvents(safeEvents);
List<RuntimeExtractionWarning> mergedWarnings = warnings == null ? List.of() : List.copyOf(new LinkedHashSet<>(warnings));
List<ExtractedSupportEvent> supportEvents = reconstructSupportEvents(safeEvents);
List<ExtractionWarning> mergedWarnings = warnings == null ? List.of() : List.copyOf(new LinkedHashSet<>(warnings));
OffsetDateTime loadedFrom = minTimestamp(activityIntervals, vehicleUsageIntervals, supportEvents);
OffsetDateTime loadedTo = maxTimestamp(activityIntervals, vehicleUsageIntervals, supportEvents);
return new RuntimeDriverTimeline(
return new ResolvedDriverTimeline(
resolveSourceKind(safeEvents, sourceKind),
loadedFrom,
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<>();
for (EventHubEventDto event : events) {
if (event.eventDomain() != EventDomain.DRIVER_ACTIVITY) {
@ -83,13 +83,13 @@ public class UnifiedEventTimelineReconstructor {
return byIntervalId.values().stream()
.map(ActivityAccumulator::finish)
.filter(interval -> interval != null)
.sorted(Comparator.comparing(RuntimeActivityInterval::from)
.thenComparing(RuntimeActivityInterval::to)
.thenComparing(RuntimeActivityInterval::activityType, Comparator.nullsLast(String::compareTo)))
.sorted(Comparator.comparing(ResolvedActivityInterval::from)
.thenComparing(ResolvedActivityInterval::to)
.thenComparing(ResolvedActivityInterval::activityType, Comparator.nullsLast(String::compareTo)))
.toList();
}
private List<RuntimeVehicleUsageInterval> reconstructVehicleUsageIntervals(
private List<ResolvedVehicleUsageInterval> reconstructVehicleUsageIntervals(
UUID sessionId,
String driverKey,
List<EventHubEventDto> events
@ -117,13 +117,13 @@ public class UnifiedEventTimelineReconstructor {
return byIntervalId.values().stream()
.map(VehicleUsageAccumulator::finish)
.filter(interval -> interval != null)
.sorted(Comparator.comparing(RuntimeVehicleUsageInterval::from)
.thenComparing(RuntimeVehicleUsageInterval::to, Comparator.nullsLast(Comparator.naturalOrder())))
.sorted(Comparator.comparing(ResolvedVehicleUsageInterval::from)
.thenComparing(ResolvedVehicleUsageInterval::to, Comparator.nullsLast(Comparator.naturalOrder())))
.toList();
}
private List<RuntimeSupportEvent> reconstructSupportEvents(List<EventHubEventDto> events) {
List<RuntimeSupportEvent> result = new ArrayList<>();
private List<ExtractedSupportEvent> reconstructSupportEvents(List<EventHubEventDto> events) {
List<ExtractedSupportEvent> result = new ArrayList<>();
for (EventHubEventDto event : events) {
if (event.eventDomain() == EventDomain.DRIVER_ACTIVITY) {
continue;
@ -136,16 +136,16 @@ public class UnifiedEventTimelineReconstructor {
String eventId = firstNonBlank(text(raw, "supportEventId"), event.externalSourceEventId());
BigDecimal latitude = event.position() == null ? null : event.position().latitude();
BigDecimal longitude = event.position() == null ? null : event.position().longitude();
result.add(new RuntimeSupportEvent(
result.add(new ExtractedSupportEvent(
eventId,
RuntimeEntityReferenceResolver.driverKey(event),
TachographRuntimeIdentityResolver.driverKey(event),
event.occurredAt(),
event.eventDomain().name(),
text(raw, "supportEventType") == null ? event.eventType().name() : text(raw, "supportEventType"),
event.lifecycle().name(),
text(raw, "slot"),
RuntimeEntityReferenceResolver.registrationKey(event),
RuntimeEntityReferenceResolver.vehicleKey(event),
TachographRuntimeIdentityResolver.registrationKey(event),
TachographRuntimeIdentityResolver.vehicleKey(event),
firstNonBlank(text(raw, "country"), detailText(event, "country")),
text(raw, "region"),
firstNonBlank(text(raw, "countryFrom"), detailText(event, "countryFrom")),
@ -161,9 +161,9 @@ public class UnifiedEventTimelineReconstructor {
text(raw, "rawRecordPath")
));
}
result.sort(Comparator.comparing(RuntimeSupportEvent::occurredAt)
.thenComparing(RuntimeSupportEvent::eventDomain, Comparator.nullsLast(String::compareTo))
.thenComparing(RuntimeSupportEvent::eventId, Comparator.nullsLast(String::compareTo)));
result.sort(Comparator.comparing(ExtractedSupportEvent::occurredAt)
.thenComparing(ExtractedSupportEvent::eventDomain, Comparator.nullsLast(String::compareTo))
.thenComparing(ExtractedSupportEvent::eventId, Comparator.nullsLast(String::compareTo)));
return List.copyOf(result);
}
@ -189,36 +189,36 @@ public class UnifiedEventTimelineReconstructor {
}
private OffsetDateTime minTimestamp(
List<RuntimeActivityInterval> activityIntervals,
List<RuntimeVehicleUsageInterval> vehicleUsageIntervals,
List<RuntimeSupportEvent> supportEvents
List<ResolvedActivityInterval> activityIntervals,
List<ResolvedVehicleUsageInterval> vehicleUsageIntervals,
List<ExtractedSupportEvent> supportEvents
) {
OffsetDateTime min = null;
for (RuntimeActivityInterval interval : activityIntervals) {
for (ResolvedActivityInterval interval : activityIntervals) {
min = min(min, interval.from());
}
for (RuntimeVehicleUsageInterval interval : vehicleUsageIntervals) {
for (ResolvedVehicleUsageInterval interval : vehicleUsageIntervals) {
min = min(min, interval.from());
}
for (RuntimeSupportEvent supportEvent : supportEvents) {
for (ExtractedSupportEvent supportEvent : supportEvents) {
min = min(min, supportEvent.occurredAt());
}
return min;
}
private OffsetDateTime maxTimestamp(
List<RuntimeActivityInterval> activityIntervals,
List<RuntimeVehicleUsageInterval> vehicleUsageIntervals,
List<RuntimeSupportEvent> supportEvents
List<ResolvedActivityInterval> activityIntervals,
List<ResolvedVehicleUsageInterval> vehicleUsageIntervals,
List<ExtractedSupportEvent> supportEvents
) {
OffsetDateTime max = null;
for (RuntimeActivityInterval interval : activityIntervals) {
for (ResolvedActivityInterval interval : activityIntervals) {
max = max(max, interval.to());
}
for (RuntimeVehicleUsageInterval interval : vehicleUsageIntervals) {
for (ResolvedVehicleUsageInterval interval : vehicleUsageIntervals) {
max = max(max, interval.to());
}
for (RuntimeSupportEvent supportEvent : supportEvents) {
for (ExtractedSupportEvent supportEvent : supportEvents) {
max = max(max, supportEvent.occurredAt());
}
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)) {
return null;
}
return new RuntimeActivityInterval(
return new ResolvedActivityInterval(
intervalId,
startedAt,
endedAt,
@ -383,8 +383,8 @@ public class UnifiedEventTimelineReconstructor {
detailText(sample, "cardSlot"),
detailText(sample, "cardStatus"),
detailText(sample, "drivingStatus"),
RuntimeEntityReferenceResolver.registrationKey(sample),
RuntimeEntityReferenceResolver.vehicleKey(sample),
TachographRuntimeIdentityResolver.registrationKey(sample),
TachographRuntimeIdentityResolver.vehicleKey(sample),
text(raw, "sourceKind"),
stringList(raw, "sourceRowIds"),
booleanValue(raw, "synthetic"),
@ -427,11 +427,11 @@ public class UnifiedEventTimelineReconstructor {
}
}
private RuntimeVehicleUsageInterval finish() {
private ResolvedVehicleUsageInterval finish() {
if (startedAt == null) {
return null;
}
return RuntimeVehicleUsageInterval.resolved(
return ResolvedVehicleUsageInterval.resolved(
sessionId,
driverKey,
intervalId,
@ -439,8 +439,8 @@ public class UnifiedEventTimelineReconstructor {
endedAt,
odometerBeginKm,
odometerEndKm,
sample == null ? null : RuntimeEntityReferenceResolver.registrationKey(sample),
sample == null ? null : RuntimeEntityReferenceResolver.vehicleKey(sample),
sample == null ? null : TachographRuntimeIdentityResolver.registrationKey(sample),
sample == null ? null : TachographRuntimeIdentityResolver.vehicleKey(sample),
text(raw, "sourceKind"),
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.DriverWorkingTimeReusableProjectionBuilder;
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.model.RuntimeDriverTimeline;
import at.procon.eventhub.processing.model.RuntimeSupportEvent;
import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle;
import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest;
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.TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent;
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.TachographEsperVehicleUsageIntervalEvent;
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.OffsetDateTime;
import java.time.ZoneOffset;
@ -106,7 +107,7 @@ public class UnifiedRuntimeDerivedProjectionService {
eventBundle.mergedEvents()
);
List<EventHubEventDto> normalizedEvents = normalizationResult.normalizedEvents();
RuntimeDriverTimeline timeline = timelineReconstructor.reconstruct(
ResolvedDriverTimeline timeline = timelineReconstructor.reconstruct(
runtimeSessionId(request),
driverKey,
normalizedEvents
@ -149,7 +150,7 @@ public class UnifiedRuntimeDerivedProjectionService {
significantDrivingMinutes,
minimumRestPeriodMinutes,
timeline.activityIntervals().stream()
.map(interval -> RuntimeDriverWorkingTimeAdapter.toActivityInterval(
.map(interval -> TachographDriverWorkingTimeAdapter.toActivityInterval(
runtimeSessionId(request),
driverKey,
interval
@ -157,11 +158,11 @@ public class UnifiedRuntimeDerivedProjectionService {
.filter(Objects::nonNull)
.toList(),
timeline.vehicleUsageIntervals().stream()
.map(RuntimeDriverWorkingTimeAdapter::toVehicleUsageInterval)
.map(TachographDriverWorkingTimeAdapter::toVehicleUsageInterval)
.filter(Objects::nonNull)
.toList(),
timeline.supportEvents().stream()
.map(RuntimeDriverWorkingTimeAdapter::toSupportEvidenceEvent)
.map(this::toSupportEvidenceEvent)
.filter(Objects::nonNull)
.toList(),
notes
@ -206,11 +207,41 @@ public class UnifiedRuntimeDerivedProjectionService {
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(
UnifiedRuntimeProcessingRequest request,
List<EventHubEventDto> events
) {
return RuntimeEntityReferenceResolver.requestDriverKey(request, events);
return TachographRuntimeIdentityResolver.requestDriverKey(request, events);
}
@ -405,12 +436,12 @@ public class UnifiedRuntimeDerivedProjectionService {
}
private List<TachographEsperSupportGeoEvent> clipSupportGeoEvents(
List<RuntimeSupportEvent> supportEvents,
List<ExtractedSupportEvent> supportEvents,
String driverKey,
OffsetDateTime requestedFrom,
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 -> driverKey == null || event.driverKey() == null || Objects.equals(driverKey, event.driverKey()))
.filter(event -> requestedFrom == null || !event.occurredAt().isBefore(requestedFrom))

View File

@ -1,10 +1,10 @@
package at.procon.eventhub.processing.service;
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.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 org.springframework.stereotype.Service;
@ -22,7 +22,7 @@ public class UnifiedRuntimeDriverTimelineService {
this.timelineReconstructor = timelineReconstructor;
}
public RuntimeDriverTimeline loadDriverTimeline(UnifiedRuntimeProcessingRequest request) {
public ResolvedDriverTimeline loadDriverTimeline(UnifiedRuntimeProcessingRequest request) {
UnifiedRuntimeEventBundle bundle = runtimeEventAssemblyService.assembleDriverScopedEvents(request);
return timelineReconstructor.reconstruct(
null,
@ -35,6 +35,6 @@ public class UnifiedRuntimeDriverTimelineService {
UnifiedRuntimeProcessingRequest request,
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.lifecycle() == null ? null : event.lifecycle().name()));
parts.add(normalizeTime(event.occurredAt()));
parts.add(nullToEmpty(RuntimeEntityReferenceResolver.driverKey(event)));
parts.add(nullToEmpty(RuntimeEntityReferenceResolver.registrationKey(event)));
parts.add(nullToEmpty(RuntimeEntityReferenceResolver.vehicleKey(event)));
parts.add(nullToEmpty(TachographRuntimeIdentityResolver.driverKey(event)));
parts.add(nullToEmpty(TachographRuntimeIdentityResolver.registrationKey(event)));
parts.add(nullToEmpty(TachographRuntimeIdentityResolver.vehicleKey(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, "slot"), text(raw, "cardSlot"), text(details, "cardSlot"))));
@ -72,9 +72,9 @@ public final class RuntimeEventIdentityResolver {
parts.add("INTERVAL");
parts.add(nullToEmpty(event.eventDomain() == null ? null : event.eventDomain().name()));
parts.add(nullToEmpty(intervalSemanticType(event, raw)));
parts.add(nullToEmpty(RuntimeEntityReferenceResolver.driverKey(event)));
parts.add(nullToEmpty(RuntimeEntityReferenceResolver.registrationKey(event)));
parts.add(nullToEmpty(RuntimeEntityReferenceResolver.vehicleKey(event)));
parts.add(nullToEmpty(TachographRuntimeIdentityResolver.driverKey(event)));
parts.add(nullToEmpty(TachographRuntimeIdentityResolver.registrationKey(event)));
parts.add(nullToEmpty(TachographRuntimeIdentityResolver.vehicleKey(event)));
parts.add(nullToEmpty(intervalCardSlot(event, raw, details)));
parts.add(nullToEmpty(intervalCardStatus(event, raw, details)));
parts.add(nullToEmpty(intervalDrivingStatus(event, raw, details)));
@ -152,7 +152,7 @@ public final class RuntimeEventIdentityResolver {
}
private static JsonNode rawPayload(EventHubEventDto event) {
return RuntimeEntityReferenceResolver.rawPayload(event);
return TachographRuntimeIdentityResolver.rawPayload(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 java.util.List;
public final class RuntimeEntityReferenceResolver {
public final class TachographRuntimeIdentityResolver {
private RuntimeEntityReferenceResolver() {
private TachographRuntimeIdentityResolver() {
}
public static String driverKey(EventHubEventDto event) {

View File

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

View File

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

View File

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

View File

@ -3,7 +3,6 @@ package at.procon.eventhub.tachographfilesession.service;
import com.fasterxml.jackson.databind.JsonNode;
import at.procon.eventhub.dto.EventHubEventDto;
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.ResolvedVehicleUsageInterval;
import java.time.OffsetDateTime;
@ -52,12 +51,10 @@ public class TachographEventTimelineReconstructionHelper {
String fallbackDriverKey,
List<EventHubEventDto> events
) {
ResolvedDriverTimeline reconstructed = RuntimeTimelineCompatibilityAdapter.toResolvedDriverTimeline(
timelineReconstructor.reconstruct(
ResolvedDriverTimeline reconstructed = timelineReconstructor.reconstruct(
fallbackSessionId == null ? new UUID(0L, 0L) : fallbackSessionId,
fallbackDriverKey,
safe(events)
)
);
return new ResolvedDriverTimeline(
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.UnifiedRuntimeEventBackend;
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.service.UnifiedRuntimeDerivedProjectionService;
import at.procon.eventhub.processing.service.UnifiedRuntimeDriverTimelineService;
import at.procon.eventhub.processing.service.UnifiedRuntimeEventAssemblyService;
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.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -123,11 +123,11 @@ class UnifiedRuntimeProcessingControllerTest {
.build();
when(timelineService.loadDriverTimeline(any()))
.thenReturn(new RuntimeDriverTimeline(
.thenReturn(new ResolvedDriverTimeline(
"UNIFIED_EVENT_STREAM",
OffsetDateTime.parse("2026-05-01T08:00:00Z"),
OffsetDateTime.parse("2026-05-01T10:00:00Z"),
List.of(RuntimeVehicleUsageInterval.resolved(
List.of(ResolvedVehicleUsageInterval.resolved(
null,
"DRIVER:42",
"CVU-1",
@ -140,7 +140,7 @@ class UnifiedRuntimeProcessingControllerTest {
"DRIVER_CARD",
List.of("CVU-1")
)),
List.of(new RuntimeActivityInterval(
List.of(new ResolvedActivityInterval(
"ACT-1",
OffsetDateTime.parse("2026-05-01T08:30:00Z"),
OffsetDateTime.parse("2026-05-01T09:00:00Z"),
@ -181,6 +181,7 @@ class UnifiedRuntimeProcessingControllerTest {
.andExpect(jsonPath("$.vehicleUsageIntervals[0].intervalId").value("CVU-1"));
}
@Test
void loadsDriverDerivedProjectionsViaRuntimeApi() throws Exception {
UnifiedRuntimeEventAssemblyService eventAssemblyService = org.mockito.Mockito.mock(UnifiedRuntimeEventAssemblyService.class);

View File

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

View File

@ -3,7 +3,6 @@ package at.procon.eventhub.processing.service;
import static org.assertj.core.api.Assertions.assertThat;
import at.procon.eventhub.config.EventHubProperties;
import at.procon.eventhub.processing.model.RuntimeDriverTimeline;
import at.procon.eventhub.processing.model.UnifiedDriverTimelineRequest;
import at.procon.eventhub.service.EventDetailsFactory;
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.ExtractedVehicleRegistration;
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.TachographFileSessionMetadata;
import at.procon.eventhub.tachographfilesession.service.DriverKeyFactory;
@ -55,7 +55,7 @@ class UnifiedDriverTimelineServiceTest {
TachographFileSession session = session(driver);
repository.save(session);
RuntimeDriverTimeline timeline = service.loadDriverTimeline(
ResolvedDriverTimeline timeline = service.loadDriverTimeline(
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.VehicleRefDto;
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.ObjectNode;
import java.math.BigDecimal;
@ -38,7 +38,7 @@ class UnifiedEventTimelineReconstructorTest {
supportEvent("SUP-1", "2026-05-01T08:30:00Z")
);
RuntimeDriverTimeline timeline = reconstructor.reconstruct(
ResolvedDriverTimeline timeline = reconstructor.reconstruct(
UUID.randomUUID(),
"DRIVER:42",
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")
);
RuntimeDriverTimeline timeline = reconstructor.reconstruct(
ResolvedDriverTimeline timeline = reconstructor.reconstruct(
UUID.randomUUID(),
"DRIVER:42",
events
@ -105,7 +105,7 @@ class UnifiedEventTimelineReconstructorTest {
)
);
RuntimeDriverTimeline timeline = reconstructor.reconstruct(
ResolvedDriverTimeline timeline = reconstructor.reconstruct(
UUID.randomUUID(),
"DRIVER:42",
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.UnifiedEventSourceFamily;
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.tachographfilesession.model.ResolvedDriverTimeline;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.time.LocalDate;
@ -40,7 +40,7 @@ class UnifiedRuntimeDriverTimelineServiceTest {
new UnifiedEventTimelineReconstructor()
);
RuntimeDriverTimeline timeline = service.loadDriverTimeline(
ResolvedDriverTimeline timeline = service.loadDriverTimeline(
new UnifiedRuntimeProcessingRequest(
null,
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.VehicleRefDto;
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.service.EventAcquisitionRecordKeyService;
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(second, secondDriver)).thenReturn(List.of(event("b", occurredAt.plusHours(1), EventType.DRIVE)));
RuntimeDriverTimeline reconstructed = new RuntimeDriverTimeline(
ResolvedDriverTimeline expected = new ResolvedDriverTimeline(
"COMPOSITE_TACHOGRAPH_FILE_SESSION",
occurredAt,
occurredAt.plusHours(1),
@ -187,22 +185,14 @@ class TachographCompositeSessionServiceTest {
List.of()
);
when(reconstructor.reconstruct(any(), eq("12:123"), any(), any(), eq("COMPOSITE_TACHOGRAPH_FILE_SESSION")))
.thenReturn(reconstructed);
.thenReturn(expected);
ResolvedDriverTimeline actual =
service.getMergedDriverTimeline(created.session().compositeSessionId(), "12:123");
assertThat(actual).isEqualTo(new ResolvedDriverTimeline(
"COMPOSITE_TACHOGRAPH_FILE_SESSION",
occurredAt,
occurredAt.plusHours(1),
List.of(),
List.of(),
List.of(),
List.of()
));
assertThat(actual).isSameAs(expected);
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(
eq(created.session().compositeSessionId()),
eq("12:123"),
@ -213,10 +203,10 @@ class TachographCompositeSessionServiceTest {
assertThat(eventsCaptor.getValue()).extracting(EventHubEventDto::externalSourceEventId)
.containsExactly("a", "b");
assertThat(warningsCaptor.getValue()).containsExactly(
new RuntimeExtractionWarning("SESSION_A", "warn-a", "s1"),
new RuntimeExtractionWarning("CARD_GAP", "gap", "p1"),
new RuntimeExtractionWarning("SESSION_B", "warn-b", "s2"),
new RuntimeExtractionWarning("DUPLICATE", "duplicate", "p2")
new ExtractionWarning("SESSION_A", "warn-a", "s1"),
new ExtractionWarning("CARD_GAP", "gap", "p1"),
new ExtractionWarning("SESSION_B", "warn-b", "s2"),
new ExtractionWarning("DUPLICATE", "duplicate", "p2")
);
}