Finalize neutral working-time projection architecture

This commit is contained in:
trifonovt 2026-05-27 08:44:49 +02:00
parent cd090010c6
commit 927ac3b903
18 changed files with 2789 additions and 2879 deletions

View File

@ -1,14 +1,12 @@
package at.procon.eventhub.processing.driverworkingtime.dto; package at.procon.eventhub.processing.driverworkingtime.dto;
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent; import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeActivityInterval;
import at.procon.eventhub.tachographfilesession.model.TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent; import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeDrivingInterruptionInterval;
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent; import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimePotentialInVehicleTripInterval;
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent; import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeRestCoverageInterval;
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleOvernightStayIntervalEvent; import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeSupportGeoEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleTripIntervalEvent; import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeVehicleUsageInterval;
import at.procon.eventhub.tachographfilesession.model.TachographEsperSupportGeoEvent; import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeVuCardAbsentInterval;
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -34,19 +32,19 @@ public record DriverWorkingTimeProcessingResultDto(
int vehicleUsageIntervalCount, int vehicleUsageIntervalCount,
int vuCardAbsentIntervalCount, int vuCardAbsentIntervalCount,
int supportGeoEventCount, int supportGeoEventCount,
List<TachographEsperActivityIntervalEvent> activityIntervals, List<DriverWorkingTimeActivityInterval> activityIntervals,
List<TachographEsperActivityIntervalEvent> drivingIntervals, List<DriverWorkingTimeActivityInterval> drivingIntervals,
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals, List<DriverWorkingTimeDrivingInterruptionInterval> drivingInterruptionIntervals,
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionVehicleChangeIntervals, List<DriverWorkingTimeDrivingInterruptionInterval> drivingInterruptionVehicleChangeIntervals,
List<TachographEsperDrivingInterruptionIntervalEvent> dailyWeeklyRestCandidateIntervals, List<DriverWorkingTimeDrivingInterruptionInterval> dailyWeeklyRestCandidateIntervals,
List<TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent> dailyWeeklyRestCandidateCoverageIntervals, List<DriverWorkingTimeRestCoverageInterval> dailyWeeklyRestCandidateCoverageIntervals,
List<TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent> unclassifiedDailyWeeklyRestCandidateCoverageIntervals, List<DriverWorkingTimeRestCoverageInterval> unclassifiedDailyWeeklyRestCandidateCoverageIntervals,
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> potentialHomeOvernightStayIntervals, List<DriverWorkingTimeRestCoverageInterval> potentialHomeOvernightStayIntervals,
List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> potentialInVehicleOvernightStayIntervals, List<DriverWorkingTimeRestCoverageInterval> potentialInVehicleOvernightStayIntervals,
List<TachographEsperPotentialInVehicleTripIntervalEvent> potentialInVehicleTripIntervals, List<DriverWorkingTimePotentialInVehicleTripInterval> potentialInVehicleTripIntervals,
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageIntervals, List<DriverWorkingTimeVehicleUsageInterval> vehicleUsageIntervals,
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals, List<DriverWorkingTimeVuCardAbsentInterval> vuCardAbsentIntervals,
List<TachographEsperSupportGeoEvent> supportGeoEvents, List<DriverWorkingTimeSupportGeoEvent> supportGeoEvents,
List<String> notes List<String> notes
) { ) {
} }

View File

@ -1,6 +1,5 @@
package at.procon.eventhub.processing.driverworkingtime.model; package at.procon.eventhub.processing.driverworkingtime.model;
import at.procon.eventhub.tachographfilesession.model.ResolvedActivityInterval;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -62,49 +61,6 @@ public record DriverWorkingTimeActivityInterval(
); );
} }
public static DriverWorkingTimeActivityInterval fromResolved(
UUID sessionId,
String driverKey,
ResolvedActivityInterval 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()
);
}
private static String firstSourceIntervalId(ResolvedActivityInterval interval) {
return interval.sourceIntervalIds().isEmpty() ? interval.intervalId() : interval.sourceIntervalIds().get(0);
}
private static String lastSourceIntervalId(ResolvedActivityInterval interval) {
return interval.sourceIntervalIds().isEmpty()
? interval.intervalId()
: interval.sourceIntervalIds().get(interval.sourceIntervalIds().size() - 1);
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static List<String> castStringList(Object value) { private static List<String> castStringList(Object value) {
return value instanceof List<?> list ? (List<String>) list : List.of(); return value instanceof List<?> list ? (List<String>) list : List.of();

View File

@ -1,6 +1,5 @@
package at.procon.eventhub.processing.driverworkingtime.model; package at.procon.eventhub.processing.driverworkingtime.model;
import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -52,40 +51,6 @@ public record DriverWorkingTimeVehicleUsageInterval(
); );
} }
public static DriverWorkingTimeVehicleUsageInterval fromResolved(ResolvedVehicleUsageInterval 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()
);
}
private static String firstSourceIntervalId(ResolvedVehicleUsageInterval interval) {
return interval.sourceIntervalIds().isEmpty() ? interval.intervalId() : interval.sourceIntervalIds().get(0);
}
private static String lastSourceIntervalId(ResolvedVehicleUsageInterval interval) {
return interval.sourceIntervalIds().isEmpty()
? interval.intervalId()
: interval.sourceIntervalIds().get(interval.sourceIntervalIds().size() - 1);
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static List<String> castStringList(Object value) { private static List<String> castStringList(Object value) {
return value instanceof List<?> list ? (List<String>) list : List.of(); return value instanceof List<?> list ? (List<String>) list : List.of();

View File

@ -1,426 +1,23 @@
package at.procon.eventhub.processing.driverworkingtime.service; package at.procon.eventhub.processing.driverworkingtime.service;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeActivityInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeDerivedProjectionBundle; import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeDerivedProjectionBundle;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeDrivingInterruptionInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeGeoEvidenceEvent;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimePotentialInVehicleTripInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeProcessingInput; import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeProcessingInput;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeRestCoverageInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeVehicleUsageInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeVuCardAbsentInterval;
import at.procon.eventhub.processing.eventprocessing.support.RuntimeSupportEvidenceEvent;
import at.procon.eventhub.tachographfilesession.model.ExtractedSupportEvent;
import at.procon.eventhub.tachographfilesession.model.ResolvedActivityInterval;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval;
import at.procon.eventhub.tachographfilesession.model.TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingDerivedProjectionBundle;
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperGeoEvidenceEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleOvernightStayIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleTripIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
import at.procon.eventhub.tachographfilesession.service.DriverTimelineReusableProjectionBuilder;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.UUID;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
public class DriverWorkingTimeDerivedProjectionEngine { public class DriverWorkingTimeDerivedProjectionEngine {
private final DriverTimelineReusableProjectionBuilder legacyProjectionBuilder; private final DriverWorkingTimeReusableProjectionBuilder projectionBuilder;
public DriverWorkingTimeDerivedProjectionEngine( public DriverWorkingTimeDerivedProjectionEngine(
DriverTimelineReusableProjectionBuilder legacyProjectionBuilder DriverWorkingTimeReusableProjectionBuilder projectionBuilder
) { ) {
this.legacyProjectionBuilder = legacyProjectionBuilder; this.projectionBuilder = projectionBuilder;
} }
public DriverWorkingTimeDerivedProjectionBundle build(DriverWorkingTimeProcessingInput input) { public DriverWorkingTimeDerivedProjectionBundle build(DriverWorkingTimeProcessingInput input) {
Objects.requireNonNull(input, "input must not be null"); Objects.requireNonNull(input, "input must not be null");
ResolvedDriverTimeline timeline = toResolvedTimeline(input); return projectionBuilder.buildDerivedProjectionBundle(input);
TachographEsperDrivingDerivedProjectionBundle legacyBundle =
legacyProjectionBuilder.buildEsperDrivingDerivedProjectionBundle(
safeSessionId(input.sessionId()),
input.driverKey(),
timeline,
input.significantDrivingMinutes(),
input.minimumRestPeriodMinutes()
);
return new DriverWorkingTimeDerivedProjectionBundle(
legacyBundle.drivingInterruptionIntervals().stream().map(this::mapDrivingInterruption).toList(),
legacyBundle.dailyWeeklyRestCandidateIntervals().stream().map(this::mapDrivingInterruption).toList(),
legacyBundle.dailyWeeklyRestCandidateCoverageIntervals().stream().map(this::mapRestCoverage).toList(),
legacyBundle.unclassifiedDailyWeeklyRestCandidateCoverageIntervals().stream().map(this::mapRestCoverage).toList(),
legacyBundle.drivingInterruptionVehicleChangeIntervals().stream().map(this::mapDrivingInterruption).toList(),
legacyBundle.vuCardAbsentIntervals().stream().map(this::mapVuCardAbsent).toList(),
legacyBundle.potentialHomeOvernightStayIntervals().stream().map(this::mapPotentialHome).toList(),
legacyBundle.potentialInVehicleOvernightStayIntervals().stream().map(this::mapPotentialInVehicle).toList(),
legacyBundle.potentialInVehicleTripIntervals().stream().map(this::mapPotentialTrip).toList()
);
}
private ResolvedDriverTimeline toResolvedTimeline(DriverWorkingTimeProcessingInput input) {
List<ResolvedActivityInterval> activityIntervals = input.activityIntervals().stream()
.map(this::toResolvedActivityInterval)
.filter(Objects::nonNull)
.toList();
List<ResolvedVehicleUsageInterval> vehicleUsageIntervals = input.vehicleUsageIntervals().stream()
.map(this::toResolvedVehicleUsageInterval)
.filter(Objects::nonNull)
.toList();
List<ExtractedSupportEvent> supportEvents = input.supportEvidenceEvents().stream()
.map(this::toExtractedSupportEvent)
.filter(Objects::nonNull)
.toList();
OffsetDateTime loadedFrom = input.loadedFrom() == null
? earliest(activityIntervals, vehicleUsageIntervals, supportEvents)
: utc(input.loadedFrom());
OffsetDateTime loadedTo = input.loadedTo() == null
? latest(activityIntervals, vehicleUsageIntervals, supportEvents)
: utc(input.loadedTo());
return new ResolvedDriverTimeline(
input.sourceKind(),
loadedFrom,
loadedTo,
vehicleUsageIntervals,
activityIntervals,
supportEvents,
List.of()
);
}
private ResolvedActivityInterval toResolvedActivityInterval(DriverWorkingTimeActivityInterval interval) {
if (interval == null || interval.startedAt() == null || interval.endedAt() == null) {
return null;
}
return new ResolvedActivityInterval(
interval.intervalId(),
utc(interval.startedAt()),
utc(interval.endedAt()),
interval.durationSeconds(),
interval.activityType(),
interval.cardSlot(),
interval.cardStatus(),
interval.drivingStatus(),
interval.registrationKey(),
interval.vehicleKey(),
interval.sourceKind(),
interval.sourceIntervalIds(),
interval.synthetic(),
interval.clippedToRequestedPeriod(),
interval.level()
);
}
private ResolvedVehicleUsageInterval toResolvedVehicleUsageInterval(DriverWorkingTimeVehicleUsageInterval interval) {
if (interval == null || interval.startedAt() == null) {
return null;
}
return new ResolvedVehicleUsageInterval(
safeSessionId(interval.sessionId()),
interval.driverKey(),
interval.intervalId(),
utc(interval.startedAt()),
utc(interval.endedAt()),
interval.durationSeconds(),
interval.odometerBeginKm(),
interval.odometerEndKm(),
interval.registrationKey(),
interval.vehicleKey(),
interval.sourceKind(),
interval.sourceIntervalIds()
);
}
private ExtractedSupportEvent toExtractedSupportEvent(RuntimeSupportEvidenceEvent supportEvent) {
if (supportEvent == null || supportEvent.occurredAt() == null) {
return null;
}
Object rawRecordPath = supportEvent.rawAttributes().get("rawRecordPath");
return new ExtractedSupportEvent(
supportEvent.eventId(),
supportEvent.driverKey(),
utc(supportEvent.occurredAt()),
supportEvent.eventDomain(),
supportEvent.eventType(),
supportEvent.lifecycle(),
null,
supportEvent.registrationKey(),
supportEvent.vehicleKey(),
supportEvent.countryCode(),
supportEvent.regionCode(),
supportEvent.countryFrom(),
supportEvent.countryTo(),
supportEvent.operation(),
supportEvent.latitude(),
supportEvent.longitude(),
null,
supportEvent.odometerKm(),
null,
supportEvent.speedKmh(),
supportEvent.maxSpeedKmh(),
rawRecordPath == null ? null : rawRecordPath.toString()
);
}
private DriverWorkingTimeDrivingInterruptionInterval mapDrivingInterruption(
TachographEsperDrivingInterruptionIntervalEvent value
) {
return new DriverWorkingTimeDrivingInterruptionInterval(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.previousDrivingSourceIntervalId(),
value.nextDrivingSourceIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey()
);
}
private DriverWorkingTimeVuCardAbsentInterval mapVuCardAbsent(TachographEsperVuCardAbsentIntervalEvent value) {
return new DriverWorkingTimeVuCardAbsentInterval(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.previousUsageIntervalId(),
value.nextUsageIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey()
);
}
private DriverWorkingTimeRestCoverageInterval mapRestCoverage(
TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent value
) {
return new DriverWorkingTimeRestCoverageInterval(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.cardAbsentDurationSeconds(),
value.cardAbsentCoveragePercent(),
value.previousDrivingSourceIntervalId(),
value.nextDrivingSourceIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey(),
value.beginBoundaryOdometerKm(),
value.endBoundaryOdometerKm(),
value.beginGeoEventId(),
value.beginGeoEventDomain(),
value.beginGeoOccurredAt(),
value.beginLatitude(),
value.beginLongitude(),
value.beginGeoDistanceSeconds(),
value.beginGeoOdometerKm(),
value.endGeoEventId(),
value.endGeoEventDomain(),
value.endGeoOccurredAt(),
value.endLatitude(),
value.endLongitude(),
value.endGeoDistanceSeconds(),
value.endGeoOdometerKm(),
value.geoEvidenceMovementMeters(),
value.geoEvidenceMovementCategory(),
mapGeoEvidence(value.beginGeoEvent()),
mapGeoEvidence(value.endGeoEvent())
);
}
private DriverWorkingTimeRestCoverageInterval mapPotentialHome(
TachographEsperPotentialHomeOvernightStayIntervalEvent value
) {
return new DriverWorkingTimeRestCoverageInterval(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.cardAbsentDurationSeconds(),
value.cardAbsentCoveragePercent(),
value.previousDrivingSourceIntervalId(),
value.nextDrivingSourceIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey(),
value.beginBoundaryOdometerKm(),
value.endBoundaryOdometerKm(),
value.beginGeoEventId(),
value.beginGeoEventDomain(),
value.beginGeoOccurredAt(),
value.beginLatitude(),
value.beginLongitude(),
value.beginGeoDistanceSeconds(),
value.beginGeoOdometerKm(),
value.endGeoEventId(),
value.endGeoEventDomain(),
value.endGeoOccurredAt(),
value.endLatitude(),
value.endLongitude(),
value.endGeoDistanceSeconds(),
value.endGeoOdometerKm(),
value.geoEvidenceMovementMeters(),
value.geoEvidenceMovementCategory(),
mapGeoEvidence(value.beginGeoEvent()),
mapGeoEvidence(value.endGeoEvent())
);
}
private DriverWorkingTimeRestCoverageInterval mapPotentialInVehicle(
TachographEsperPotentialInVehicleOvernightStayIntervalEvent value
) {
return new DriverWorkingTimeRestCoverageInterval(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.cardAbsentDurationSeconds(),
value.cardAbsentCoveragePercent(),
value.previousDrivingSourceIntervalId(),
value.nextDrivingSourceIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey(),
value.beginBoundaryOdometerKm(),
value.endBoundaryOdometerKm(),
value.beginGeoEventId(),
value.beginGeoEventDomain(),
value.beginGeoOccurredAt(),
value.beginLatitude(),
value.beginLongitude(),
value.beginGeoDistanceSeconds(),
value.beginGeoOdometerKm(),
value.endGeoEventId(),
value.endGeoEventDomain(),
value.endGeoOccurredAt(),
value.endLatitude(),
value.endLongitude(),
value.endGeoDistanceSeconds(),
value.endGeoOdometerKm(),
value.geoEvidenceMovementMeters(),
value.geoEvidenceMovementCategory(),
mapGeoEvidence(value.beginGeoEvent()),
mapGeoEvidence(value.endGeoEvent())
);
}
private DriverWorkingTimePotentialInVehicleTripInterval mapPotentialTrip(
TachographEsperPotentialInVehicleTripIntervalEvent value
) {
return new DriverWorkingTimePotentialInVehicleTripInterval(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.registrationKey(),
value.vehicleKey(),
value.containedPotentialInVehicleOvernightStayIntervalCount(),
value.containedPotentialInVehicleOvernightStayDurationSeconds(),
value.containedCardAbsentDurationSeconds(),
value.firstPotentialInVehicleOvernightStayStartedAt(),
value.lastPotentialInVehicleOvernightStayEndedAt(),
value.firstPreviousDrivingSourceIntervalId(),
value.lastNextDrivingSourceIntervalId(),
value.potentialInVehicleOvernightStayIntervals().stream().map(this::mapPotentialInVehicle).toList()
);
}
private DriverWorkingTimeGeoEvidenceEvent mapGeoEvidence(TachographEsperGeoEvidenceEvent value) {
if (value == null) {
return null;
}
return new DriverWorkingTimeGeoEvidenceEvent(
value.eventId(),
value.eventDomain(),
value.occurredAt(),
value.latitude(),
value.longitude(),
value.distanceSeconds(),
value.odometerKm()
);
}
private OffsetDateTime earliest(
List<ResolvedActivityInterval> activityIntervals,
List<ResolvedVehicleUsageInterval> vehicleUsageIntervals,
List<ExtractedSupportEvent> supportEvents
) {
OffsetDateTime earliest = null;
for (ResolvedActivityInterval interval : activityIntervals) {
earliest = min(earliest, interval.from());
}
for (ResolvedVehicleUsageInterval interval : vehicleUsageIntervals) {
earliest = min(earliest, interval.from());
}
for (ExtractedSupportEvent event : supportEvents) {
earliest = min(earliest, event.occurredAt());
}
return earliest;
}
private OffsetDateTime latest(
List<ResolvedActivityInterval> activityIntervals,
List<ResolvedVehicleUsageInterval> vehicleUsageIntervals,
List<ExtractedSupportEvent> supportEvents
) {
OffsetDateTime latest = null;
for (ResolvedActivityInterval interval : activityIntervals) {
latest = max(latest, interval.to());
}
for (ResolvedVehicleUsageInterval interval : vehicleUsageIntervals) {
latest = max(latest, interval.to());
}
for (ExtractedSupportEvent event : supportEvents) {
latest = max(latest, event.occurredAt());
}
return latest;
}
private UUID safeSessionId(UUID sessionId) {
return sessionId == null ? new UUID(0L, 0L) : sessionId;
}
private OffsetDateTime utc(OffsetDateTime value) {
return value == null ? null : value.withOffsetSameInstant(java.time.ZoneOffset.UTC);
}
private OffsetDateTime max(OffsetDateTime left, OffsetDateTime right) {
if (left == null) {
return right;
}
if (right == null) {
return left;
}
return left.isAfter(right) ? left : right;
}
private OffsetDateTime min(OffsetDateTime left, OffsetDateTime right) {
if (left == null) {
return right;
}
if (right == null) {
return left;
}
return left.isBefore(right) ? left : right;
} }
} }

View File

@ -0,0 +1,769 @@
package at.procon.eventhub.processing.driverworkingtime.service;
import com.espertech.esper.common.client.EPCompiled;
import com.espertech.esper.common.client.EventBean;
import com.espertech.esper.common.client.configuration.Configuration;
import com.espertech.esper.compiler.client.CompilerArguments;
import com.espertech.esper.compiler.client.EPCompileException;
import com.espertech.esper.compiler.client.EPCompilerProvider;
import com.espertech.esper.runtime.client.EPDeployException;
import com.espertech.esper.runtime.client.EPDeployment;
import com.espertech.esper.runtime.client.EPRuntime;
import com.espertech.esper.runtime.client.EPRuntimeProvider;
import at.procon.eventhub.config.EventHubProperties;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeActivityInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeDerivedProjectionBundle;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeDrivingInterruptionInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeGeoEvidenceEvent;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimePotentialInVehicleTripInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeProcessingInput;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeRestCoverageInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeVehicleUsageInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeVuCardAbsentInterval;
import at.procon.eventhub.processing.eventprocessing.support.RuntimeSupportEvidenceEvent;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.util.StreamUtils;
@Service
public class DriverWorkingTimeReusableProjectionBuilder {
private static final AtomicLong RUNTIME_COUNTER = new AtomicLong();
private static final String DRIVING_DERIVED_PROJECTION_BUNDLE_EPL_TEMPLATE =
loadResource("esper/driver-working-time-derived-projections.epl");
private final EventHubProperties properties;
@Autowired
public DriverWorkingTimeReusableProjectionBuilder(
EventHubProperties properties
) {
this.properties = properties;
}
public DriverWorkingTimeDerivedProjectionBundle buildDerivedProjectionBundle(
DriverWorkingTimeProcessingInput input
) {
if (input == null) {
return emptyDerivedProjectionBundle();
}
return buildDerivedProjectionBundle(
buildActivityIntervalInputEvents(input.activityIntervals()),
buildVehicleUsageIntervalInputEventsCommon(input.vehicleUsageIntervals()),
buildSupportGeoInputEventsCommon(input.sessionId(), input.supportEvidenceEvents()),
input.significantDrivingMinutes(),
input.minimumRestPeriodMinutes()
);
}
private DriverWorkingTimeDerivedProjectionBundle buildDerivedProjectionBundle(
List<Map<String, Object>> activityInputEvents,
List<Map<String, Object>> vehicleUsageInputEvents,
List<Map<String, Object>> supportGeoInputEvents,
int significantDrivingMinutes,
int minimumRestPeriodMinutes
) {
if ((activityInputEvents == null || activityInputEvents.isEmpty())
&& (vehicleUsageInputEvents == null || vehicleUsageInputEvents.isEmpty())) {
return emptyDerivedProjectionBundle();
}
List<DriverWorkingTimeDrivingInterruptionInterval> drivingInterruptionIntervals = new ArrayList<>();
List<DriverWorkingTimeDrivingInterruptionInterval> dailyWeeklyRestCandidateIntervals = new ArrayList<>();
List<DriverWorkingTimeRestCoverageInterval> dailyWeeklyRestCandidateCoverageIntervals = new ArrayList<>();
List<DriverWorkingTimeRestCoverageInterval> unclassifiedDailyWeeklyRestCandidateCoverageIntervals = new ArrayList<>();
List<DriverWorkingTimeDrivingInterruptionInterval> drivingInterruptionVehicleChangeIntervals = new ArrayList<>();
List<DriverWorkingTimeVuCardAbsentInterval> vuCardAbsentIntervals = new ArrayList<>();
List<DriverWorkingTimeRestCoverageInterval> potentialHomeOvernightStayIntervals = new ArrayList<>();
List<DriverWorkingTimeRestCoverageInterval> potentialInVehicleOvernightStayIntervals = new ArrayList<>();
List<DriverWorkingTimePotentialInVehicleTripInterval> potentialInVehicleTripIntervals = new ArrayList<>();
executeWithRuntime(
configuration -> {
configuration.getCommon().addEventType(
"TachographActivityIntervalInputEvent",
activityIntervalInputDefinition()
);
configuration.getCommon().addEventType(
"TachographVehicleUsageIntervalInputEvent",
vehicleUsageIntervalInputDefinition()
);
configuration.getCommon().addEventType(
"TachographSupportGeoEvidenceInputEvent",
supportGeoEvidenceInputDefinition()
);
},
renderDrivingDerivedProjectionBundleEpl(significantDrivingMinutes, minimumRestPeriodMinutes),
Map.of(
"drivingInterruptionIntervals",
newData -> collectDrivingInterruptionIntervalModels(newData, drivingInterruptionIntervals),
"dailyWeeklyRestCandidateIntervals",
newData -> collectDrivingInterruptionIntervalModels(newData, dailyWeeklyRestCandidateIntervals),
"dailyWeeklyRestCandidateCoverageIntervals",
newData -> collectDailyWeeklyRestCandidateCoverageIntervalModels(newData, dailyWeeklyRestCandidateCoverageIntervals),
"unclassifiedDailyWeeklyRestCandidateCoverageIntervals",
newData -> collectDailyWeeklyRestCandidateCoverageIntervalModels(newData, unclassifiedDailyWeeklyRestCandidateCoverageIntervals),
"drivingInterruptionVehicleChangeIntervals",
newData -> collectDrivingInterruptionIntervalModels(newData, drivingInterruptionVehicleChangeIntervals),
"vuCardAbsentIntervals",
newData -> collectVuCardAbsentIntervalModels(newData, vuCardAbsentIntervals),
"potentialHomeOvernightStayIntervals",
newData -> collectPotentialHomeOvernightStayIntervalModels(newData, potentialHomeOvernightStayIntervals),
"potentialInVehicleOvernightStayIntervals",
newData -> collectPotentialInVehicleOvernightStayIntervalModels(newData, potentialInVehicleOvernightStayIntervals),
"potentialInVehicleTripIntervals",
newData -> collectPotentialInVehicleTripIntervalModels(newData, potentialInVehicleTripIntervals)
),
runtime -> {
if (supportGeoInputEvents != null) {
for (Map<String, Object> supportGeoEvidence : supportGeoInputEvents) {
runtime.getEventService().sendEventMap(
supportGeoEvidence,
"TachographSupportGeoEvidenceInputEvent"
);
}
}
if (vehicleUsageInputEvents != null) {
for (Map<String, Object> interval : vehicleUsageInputEvents) {
runtime.getEventService().sendEventMap(
interval,
"TachographVehicleUsageIntervalInputEvent"
);
}
}
if (activityInputEvents != null) {
for (Map<String, Object> interval : activityInputEvents) {
runtime.getEventService().sendEventMap(
interval,
"TachographActivityIntervalInputEvent"
);
}
}
}
);
List<DriverWorkingTimeRestCoverageInterval> sortedDailyWeeklyRestCandidateCoverageIntervals =
sortDailyWeeklyRestCandidateCoverageIntervalsCommon(dailyWeeklyRestCandidateCoverageIntervals);
List<DriverWorkingTimeRestCoverageInterval> sortedUnclassifiedDailyWeeklyRestCandidateCoverageIntervals =
sortDailyWeeklyRestCandidateCoverageIntervalsCommon(unclassifiedDailyWeeklyRestCandidateCoverageIntervals);
List<DriverWorkingTimeRestCoverageInterval> sortedPotentialHomeOvernightStayIntervals =
sortPotentialHomeOvernightStayIntervalsCommon(potentialHomeOvernightStayIntervals);
List<DriverWorkingTimeRestCoverageInterval> sortedPotentialInVehicleOvernightStayIntervals =
sortPotentialInVehicleOvernightStayIntervalsCommon(potentialInVehicleOvernightStayIntervals);
return new DriverWorkingTimeDerivedProjectionBundle(
sortDrivingInterruptionIntervalsCommon(drivingInterruptionIntervals),
sortDrivingInterruptionIntervalsCommon(dailyWeeklyRestCandidateIntervals),
sortedDailyWeeklyRestCandidateCoverageIntervals,
sortedUnclassifiedDailyWeeklyRestCandidateCoverageIntervals,
sortDrivingInterruptionIntervalsCommon(drivingInterruptionVehicleChangeIntervals),
sortVuCardAbsentIntervalsCommon(vuCardAbsentIntervals),
sortedPotentialHomeOvernightStayIntervals,
sortedPotentialInVehicleOvernightStayIntervals,
sortPotentialInVehicleTripIntervalsCommon(potentialInVehicleTripIntervals)
);
}
private List<Map<String, Object>> buildActivityIntervalInputEvents(
List<DriverWorkingTimeActivityInterval> activityIntervals
) {
return safeList(activityIntervals).stream()
.map(this::toActivityIntervalInputMap)
.filter(Objects::nonNull)
.sorted(Comparator
.comparing((Map<String, Object> event) -> (Long) event.get("startedAtEpochSecond"))
.thenComparing(event -> Objects.toString(event.get("driverKey"), ""))
.thenComparing(event -> Objects.toString(event.get("intervalId"), "")))
.toList();
}
private List<Map<String, Object>> buildVehicleUsageIntervalInputEventsCommon(
List<DriverWorkingTimeVehicleUsageInterval> vehicleUsageIntervals
) {
return safeList(vehicleUsageIntervals).stream()
.map(this::toVehicleUsageIntervalInputMap)
.filter(Objects::nonNull)
.sorted(Comparator
.comparing((Map<String, Object> event) -> (Long) event.get("startedAtEpochSecond"))
.thenComparing(event -> Objects.toString(event.get("driverKey"), ""))
.thenComparing(event -> Objects.toString(event.get("intervalId"), "")))
.toList();
}
private List<Map<String, Object>> buildSupportGeoInputEventsCommon(
UUID sessionId,
List<RuntimeSupportEvidenceEvent> supportEvents
) {
return safeList(supportEvents).stream()
.map(event -> toSupportGeoEvidenceInputMap(sessionId, event))
.filter(Objects::nonNull)
.sorted(Comparator
.comparing((Map<String, Object> event) -> (Long) event.get("occurredAtEpochSecond"))
.thenComparing(event -> Objects.toString(event.get("driverKey"), ""))
.thenComparing(event -> Objects.toString(event.get("eventId"), "")))
.toList();
}
private <T> List<T> safeList(List<T> values) {
return values == null ? List.of() : values;
}
private DriverWorkingTimeDerivedProjectionBundle emptyDerivedProjectionBundle() {
return new DriverWorkingTimeDerivedProjectionBundle(
List.of(),
List.of(),
List.of(),
List.of(),
List.of(),
List.of(),
List.of(),
List.of(),
List.of()
);
}
private void executeWithRuntime(
Consumer<Configuration> configurationSetup,
String epl,
Map<String, Consumer<EventBean[]>> listeners,
Consumer<EPRuntime> sender
) {
EPRuntime runtime = null;
try {
Configuration configuration = new Configuration();
configurationSetup.accept(configuration);
String runtimeUri = "eventhub-tachograph-reusable-projection-" + RUNTIME_COUNTER.incrementAndGet();
runtime = EPRuntimeProvider.getRuntime(runtimeUri, configuration);
CompilerArguments arguments = new CompilerArguments(configuration);
EPCompiled compiled = EPCompilerProvider.getCompiler().compile(epl, arguments);
EPDeployment deployment = runtime.getDeploymentService().deploy(compiled);
for (Map.Entry<String, Consumer<EventBean[]>> entry : listeners.entrySet()) {
runtime.getDeploymentService()
.getStatement(deployment.getDeploymentId(), entry.getKey())
.addListener((newData, oldData, statement, rt) -> entry.getValue().accept(newData));
}
sender.accept(runtime);
} catch (EPCompileException | EPDeployException e) {
throw new IllegalStateException("Cannot compile/deploy reusable tachograph projection EPL bundle", e);
} finally {
if (runtime != null) {
runtime.destroy();
}
}
}
private Map<String, Object> activityIntervalInputDefinition() {
Map<String, Object> definition = new LinkedHashMap<>();
definition.put("sessionId", UUID.class);
definition.put("driverKey", String.class);
definition.put("intervalId", String.class);
definition.put("activityType", String.class);
definition.put("cardSlot", String.class);
definition.put("cardStatus", String.class);
definition.put("drivingStatus", String.class);
definition.put("registrationKey", String.class);
definition.put("vehicleKey", String.class);
definition.put("sourceKind", String.class);
definition.put("firstSourceIntervalId", String.class);
definition.put("lastSourceIntervalId", String.class);
definition.put("startedAt", OffsetDateTime.class);
definition.put("endedAt", OffsetDateTime.class);
definition.put("startedAtEpochSecond", long.class);
definition.put("endedAtEpochSecond", long.class);
definition.put("durationSeconds", long.class);
definition.put("sourceIntervalIds", java.util.List.class);
definition.put("synthetic", boolean.class);
definition.put("clippedToRequestedPeriod", boolean.class);
definition.put("level", String.class);
return definition;
}
private Map<String, Object> vehicleUsageIntervalInputDefinition() {
Map<String, Object> definition = new LinkedHashMap<>();
definition.put("sessionId", UUID.class);
definition.put("driverKey", String.class);
definition.put("intervalId", String.class);
definition.put("firstSourceIntervalId", String.class);
definition.put("lastSourceIntervalId", String.class);
definition.put("startedAt", OffsetDateTime.class);
definition.put("endedAt", OffsetDateTime.class);
definition.put("startedAtEpochSecond", long.class);
definition.put("endedAtEpochSecond", Long.class);
definition.put("durationSeconds", long.class);
definition.put("odometerBeginKm", Long.class);
definition.put("odometerEndKm", Long.class);
definition.put("registrationKey", String.class);
definition.put("vehicleKey", String.class);
definition.put("sourceKind", String.class);
definition.put("sourceIntervalIds", java.util.List.class);
return definition;
}
private Map<String, Object> supportGeoEvidenceInputDefinition() {
Map<String, Object> definition = new LinkedHashMap<>();
definition.put("sessionId", UUID.class);
definition.put("driverKey", String.class);
definition.put("eventId", String.class);
definition.put("eventDomain", String.class);
definition.put("occurredAt", OffsetDateTime.class);
definition.put("occurredAtEpochSecond", long.class);
definition.put("registrationKey", String.class);
definition.put("vehicleKey", String.class);
definition.put("latitude", Double.class);
definition.put("longitude", Double.class);
definition.put("odometerKm", Long.class);
definition.put("priority", int.class);
return definition;
}
private Map<String, Object> toActivityIntervalInputMap(
DriverWorkingTimeActivityInterval interval
) {
if (interval == null || interval.startedAt() == null || interval.endedAt() == null) {
return null;
}
Map<String, Object> event = new LinkedHashMap<>();
event.put("sessionId", interval.sessionId());
event.put("driverKey", interval.driverKey());
event.put("intervalId", interval.intervalId());
event.put("activityType", interval.activityType());
event.put("cardSlot", interval.cardSlot());
event.put("cardStatus", interval.cardStatus());
event.put("drivingStatus", interval.drivingStatus());
event.put("registrationKey", interval.registrationKey());
event.put("vehicleKey", interval.vehicleKey());
event.put("sourceKind", interval.sourceKind());
event.put("firstSourceIntervalId", interval.firstSourceIntervalId());
event.put("lastSourceIntervalId", interval.lastSourceIntervalId());
event.put("startedAt", interval.startedAt());
event.put("endedAt", interval.endedAt());
event.put("startedAtEpochSecond", interval.startedAtEpochSecond());
event.put("endedAtEpochSecond", interval.endedAtEpochSecond());
event.put("durationSeconds", interval.durationSeconds());
event.put("sourceIntervalIds", interval.sourceIntervalIds());
event.put("synthetic", interval.synthetic());
event.put("clippedToRequestedPeriod", interval.clippedToRequestedPeriod());
event.put("level", interval.level());
return event;
}
private Map<String, Object> toVehicleUsageIntervalInputMap(DriverWorkingTimeVehicleUsageInterval interval) {
if (interval == null || interval.startedAt() == null) {
return null;
}
Map<String, Object> event = new LinkedHashMap<>();
event.put("sessionId", interval.sessionId());
event.put("driverKey", interval.driverKey());
event.put("intervalId", interval.intervalId());
event.put("firstSourceIntervalId", interval.firstSourceIntervalId());
event.put("lastSourceIntervalId", interval.lastSourceIntervalId());
event.put("startedAt", interval.startedAt());
event.put("endedAt", interval.endedAt());
event.put("startedAtEpochSecond", interval.startedAtEpochSecond());
event.put("endedAtEpochSecond", interval.endedAtEpochSecond());
event.put("durationSeconds", interval.durationSeconds());
event.put("odometerBeginKm", interval.odometerBeginKm());
event.put("odometerEndKm", interval.odometerEndKm());
event.put("registrationKey", interval.registrationKey());
event.put("vehicleKey", interval.vehicleKey());
event.put("sourceKind", interval.sourceKind());
event.put("sourceIntervalIds", interval.sourceIntervalIds());
return event;
}
private Map<String, Object> toSupportGeoEvidenceInputMap(
UUID sessionId,
RuntimeSupportEvidenceEvent supportEvent
) {
if (supportEvent == null
|| supportEvent.driverKey() == null
|| supportEvent.occurredAt() == null
|| supportEvent.latitude() == null
|| supportEvent.longitude() == null) {
return null;
}
int priority = supportGeoPriority(supportEvent.eventDomain());
if (priority <= 0) {
return null;
}
Map<String, Object> event = new LinkedHashMap<>();
event.put("sessionId", sessionId == null ? new UUID(0L, 0L) : sessionId);
event.put("driverKey", supportEvent.driverKey());
event.put("eventId", supportEvent.eventId());
event.put("eventDomain", supportEvent.eventDomain());
event.put("occurredAt", supportEvent.occurredAt());
event.put("occurredAtEpochSecond", supportEvent.occurredAt().toEpochSecond());
event.put("registrationKey", supportEvent.registrationKey());
event.put("vehicleKey", supportEvent.vehicleKey());
event.put("latitude", supportEvent.latitude().doubleValue());
event.put("longitude", supportEvent.longitude().doubleValue());
event.put("odometerKm", supportEvent.odometerKm());
event.put("priority", priority);
return event;
}
private int supportGeoPriority(String eventDomain) {
if (eventDomain == null || eventDomain.isBlank()) {
return 0;
}
return switch (eventDomain.trim().toUpperCase()) {
case "POSITION" -> 500;
case "PLACE" -> 400;
case "BORDER_CROSSING" -> 300;
case "LOAD_UNLOAD" -> 250;
default -> 0;
};
}
private void collectDrivingInterruptionIntervalModels(
EventBean[] newData,
List<DriverWorkingTimeDrivingInterruptionInterval> target
) {
if (newData == null) {
return;
}
for (EventBean event : newData) {
long startedAtEpochSecond = (Long) event.get("startedAtEpochSecond");
long endedAtEpochSecond = (Long) event.get("endedAtEpochSecond");
target.add(new DriverWorkingTimeDrivingInterruptionInterval(
(UUID) event.get("sessionId"),
(String) event.get("driverKey"),
OffsetDateTime.ofInstant(Instant.ofEpochSecond(startedAtEpochSecond), ZoneOffset.UTC),
OffsetDateTime.ofInstant(Instant.ofEpochSecond(endedAtEpochSecond), ZoneOffset.UTC),
(Long) event.get("durationSeconds"),
(String) event.get("previousDrivingSourceIntervalId"),
(String) event.get("nextDrivingSourceIntervalId"),
(String) event.get("previousRegistrationKey"),
(String) event.get("nextRegistrationKey"),
(String) event.get("previousVehicleKey"),
(String) event.get("nextVehicleKey")
));
}
}
private void collectVuCardAbsentIntervalModels(
EventBean[] newData,
List<DriverWorkingTimeVuCardAbsentInterval> target
) {
if (newData == null) {
return;
}
for (EventBean event : newData) {
long startedAtEpochSecond = (Long) event.get("startedAtEpochSecond");
long endedAtEpochSecond = (Long) event.get("endedAtEpochSecond");
target.add(new DriverWorkingTimeVuCardAbsentInterval(
(UUID) event.get("sessionId"),
(String) event.get("driverKey"),
OffsetDateTime.ofInstant(Instant.ofEpochSecond(startedAtEpochSecond), ZoneOffset.UTC),
OffsetDateTime.ofInstant(Instant.ofEpochSecond(endedAtEpochSecond), ZoneOffset.UTC),
(Long) event.get("durationSeconds"),
(String) event.get("previousUsageIntervalId"),
(String) event.get("nextUsageIntervalId"),
(String) event.get("previousRegistrationKey"),
(String) event.get("nextRegistrationKey"),
(String) event.get("previousVehicleKey"),
(String) event.get("nextVehicleKey")
));
}
}
private void collectDailyWeeklyRestCandidateCoverageIntervalModels(
EventBean[] newData,
List<DriverWorkingTimeRestCoverageInterval> target
) {
collectRestCoverageModels(newData, target);
}
private void collectPotentialHomeOvernightStayIntervalModels(
EventBean[] newData,
List<DriverWorkingTimeRestCoverageInterval> target
) {
collectRestCoverageModels(newData, target);
}
private void collectPotentialInVehicleOvernightStayIntervalModels(
EventBean[] newData,
List<DriverWorkingTimeRestCoverageInterval> target
) {
collectRestCoverageModels(newData, target);
}
private void collectRestCoverageModels(
EventBean[] newData,
List<DriverWorkingTimeRestCoverageInterval> target
) {
if (newData == null) {
return;
}
for (EventBean event : newData) {
long startedAtEpochSecond = (Long) event.get("startedAtEpochSecond");
long endedAtEpochSecond = (Long) event.get("endedAtEpochSecond");
DriverWorkingTimeGeoEvidenceEvent beginGeoEvent = geoEvidenceModel(
(String) event.get("beginGeoEventId"),
(String) event.get("beginGeoEventDomain"),
offsetDateTime(event.get("beginGeoOccurredAtEpochSecond")),
(Double) event.get("beginLatitude"),
(Double) event.get("beginLongitude"),
longOrNull(event.get("beginGeoDistanceSeconds")),
longOrNull(event.get("beginGeoOdometerKm"))
);
DriverWorkingTimeGeoEvidenceEvent endGeoEvent = geoEvidenceModel(
(String) event.get("endGeoEventId"),
(String) event.get("endGeoEventDomain"),
offsetDateTime(event.get("endGeoOccurredAtEpochSecond")),
(Double) event.get("endLatitude"),
(Double) event.get("endLongitude"),
longOrNull(event.get("endGeoDistanceSeconds")),
longOrNull(event.get("endGeoOdometerKm"))
);
target.add(new DriverWorkingTimeRestCoverageInterval(
(UUID) event.get("sessionId"),
(String) event.get("driverKey"),
OffsetDateTime.ofInstant(Instant.ofEpochSecond(startedAtEpochSecond), ZoneOffset.UTC),
OffsetDateTime.ofInstant(Instant.ofEpochSecond(endedAtEpochSecond), ZoneOffset.UTC),
(Long) event.get("durationSeconds"),
(Long) event.get("cardAbsentDurationSeconds"),
(Double) event.get("cardAbsentCoveragePercent"),
(String) event.get("previousDrivingSourceIntervalId"),
(String) event.get("nextDrivingSourceIntervalId"),
(String) event.get("previousRegistrationKey"),
(String) event.get("nextRegistrationKey"),
(String) event.get("previousVehicleKey"),
(String) event.get("nextVehicleKey"),
longOrNull(event.get("beginBoundaryOdometerKm")),
longOrNull(event.get("endBoundaryOdometerKm")),
(String) event.get("beginGeoEventId"),
(String) event.get("beginGeoEventDomain"),
offsetDateTime(event.get("beginGeoOccurredAtEpochSecond")),
(Double) event.get("beginLatitude"),
(Double) event.get("beginLongitude"),
longOrNull(event.get("beginGeoDistanceSeconds")),
longOrNull(event.get("beginGeoOdometerKm")),
(String) event.get("endGeoEventId"),
(String) event.get("endGeoEventDomain"),
offsetDateTime(event.get("endGeoOccurredAtEpochSecond")),
(Double) event.get("endLatitude"),
(Double) event.get("endLongitude"),
longOrNull(event.get("endGeoDistanceSeconds")),
longOrNull(event.get("endGeoOdometerKm")),
longOrNull(event.get("geoEvidenceMovementMeters")),
(String) event.get("geoEvidenceMovementCategory"),
beginGeoEvent,
endGeoEvent
));
}
}
private void collectPotentialInVehicleTripIntervalModels(
EventBean[] newData,
List<DriverWorkingTimePotentialInVehicleTripInterval> target
) {
if (newData == null) {
return;
}
for (EventBean event : newData) {
long startedAtEpochSecond = (Long) event.get("startedAtEpochSecond");
long endedAtEpochSecond = (Long) event.get("endedAtEpochSecond");
target.add(new DriverWorkingTimePotentialInVehicleTripInterval(
(UUID) event.get("sessionId"),
(String) event.get("driverKey"),
OffsetDateTime.ofInstant(Instant.ofEpochSecond(startedAtEpochSecond), ZoneOffset.UTC),
OffsetDateTime.ofInstant(Instant.ofEpochSecond(endedAtEpochSecond), ZoneOffset.UTC),
(Long) event.get("durationSeconds"),
(String) event.get("registrationKey"),
(String) event.get("vehicleKey"),
(Integer) event.get("containedPotentialInVehicleOvernightStayIntervalCount"),
(Long) event.get("containedPotentialInVehicleOvernightStayDurationSeconds"),
(Long) event.get("containedCardAbsentDurationSeconds"),
OffsetDateTime.ofInstant(Instant.ofEpochSecond((Long) event.get("firstPotentialInVehicleOvernightStayStartedAtEpochSecond")), ZoneOffset.UTC),
OffsetDateTime.ofInstant(Instant.ofEpochSecond((Long) event.get("lastPotentialInVehicleOvernightStayEndedAtEpochSecond")), ZoneOffset.UTC),
(String) event.get("firstPreviousDrivingSourceIntervalId"),
(String) event.get("lastNextDrivingSourceIntervalId"),
List.of()
));
}
}
private List<DriverWorkingTimeDrivingInterruptionInterval> sortDrivingInterruptionIntervalsCommon(
List<DriverWorkingTimeDrivingInterruptionInterval> intervals
) {
return intervals.stream()
.sorted(Comparator.comparing(DriverWorkingTimeDrivingInterruptionInterval::startedAt)
.thenComparing(DriverWorkingTimeDrivingInterruptionInterval::endedAt))
.toList();
}
private List<DriverWorkingTimeVuCardAbsentInterval> sortVuCardAbsentIntervalsCommon(
List<DriverWorkingTimeVuCardAbsentInterval> intervals
) {
return intervals.stream()
.sorted(Comparator.comparing(DriverWorkingTimeVuCardAbsentInterval::startedAt)
.thenComparing(DriverWorkingTimeVuCardAbsentInterval::endedAt))
.toList();
}
private List<DriverWorkingTimeRestCoverageInterval> sortDailyWeeklyRestCandidateCoverageIntervalsCommon(
List<DriverWorkingTimeRestCoverageInterval> intervals
) {
return deduplicateRestCoverageIntervalsCommon(intervals).stream()
.sorted(Comparator.comparing(DriverWorkingTimeRestCoverageInterval::startedAt)
.thenComparing(DriverWorkingTimeRestCoverageInterval::endedAt))
.toList();
}
private List<DriverWorkingTimeRestCoverageInterval> sortPotentialHomeOvernightStayIntervalsCommon(
List<DriverWorkingTimeRestCoverageInterval> intervals
) {
return deduplicateRestCoverageIntervalsCommon(intervals).stream()
.sorted(Comparator.comparing(DriverWorkingTimeRestCoverageInterval::startedAt)
.thenComparing(DriverWorkingTimeRestCoverageInterval::endedAt))
.toList();
}
private List<DriverWorkingTimeRestCoverageInterval> sortPotentialInVehicleOvernightStayIntervalsCommon(
List<DriverWorkingTimeRestCoverageInterval> intervals
) {
return deduplicateRestCoverageIntervalsCommon(intervals).stream()
.sorted(Comparator.comparing(DriverWorkingTimeRestCoverageInterval::startedAt)
.thenComparing(DriverWorkingTimeRestCoverageInterval::endedAt))
.toList();
}
private List<DriverWorkingTimePotentialInVehicleTripInterval> sortPotentialInVehicleTripIntervalsCommon(
List<DriverWorkingTimePotentialInVehicleTripInterval> intervals
) {
return intervals.stream()
.sorted(Comparator.comparing(DriverWorkingTimePotentialInVehicleTripInterval::startedAt)
.thenComparing(DriverWorkingTimePotentialInVehicleTripInterval::endedAt))
.toList();
}
private List<DriverWorkingTimeRestCoverageInterval> deduplicateRestCoverageIntervalsCommon(
List<DriverWorkingTimeRestCoverageInterval> intervals
) {
Map<String, DriverWorkingTimeRestCoverageInterval> deduplicated = new LinkedHashMap<>();
for (DriverWorkingTimeRestCoverageInterval interval : intervals) {
deduplicated.put(restCoverageIntervalKey(
interval.driverKey(),
interval.startedAt(),
interval.endedAt(),
interval.previousDrivingSourceIntervalId(),
interval.nextDrivingSourceIntervalId()
), interval);
}
return new ArrayList<>(deduplicated.values());
}
private String restCoverageIntervalKey(
String driverKey,
OffsetDateTime startedAt,
OffsetDateTime endedAt,
String previousDrivingSourceIntervalId,
String nextDrivingSourceIntervalId
) {
return String.join("|",
driverKey == null ? "" : driverKey,
startedAt == null ? "" : startedAt.toString(),
endedAt == null ? "" : endedAt.toString(),
previousDrivingSourceIntervalId == null ? "" : previousDrivingSourceIntervalId,
nextDrivingSourceIntervalId == null ? "" : nextDrivingSourceIntervalId
);
}
private DriverWorkingTimeGeoEvidenceEvent geoEvidenceModel(
String eventId,
String eventDomain,
OffsetDateTime occurredAt,
Double latitude,
Double longitude,
Long distanceSeconds,
Long odometerKm
) {
if (eventId == null
&& eventDomain == null
&& occurredAt == null
&& latitude == null
&& longitude == null
&& distanceSeconds == null
&& odometerKm == null) {
return null;
}
return new DriverWorkingTimeGeoEvidenceEvent(
eventId,
eventDomain,
occurredAt,
latitude,
longitude,
distanceSeconds,
odometerKm
);
}
private String renderDrivingDerivedProjectionBundleEpl(int significantDrivingMinutes, int minimumRestPeriodMinutes) {
return DRIVING_DERIVED_PROJECTION_BUNDLE_EPL_TEMPLATE
.replace(
"${SIGNIFICANT_DRIVING_THRESHOLD_SECONDS}",
Long.toString(Math.max(1, significantDrivingMinutes) * 60L)
)
.replace(
"${MINIMUM_REST_PERIOD_THRESHOLD_SECONDS}",
Long.toString(Math.max(1, minimumRestPeriodMinutes) * 60L)
)
.replace(
"${REST_GEO_LOOKBACK_SECONDS}",
Long.toString(Math.max(1, properties.getTachographFileSession().getProcessing().getRestCandidateGeoLookbackMinutes()) * 60L)
)
.replace(
"${REST_GEO_LOOKAHEAD_SECONDS}",
Long.toString(Math.max(1, properties.getTachographFileSession().getProcessing().getRestCandidateGeoLookaheadMinutes()) * 60L)
)
.replace(
"${REST_GEO_STATIONARY_MAX_METERS}",
Integer.toString(Math.max(0, properties.getTachographFileSession().getProcessing().getRestCandidateGeoStationaryMaxMeters()))
)
.replace(
"${REST_GEO_MINOR_MOVEMENT_MAX_METERS}",
Integer.toString(Math.max(
properties.getTachographFileSession().getProcessing().getRestCandidateGeoStationaryMaxMeters(),
properties.getTachographFileSession().getProcessing().getRestCandidateGeoMinorMovementMaxMeters()
))
);
}
private OffsetDateTime offsetDateTime(Object epochSecond) {
if (!(epochSecond instanceof Long value)) {
return null;
}
return OffsetDateTime.ofInstant(Instant.ofEpochSecond(value), ZoneOffset.UTC);
}
private Long longOrNull(Object value) {
return value instanceof Long number ? number : null;
}
private static String loadResource(String path) {
try {
ClassPathResource resource = new ClassPathResource(path);
return StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
} catch (IOException e) {
throw new IllegalStateException("Cannot load EPL resource: " + path, e);
}
}
}

View File

@ -10,6 +10,7 @@ import at.procon.eventhub.processing.eventprocessing.partition.RuntimeEventScope
import at.procon.eventhub.processing.model.RuntimeDriverVehicleEvidenceAttachmentResult; import at.procon.eventhub.processing.model.RuntimeDriverVehicleEvidenceAttachmentResult;
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 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;
@ -67,7 +68,7 @@ public class RuntimeDriverVehicleEvidenceAttachmentService {
); );
List<DriverWorkingTimeVehicleUsageInterval> vehicleUsageIntervals = mergeVehicleUsageIntervals(timeline.vehicleUsageIntervals()) List<DriverWorkingTimeVehicleUsageInterval> vehicleUsageIntervals = mergeVehicleUsageIntervals(timeline.vehicleUsageIntervals())
.stream() .stream()
.map(DriverWorkingTimeVehicleUsageInterval::fromResolved) .map(TachographDriverWorkingTimeAdapter::toVehicleUsageInterval)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.toList(); .toList();
return attachVehicleEvidence( return attachVehicleEvidence(

View File

@ -10,12 +10,15 @@ import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeAc
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeProcessingInput; import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeProcessingInput;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeVehicleUsageInterval; import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeVehicleUsageInterval;
import at.procon.eventhub.processing.driverworkingtime.service.DriverWorkingTimeDerivedProjectionEngine; import at.procon.eventhub.processing.driverworkingtime.service.DriverWorkingTimeDerivedProjectionEngine;
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.RuntimeSupportEvidenceNormalizationResult;
import at.procon.eventhub.processing.eventprocessing.support.RuntimeSupportEvidenceEvent; 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.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.tachographfilesession.service.TachographDriverWorkingTimeAdapter;
import at.procon.eventhub.tachographfilesession.model.ExtractedSupportEvent; import at.procon.eventhub.tachographfilesession.model.ExtractedSupportEvent;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline; import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent; import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
@ -28,9 +31,6 @@ 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.tachographfilesession.service.DriverTimelineBuilder;
import at.procon.eventhub.tachographfilesession.service.DriverTimelineReusableProjectionBuilder;
import at.procon.eventhub.processing.driverworkingtime.service.DriverWorkingTimeProcessingCore;
import java.time.Duration; import java.time.Duration;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.time.ZoneOffset; import java.time.ZoneOffset;
@ -47,8 +47,6 @@ public class UnifiedRuntimeDerivedProjectionService {
private final UnifiedRuntimeEventAssemblyService runtimeEventAssemblyService; private final UnifiedRuntimeEventAssemblyService runtimeEventAssemblyService;
private final UnifiedEventTimelineReconstructor timelineReconstructor; private final UnifiedEventTimelineReconstructor timelineReconstructor;
private final DriverTimelineBuilder driverTimelineBuilder;
private final DriverTimelineReusableProjectionBuilder reusableProjectionBuilder;
private final DriverWorkingTimeProcessingCore workingTimeProcessingCore; private final DriverWorkingTimeProcessingCore workingTimeProcessingCore;
private final RuntimeSupportEvidenceNormalizer supportEvidenceNormalizer; private final RuntimeSupportEvidenceNormalizer supportEvidenceNormalizer;
private final EventHubProperties properties; private final EventHubProperties properties;
@ -56,18 +54,17 @@ public class UnifiedRuntimeDerivedProjectionService {
public UnifiedRuntimeDerivedProjectionService( public UnifiedRuntimeDerivedProjectionService(
UnifiedRuntimeEventAssemblyService runtimeEventAssemblyService, UnifiedRuntimeEventAssemblyService runtimeEventAssemblyService,
UnifiedEventTimelineReconstructor timelineReconstructor, UnifiedEventTimelineReconstructor timelineReconstructor,
DriverTimelineBuilder driverTimelineBuilder,
DriverTimelineReusableProjectionBuilder reusableProjectionBuilder,
EventHubProperties properties, EventHubProperties properties,
DriverWorkingTimeReusableProjectionBuilder reusableProjectionBuilder,
RuntimeSupportEvidenceNormalizer supportEvidenceNormalizer RuntimeSupportEvidenceNormalizer supportEvidenceNormalizer
) { ) {
this( this(
runtimeEventAssemblyService, runtimeEventAssemblyService,
timelineReconstructor, timelineReconstructor,
driverTimelineBuilder,
reusableProjectionBuilder,
properties, properties,
new DriverWorkingTimeProcessingCore(new DriverWorkingTimeDerivedProjectionEngine(reusableProjectionBuilder)), new DriverWorkingTimeProcessingCore(new DriverWorkingTimeDerivedProjectionEngine(
reusableProjectionBuilder
)),
supportEvidenceNormalizer supportEvidenceNormalizer
); );
} }
@ -76,16 +73,12 @@ public class UnifiedRuntimeDerivedProjectionService {
public UnifiedRuntimeDerivedProjectionService( public UnifiedRuntimeDerivedProjectionService(
UnifiedRuntimeEventAssemblyService runtimeEventAssemblyService, UnifiedRuntimeEventAssemblyService runtimeEventAssemblyService,
UnifiedEventTimelineReconstructor timelineReconstructor, UnifiedEventTimelineReconstructor timelineReconstructor,
DriverTimelineBuilder driverTimelineBuilder,
DriverTimelineReusableProjectionBuilder reusableProjectionBuilder,
EventHubProperties properties, EventHubProperties properties,
DriverWorkingTimeProcessingCore workingTimeProcessingCore, DriverWorkingTimeProcessingCore workingTimeProcessingCore,
RuntimeSupportEvidenceNormalizer supportEvidenceNormalizer RuntimeSupportEvidenceNormalizer supportEvidenceNormalizer
) { ) {
this.runtimeEventAssemblyService = runtimeEventAssemblyService; this.runtimeEventAssemblyService = runtimeEventAssemblyService;
this.timelineReconstructor = timelineReconstructor; this.timelineReconstructor = timelineReconstructor;
this.driverTimelineBuilder = driverTimelineBuilder;
this.reusableProjectionBuilder = reusableProjectionBuilder;
this.properties = properties; this.properties = properties;
this.workingTimeProcessingCore = workingTimeProcessingCore; this.workingTimeProcessingCore = workingTimeProcessingCore;
this.supportEvidenceNormalizer = supportEvidenceNormalizer; this.supportEvidenceNormalizer = supportEvidenceNormalizer;
@ -156,11 +149,15 @@ public class UnifiedRuntimeDerivedProjectionService {
significantDrivingMinutes, significantDrivingMinutes,
minimumRestPeriodMinutes, minimumRestPeriodMinutes,
timeline.activityIntervals().stream() timeline.activityIntervals().stream()
.map(interval -> DriverWorkingTimeActivityInterval.fromResolved(runtimeSessionId(request), driverKey, interval)) .map(interval -> TachographDriverWorkingTimeAdapter.toActivityInterval(
runtimeSessionId(request),
driverKey,
interval
))
.filter(Objects::nonNull) .filter(Objects::nonNull)
.toList(), .toList(),
timeline.vehicleUsageIntervals().stream() timeline.vehicleUsageIntervals().stream()
.map(DriverWorkingTimeVehicleUsageInterval::fromResolved) .map(TachographDriverWorkingTimeAdapter::toVehicleUsageInterval)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.toList(), .toList(),
timeline.supportEvents().stream() timeline.supportEvents().stream()

View File

@ -1,9 +1,18 @@
package at.procon.eventhub.tachographfilesession.dto; package at.procon.eventhub.tachographfilesession.dto;
import at.procon.eventhub.processing.driverworkingtime.dto.DriverWorkingTimeProcessingResultDto; import at.procon.eventhub.processing.driverworkingtime.dto.DriverWorkingTimeProcessingResultDto;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeActivityInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeDrivingInterruptionInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeGeoEvidenceEvent;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimePotentialInVehicleTripInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeRestCoverageInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeSupportGeoEvent;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeVehicleUsageInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeVuCardAbsentInterval;
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.TachographEsperDrivingInterruptionIntervalEvent; import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperGeoEvidenceEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent; import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleOvernightStayIntervalEvent; import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleOvernightStayIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleTripIntervalEvent; import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleTripIntervalEvent;
@ -78,19 +87,19 @@ public record TachographEsperDriverProcessingResultDto(
result.vehicleUsageIntervalCount(), result.vehicleUsageIntervalCount(),
result.vuCardAbsentIntervalCount(), result.vuCardAbsentIntervalCount(),
result.supportGeoEventCount(), result.supportGeoEventCount(),
result.activityIntervals(), mapActivityIntervalsToLegacy(result.activityIntervals()),
result.drivingIntervals(), mapActivityIntervalsToLegacy(result.drivingIntervals()),
result.drivingInterruptionIntervals(), mapDrivingInterruptionsToLegacy(result.drivingInterruptionIntervals()),
result.drivingInterruptionVehicleChangeIntervals(), mapDrivingInterruptionsToLegacy(result.drivingInterruptionVehicleChangeIntervals()),
result.dailyWeeklyRestCandidateIntervals(), mapDrivingInterruptionsToLegacy(result.dailyWeeklyRestCandidateIntervals()),
result.dailyWeeklyRestCandidateCoverageIntervals(), mapCoverageIntervalsToLegacy(result.dailyWeeklyRestCandidateCoverageIntervals()),
result.unclassifiedDailyWeeklyRestCandidateCoverageIntervals(), mapCoverageIntervalsToLegacy(result.unclassifiedDailyWeeklyRestCandidateCoverageIntervals()),
result.potentialHomeOvernightStayIntervals(), mapPotentialHomeIntervalsToLegacy(result.potentialHomeOvernightStayIntervals()),
result.potentialInVehicleOvernightStayIntervals(), mapPotentialInVehicleIntervalsToLegacy(result.potentialInVehicleOvernightStayIntervals()),
result.potentialInVehicleTripIntervals(), mapPotentialTripsToLegacy(result.potentialInVehicleTripIntervals()),
result.vehicleUsageIntervals(), mapVehicleUsageIntervalsToLegacy(result.vehicleUsageIntervals()),
result.vuCardAbsentIntervals(), mapVuCardAbsentIntervalsToLegacy(result.vuCardAbsentIntervals()),
result.supportGeoEvents(), mapSupportGeoEventsToLegacy(result.supportGeoEvents()),
result.notes() result.notes()
); );
} }
@ -117,20 +126,689 @@ public record TachographEsperDriverProcessingResultDto(
vehicleUsageIntervalCount, vehicleUsageIntervalCount,
vuCardAbsentIntervalCount, vuCardAbsentIntervalCount,
supportGeoEventCount, supportGeoEventCount,
activityIntervals, mapActivityIntervalsFromLegacy(activityIntervals),
drivingIntervals, mapActivityIntervalsFromLegacy(drivingIntervals),
drivingInterruptionIntervals, mapDrivingInterruptionsFromLegacy(drivingInterruptionIntervals),
drivingInterruptionVehicleChangeIntervals, mapDrivingInterruptionsFromLegacy(drivingInterruptionVehicleChangeIntervals),
dailyWeeklyRestCandidateIntervals, mapDrivingInterruptionsFromLegacy(dailyWeeklyRestCandidateIntervals),
dailyWeeklyRestCandidateCoverageIntervals, mapCoverageIntervalsFromLegacy(dailyWeeklyRestCandidateCoverageIntervals),
unclassifiedDailyWeeklyRestCandidateCoverageIntervals, mapCoverageIntervalsFromLegacy(unclassifiedDailyWeeklyRestCandidateCoverageIntervals),
potentialHomeOvernightStayIntervals, mapPotentialHomeIntervalsFromLegacy(potentialHomeOvernightStayIntervals),
potentialInVehicleOvernightStayIntervals, mapPotentialInVehicleIntervalsFromLegacy(potentialInVehicleOvernightStayIntervals),
potentialInVehicleTripIntervals, mapPotentialTripsFromLegacy(potentialInVehicleTripIntervals),
vehicleUsageIntervals, mapVehicleUsageIntervalsFromLegacy(vehicleUsageIntervals),
vuCardAbsentIntervals, mapVuCardAbsentIntervalsFromLegacy(vuCardAbsentIntervals),
supportGeoEvents, mapSupportGeoEventsFromLegacy(supportGeoEvents),
notes notes
); );
} }
private static List<TachographEsperActivityIntervalEvent> mapActivityIntervalsToLegacy(
List<DriverWorkingTimeActivityInterval> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toLegacy).toList();
}
private static List<DriverWorkingTimeActivityInterval> mapActivityIntervalsFromLegacy(
List<TachographEsperActivityIntervalEvent> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toCommon).toList();
}
private static List<TachographEsperDrivingInterruptionIntervalEvent> mapDrivingInterruptionsToLegacy(
List<DriverWorkingTimeDrivingInterruptionInterval> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toLegacy).toList();
}
private static List<DriverWorkingTimeDrivingInterruptionInterval> mapDrivingInterruptionsFromLegacy(
List<TachographEsperDrivingInterruptionIntervalEvent> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toCommon).toList();
}
private static List<TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent> mapCoverageIntervalsToLegacy(
List<DriverWorkingTimeRestCoverageInterval> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toLegacyCoverage).toList();
}
private static List<DriverWorkingTimeRestCoverageInterval> mapCoverageIntervalsFromLegacy(
List<TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toCommon).toList();
}
private static List<TachographEsperPotentialHomeOvernightStayIntervalEvent> mapPotentialHomeIntervalsToLegacy(
List<DriverWorkingTimeRestCoverageInterval> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toLegacyPotentialHome).toList();
}
private static List<DriverWorkingTimeRestCoverageInterval> mapPotentialHomeIntervalsFromLegacy(
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toCommon).toList();
}
private static List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> mapPotentialInVehicleIntervalsToLegacy(
List<DriverWorkingTimeRestCoverageInterval> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toLegacyPotentialInVehicle).toList();
}
private static List<DriverWorkingTimeRestCoverageInterval> mapPotentialInVehicleIntervalsFromLegacy(
List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toCommon).toList();
}
private static List<TachographEsperPotentialInVehicleTripIntervalEvent> mapPotentialTripsToLegacy(
List<DriverWorkingTimePotentialInVehicleTripInterval> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toLegacy).toList();
}
private static List<DriverWorkingTimePotentialInVehicleTripInterval> mapPotentialTripsFromLegacy(
List<TachographEsperPotentialInVehicleTripIntervalEvent> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toCommon).toList();
}
private static List<TachographEsperVehicleUsageIntervalEvent> mapVehicleUsageIntervalsToLegacy(
List<DriverWorkingTimeVehicleUsageInterval> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toLegacy).toList();
}
private static List<DriverWorkingTimeVehicleUsageInterval> mapVehicleUsageIntervalsFromLegacy(
List<TachographEsperVehicleUsageIntervalEvent> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toCommon).toList();
}
private static List<TachographEsperVuCardAbsentIntervalEvent> mapVuCardAbsentIntervalsToLegacy(
List<DriverWorkingTimeVuCardAbsentInterval> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toLegacy).toList();
}
private static List<DriverWorkingTimeVuCardAbsentInterval> mapVuCardAbsentIntervalsFromLegacy(
List<TachographEsperVuCardAbsentIntervalEvent> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toCommon).toList();
}
private static List<TachographEsperSupportGeoEvent> mapSupportGeoEventsToLegacy(
List<DriverWorkingTimeSupportGeoEvent> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toLegacy).toList();
}
private static List<DriverWorkingTimeSupportGeoEvent> mapSupportGeoEventsFromLegacy(
List<TachographEsperSupportGeoEvent> values
) {
return safe(values).stream().map(TachographEsperDriverProcessingResultDto::toCommon).toList();
}
private static DriverWorkingTimeActivityInterval toCommon(TachographEsperActivityIntervalEvent value) {
if (value == null) {
return null;
}
return new DriverWorkingTimeActivityInterval(
value.sessionId(),
value.driverKey(),
value.intervalId(),
value.activityType(),
value.cardSlot(),
value.cardStatus(),
value.drivingStatus(),
value.registrationKey(),
value.vehicleKey(),
value.sourceKind(),
firstSourceIntervalId(value.intervalId(), value.sourceIntervalIds()),
lastSourceIntervalId(value.intervalId(), value.sourceIntervalIds()),
value.startedAt(),
value.endedAt(),
epochSecond(value.startedAt()),
epochSecond(value.endedAt()),
value.durationSeconds(),
value.sourceIntervalIds(),
value.synthetic(),
value.clippedToRequestedPeriod(),
value.level()
);
}
private static TachographEsperActivityIntervalEvent toLegacy(DriverWorkingTimeActivityInterval value) {
return new TachographEsperActivityIntervalEvent(
value.sessionId(),
value.driverKey(),
value.intervalId(),
value.activityType(),
value.cardSlot(),
value.cardStatus(),
value.drivingStatus(),
value.registrationKey(),
value.vehicleKey(),
value.sourceKind(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.sourceIntervalIds(),
value.synthetic(),
value.clippedToRequestedPeriod(),
value.level()
);
}
private static DriverWorkingTimeDrivingInterruptionInterval toCommon(
TachographEsperDrivingInterruptionIntervalEvent value
) {
if (value == null) {
return null;
}
return new DriverWorkingTimeDrivingInterruptionInterval(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.previousDrivingSourceIntervalId(),
value.nextDrivingSourceIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey()
);
}
private static TachographEsperDrivingInterruptionIntervalEvent toLegacy(
DriverWorkingTimeDrivingInterruptionInterval value
) {
return new TachographEsperDrivingInterruptionIntervalEvent(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.previousDrivingSourceIntervalId(),
value.nextDrivingSourceIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey()
);
}
private static DriverWorkingTimeRestCoverageInterval toCommon(
TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent value
) {
if (value == null) {
return null;
}
return new DriverWorkingTimeRestCoverageInterval(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.cardAbsentDurationSeconds(),
value.cardAbsentCoveragePercent(),
value.previousDrivingSourceIntervalId(),
value.nextDrivingSourceIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey(),
value.beginBoundaryOdometerKm(),
value.endBoundaryOdometerKm(),
value.beginGeoEventId(),
value.beginGeoEventDomain(),
value.beginGeoOccurredAt(),
value.beginLatitude(),
value.beginLongitude(),
value.beginGeoDistanceSeconds(),
value.beginGeoOdometerKm(),
value.endGeoEventId(),
value.endGeoEventDomain(),
value.endGeoOccurredAt(),
value.endLatitude(),
value.endLongitude(),
value.endGeoDistanceSeconds(),
value.endGeoOdometerKm(),
value.geoEvidenceMovementMeters(),
value.geoEvidenceMovementCategory(),
toCommon(value.beginGeoEvent()),
toCommon(value.endGeoEvent())
);
}
private static DriverWorkingTimeRestCoverageInterval toCommon(
TachographEsperPotentialHomeOvernightStayIntervalEvent value
) {
if (value == null) {
return null;
}
return new DriverWorkingTimeRestCoverageInterval(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.cardAbsentDurationSeconds(),
value.cardAbsentCoveragePercent(),
value.previousDrivingSourceIntervalId(),
value.nextDrivingSourceIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey(),
value.beginBoundaryOdometerKm(),
value.endBoundaryOdometerKm(),
value.beginGeoEventId(),
value.beginGeoEventDomain(),
value.beginGeoOccurredAt(),
value.beginLatitude(),
value.beginLongitude(),
value.beginGeoDistanceSeconds(),
value.beginGeoOdometerKm(),
value.endGeoEventId(),
value.endGeoEventDomain(),
value.endGeoOccurredAt(),
value.endLatitude(),
value.endLongitude(),
value.endGeoDistanceSeconds(),
value.endGeoOdometerKm(),
value.geoEvidenceMovementMeters(),
value.geoEvidenceMovementCategory(),
toCommon(value.beginGeoEvent()),
toCommon(value.endGeoEvent())
);
}
private static DriverWorkingTimeRestCoverageInterval toCommon(
TachographEsperPotentialInVehicleOvernightStayIntervalEvent value
) {
if (value == null) {
return null;
}
return new DriverWorkingTimeRestCoverageInterval(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.cardAbsentDurationSeconds(),
value.cardAbsentCoveragePercent(),
value.previousDrivingSourceIntervalId(),
value.nextDrivingSourceIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey(),
value.beginBoundaryOdometerKm(),
value.endBoundaryOdometerKm(),
value.beginGeoEventId(),
value.beginGeoEventDomain(),
value.beginGeoOccurredAt(),
value.beginLatitude(),
value.beginLongitude(),
value.beginGeoDistanceSeconds(),
value.beginGeoOdometerKm(),
value.endGeoEventId(),
value.endGeoEventDomain(),
value.endGeoOccurredAt(),
value.endLatitude(),
value.endLongitude(),
value.endGeoDistanceSeconds(),
value.endGeoOdometerKm(),
value.geoEvidenceMovementMeters(),
value.geoEvidenceMovementCategory(),
toCommon(value.beginGeoEvent()),
toCommon(value.endGeoEvent())
);
}
private static TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent toLegacyCoverage(
DriverWorkingTimeRestCoverageInterval value
) {
return new TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.cardAbsentDurationSeconds(),
value.cardAbsentCoveragePercent(),
value.previousDrivingSourceIntervalId(),
value.nextDrivingSourceIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey(),
value.beginBoundaryOdometerKm(),
value.endBoundaryOdometerKm(),
value.beginGeoEventId(),
value.beginGeoEventDomain(),
value.beginGeoOccurredAt(),
value.beginLatitude(),
value.beginLongitude(),
value.beginGeoDistanceSeconds(),
value.beginGeoOdometerKm(),
value.endGeoEventId(),
value.endGeoEventDomain(),
value.endGeoOccurredAt(),
value.endLatitude(),
value.endLongitude(),
value.endGeoDistanceSeconds(),
value.endGeoOdometerKm(),
value.geoEvidenceMovementMeters(),
value.geoEvidenceMovementCategory(),
toLegacy(value.beginGeoEvent()),
toLegacy(value.endGeoEvent())
);
}
private static TachographEsperPotentialHomeOvernightStayIntervalEvent toLegacyPotentialHome(
DriverWorkingTimeRestCoverageInterval value
) {
return new TachographEsperPotentialHomeOvernightStayIntervalEvent(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.cardAbsentDurationSeconds(),
value.cardAbsentCoveragePercent(),
value.previousDrivingSourceIntervalId(),
value.nextDrivingSourceIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey(),
value.beginBoundaryOdometerKm(),
value.endBoundaryOdometerKm(),
value.beginGeoEventId(),
value.beginGeoEventDomain(),
value.beginGeoOccurredAt(),
value.beginLatitude(),
value.beginLongitude(),
value.beginGeoDistanceSeconds(),
value.beginGeoOdometerKm(),
value.endGeoEventId(),
value.endGeoEventDomain(),
value.endGeoOccurredAt(),
value.endLatitude(),
value.endLongitude(),
value.endGeoDistanceSeconds(),
value.endGeoOdometerKm(),
value.geoEvidenceMovementMeters(),
value.geoEvidenceMovementCategory(),
toLegacy(value.beginGeoEvent()),
toLegacy(value.endGeoEvent())
);
}
private static TachographEsperPotentialInVehicleOvernightStayIntervalEvent toLegacyPotentialInVehicle(
DriverWorkingTimeRestCoverageInterval value
) {
return new TachographEsperPotentialInVehicleOvernightStayIntervalEvent(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.cardAbsentDurationSeconds(),
value.cardAbsentCoveragePercent(),
value.previousDrivingSourceIntervalId(),
value.nextDrivingSourceIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey(),
value.beginBoundaryOdometerKm(),
value.endBoundaryOdometerKm(),
value.beginGeoEventId(),
value.beginGeoEventDomain(),
value.beginGeoOccurredAt(),
value.beginLatitude(),
value.beginLongitude(),
value.beginGeoDistanceSeconds(),
value.beginGeoOdometerKm(),
value.endGeoEventId(),
value.endGeoEventDomain(),
value.endGeoOccurredAt(),
value.endLatitude(),
value.endLongitude(),
value.endGeoDistanceSeconds(),
value.endGeoOdometerKm(),
value.geoEvidenceMovementMeters(),
value.geoEvidenceMovementCategory(),
toLegacy(value.beginGeoEvent()),
toLegacy(value.endGeoEvent())
);
}
private static DriverWorkingTimePotentialInVehicleTripInterval toCommon(
TachographEsperPotentialInVehicleTripIntervalEvent value
) {
if (value == null) {
return null;
}
return new DriverWorkingTimePotentialInVehicleTripInterval(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.registrationKey(),
value.vehicleKey(),
value.containedPotentialInVehicleOvernightStayIntervalCount(),
value.containedPotentialInVehicleOvernightStayDurationSeconds(),
value.containedCardAbsentDurationSeconds(),
value.firstPotentialInVehicleOvernightStayStartedAt(),
value.lastPotentialInVehicleOvernightStayEndedAt(),
value.firstPreviousDrivingSourceIntervalId(),
value.lastNextDrivingSourceIntervalId(),
safe(value.potentialInVehicleOvernightStayIntervals()).stream()
.map(TachographEsperDriverProcessingResultDto::toCommon)
.toList()
);
}
private static TachographEsperPotentialInVehicleTripIntervalEvent toLegacy(
DriverWorkingTimePotentialInVehicleTripInterval value
) {
return new TachographEsperPotentialInVehicleTripIntervalEvent(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.registrationKey(),
value.vehicleKey(),
value.containedPotentialInVehicleOvernightStayIntervalCount(),
value.containedPotentialInVehicleOvernightStayDurationSeconds(),
value.containedCardAbsentDurationSeconds(),
value.firstPotentialInVehicleOvernightStayStartedAt(),
value.lastPotentialInVehicleOvernightStayEndedAt(),
value.firstPreviousDrivingSourceIntervalId(),
value.lastNextDrivingSourceIntervalId(),
safe(value.potentialInVehicleOvernightStayIntervals()).stream()
.map(TachographEsperDriverProcessingResultDto::toLegacyPotentialInVehicle)
.toList()
);
}
private static DriverWorkingTimeVehicleUsageInterval toCommon(TachographEsperVehicleUsageIntervalEvent value) {
if (value == null) {
return null;
}
return new DriverWorkingTimeVehicleUsageInterval(
value.sessionId(),
value.driverKey(),
value.intervalId(),
firstSourceIntervalId(value.intervalId(), value.sourceIntervalIds()),
lastSourceIntervalId(value.intervalId(), value.sourceIntervalIds()),
value.startedAt(),
value.endedAt(),
epochSecond(value.startedAt()),
value.endedAt() == null ? null : value.endedAt().toEpochSecond(),
value.durationSeconds(),
value.odometerBeginKm(),
value.odometerEndKm(),
value.registrationKey(),
value.vehicleKey(),
value.sourceKind(),
value.sourceIntervalIds()
);
}
private static TachographEsperVehicleUsageIntervalEvent toLegacy(DriverWorkingTimeVehicleUsageInterval value) {
return new TachographEsperVehicleUsageIntervalEvent(
value.sessionId(),
value.driverKey(),
value.intervalId(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.odometerBeginKm(),
value.odometerEndKm(),
value.registrationKey(),
value.vehicleKey(),
value.sourceKind(),
value.sourceIntervalIds()
);
}
private static DriverWorkingTimeVuCardAbsentInterval toCommon(TachographEsperVuCardAbsentIntervalEvent value) {
if (value == null) {
return null;
}
return new DriverWorkingTimeVuCardAbsentInterval(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.previousUsageIntervalId(),
value.nextUsageIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey()
);
}
private static TachographEsperVuCardAbsentIntervalEvent toLegacy(DriverWorkingTimeVuCardAbsentInterval value) {
return new TachographEsperVuCardAbsentIntervalEvent(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.previousUsageIntervalId(),
value.nextUsageIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey()
);
}
private static DriverWorkingTimeSupportGeoEvent toCommon(TachographEsperSupportGeoEvent value) {
if (value == null) {
return null;
}
return new DriverWorkingTimeSupportGeoEvent(
value.eventId(),
value.driverKey(),
value.occurredAt(),
value.eventDomain(),
value.eventType(),
value.eventLifecycle(),
value.registrationKey(),
value.vehicleKey(),
value.country(),
value.region(),
value.countryFrom(),
value.countryTo(),
value.operation(),
value.latitude(),
value.longitude(),
value.odometerKm(),
value.rawRecordPath()
);
}
private static TachographEsperSupportGeoEvent toLegacy(DriverWorkingTimeSupportGeoEvent value) {
return new TachographEsperSupportGeoEvent(
value.eventId(),
value.driverKey(),
value.occurredAt(),
value.eventDomain(),
value.eventType(),
value.eventLifecycle(),
value.registrationKey(),
value.vehicleKey(),
value.country(),
value.region(),
value.countryFrom(),
value.countryTo(),
value.operation(),
value.latitude(),
value.longitude(),
value.odometerKm(),
value.rawRecordPath()
);
}
private static DriverWorkingTimeGeoEvidenceEvent toCommon(TachographEsperGeoEvidenceEvent value) {
if (value == null) {
return null;
}
return new DriverWorkingTimeGeoEvidenceEvent(
value.eventId(),
value.eventDomain(),
value.occurredAt(),
value.latitude(),
value.longitude(),
value.distanceSeconds(),
value.odometerKm()
);
}
private static TachographEsperGeoEvidenceEvent toLegacy(DriverWorkingTimeGeoEvidenceEvent value) {
if (value == null) {
return null;
}
return new TachographEsperGeoEvidenceEvent(
value.eventId(),
value.eventDomain(),
value.occurredAt(),
value.latitude(),
value.longitude(),
value.distanceSeconds(),
value.odometerKm()
);
}
private static String firstSourceIntervalId(String intervalId, List<String> sourceIntervalIds) {
return sourceIntervalIds == null || sourceIntervalIds.isEmpty() ? intervalId : sourceIntervalIds.getFirst();
}
private static String lastSourceIntervalId(String intervalId, List<String> sourceIntervalIds) {
return sourceIntervalIds == null || sourceIntervalIds.isEmpty()
? intervalId
: sourceIntervalIds.getLast();
}
private static long epochSecond(OffsetDateTime value) {
return value == null ? 0L : value.toEpochSecond();
}
private static <T> List<T> safe(List<T> values) {
return values == null ? List.of() : values;
}
} }

View File

@ -0,0 +1,236 @@
package at.procon.eventhub.tachographfilesession.service;
import at.procon.eventhub.config.EventHubProperties;
import at.procon.eventhub.dto.EventHubEventDto;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeDerivedProjectionBundle;
import at.procon.eventhub.processing.driverworkingtime.service.DriverWorkingTimeReusableProjectionBuilder;
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingDerivedProjectionBundle;
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Tachograph-owned compatibility facade that adapts legacy file-session and event-based callers
* onto the neutral driver working-time projection engine.
*/
@Component
public class TachographDerivedProjectionCompatibilityFacade {
private final DriverTimelineBuilder driverTimelineBuilder;
private final RawSourceDriverTimelineEventBuilder rawSourceEventBuilder;
private final TachographEventTimelineReconstructionHelper reconstructionHelper;
private final EventHubProperties properties;
private final DriverWorkingTimeReusableProjectionBuilder commonBuilder;
public TachographDerivedProjectionCompatibilityFacade(
DriverTimelineBuilder driverTimelineBuilder,
EventHubProperties properties
) {
this(
driverTimelineBuilder,
null,
new TachographEventTimelineReconstructionHelper(),
properties,
new DriverWorkingTimeReusableProjectionBuilder(properties)
);
}
public TachographDerivedProjectionCompatibilityFacade(
DriverTimelineBuilder driverTimelineBuilder,
RawSourceDriverTimelineEventBuilder rawSourceEventBuilder,
EventHubProperties properties
) {
this(
driverTimelineBuilder,
rawSourceEventBuilder,
new TachographEventTimelineReconstructionHelper(),
properties,
new DriverWorkingTimeReusableProjectionBuilder(properties)
);
}
@Autowired
public TachographDerivedProjectionCompatibilityFacade(
DriverTimelineBuilder driverTimelineBuilder,
RawSourceDriverTimelineEventBuilder rawSourceEventBuilder,
TachographEventTimelineReconstructionHelper reconstructionHelper,
EventHubProperties properties,
DriverWorkingTimeReusableProjectionBuilder commonBuilder
) {
this.driverTimelineBuilder = driverTimelineBuilder;
this.rawSourceEventBuilder = rawSourceEventBuilder;
this.reconstructionHelper = reconstructionHelper == null
? new TachographEventTimelineReconstructionHelper()
: reconstructionHelper;
this.properties = properties;
this.commonBuilder = commonBuilder;
}
public DriverWorkingTimeReusableProjectionBuilder commonBuilder() {
return commonBuilder;
}
public TachographEsperDrivingDerivedProjectionBundle buildEsperDrivingDerivedProjectionBundle(
TachographFileSession session,
DriverExtractionSession driverSession,
int significantDrivingMinutes,
int minimumRestPeriodMinutes
) {
if (session == null || driverSession == null || driverSession.driverKey() == null) {
return TachographDriverWorkingTimeAdapter.emptyLegacyBundle();
}
if (drivingDerivedProjectionInputMode() == EventHubProperties.DrivingDerivedProjectionInputMode.EVENTS) {
return buildEsperDrivingDerivedProjectionBundleFromEvents(
session.sessionId(),
driverSession.driverKey(),
rawSourceEventBuilder().buildRawEventBundle(session, driverSession).allEvents(),
significantDrivingMinutes,
minimumRestPeriodMinutes
);
}
ResolvedDriverTimeline timeline = driverTimelineBuilder.build(session, driverSession);
return buildEsperDrivingDerivedProjectionBundle(
session.sessionId(),
driverSession.driverKey(),
timeline,
significantDrivingMinutes,
minimumRestPeriodMinutes
);
}
public TachographEsperDrivingDerivedProjectionBundle buildEsperDrivingDerivedProjectionBundle(
TachographFileSession session,
int significantDrivingMinutes,
int minimumRestPeriodMinutes
) {
if (session == null || session.driversByKey() == null || session.driversByKey().isEmpty()) {
return TachographDriverWorkingTimeAdapter.emptyLegacyBundle();
}
List<TachographEsperDrivingDerivedProjectionBundle> bundles = session.driversByKey().values().stream()
.map(driverSession -> buildEsperDrivingDerivedProjectionBundle(
session,
driverSession,
significantDrivingMinutes,
minimumRestPeriodMinutes
))
.toList();
return TachographDriverWorkingTimeAdapter.mergeLegacyBundles(bundles);
}
public TachographEsperDrivingDerivedProjectionBundle buildEsperDrivingDerivedProjectionBundle(
UUID sessionId,
String driverKey,
ResolvedDriverTimeline timeline,
int significantDrivingMinutes,
int minimumRestPeriodMinutes
) {
if (timeline == null || driverKey == null || driverKey.isBlank()) {
return TachographDriverWorkingTimeAdapter.emptyLegacyBundle();
}
DriverWorkingTimeDerivedProjectionBundle bundle = commonBuilder.buildDerivedProjectionBundle(
TachographDriverWorkingTimeAdapter.toProcessingInput(
sessionId == null ? new UUID(0L, 0L) : sessionId,
driverKey,
timeline,
null,
null,
significantDrivingMinutes,
minimumRestPeriodMinutes,
List.of()
)
);
return TachographDriverWorkingTimeAdapter.toLegacyBundle(bundle);
}
public TachographEsperDrivingDerivedProjectionBundle buildEsperDrivingDerivedProjectionBundleFromEvents(
List<EventHubEventDto> events,
int significantDrivingMinutes,
int minimumRestPeriodMinutes
) {
return buildEsperDrivingDerivedProjectionBundleFromEvents(
null,
null,
events,
significantDrivingMinutes,
minimumRestPeriodMinutes
);
}
public TachographEsperDrivingDerivedProjectionBundle buildEsperDrivingDerivedProjectionBundleFromEvents(
UUID fallbackSessionId,
String fallbackDriverKey,
List<EventHubEventDto> events,
int significantDrivingMinutes,
int minimumRestPeriodMinutes
) {
if (fallbackDriverKey == null) {
Map<String, List<EventHubEventDto>> eventsByDriver = reconstructionHelper.groupEventsByDriverKey(events);
if (eventsByDriver.isEmpty()) {
return TachographDriverWorkingTimeAdapter.emptyLegacyBundle();
}
if (eventsByDriver.size() > 1) {
return buildEsperDrivingDerivedProjectionBundleFromGroupedEvents(
fallbackSessionId,
eventsByDriver,
significantDrivingMinutes,
minimumRestPeriodMinutes
);
}
Map.Entry<String, List<EventHubEventDto>> onlyDriver = eventsByDriver.entrySet().iterator().next();
fallbackDriverKey = onlyDriver.getKey();
events = onlyDriver.getValue();
}
ResolvedDriverTimeline timeline = reconstructionHelper.reconstructMergedTimelineFromEvents(
fallbackSessionId,
fallbackDriverKey,
events
);
return buildEsperDrivingDerivedProjectionBundle(
fallbackSessionId == null ? new UUID(0L, 0L) : fallbackSessionId,
fallbackDriverKey,
timeline,
significantDrivingMinutes,
minimumRestPeriodMinutes
);
}
private TachographEsperDrivingDerivedProjectionBundle buildEsperDrivingDerivedProjectionBundleFromGroupedEvents(
UUID fallbackSessionId,
Map<String, List<EventHubEventDto>> eventsByDriver,
int significantDrivingMinutes,
int minimumRestPeriodMinutes
) {
List<TachographEsperDrivingDerivedProjectionBundle> bundles = eventsByDriver.entrySet().stream()
.map(entry -> buildEsperDrivingDerivedProjectionBundleFromEvents(
fallbackSessionId,
entry.getKey(),
entry.getValue(),
significantDrivingMinutes,
minimumRestPeriodMinutes
))
.toList();
return TachographDriverWorkingTimeAdapter.mergeLegacyBundles(bundles);
}
private EventHubProperties.DrivingDerivedProjectionInputMode drivingDerivedProjectionInputMode() {
return properties.getTachographFileSession().getProcessing().getDrivingDerivedProjectionInputMode();
}
private RawSourceDriverTimelineEventBuilder rawSourceEventBuilder() {
if (rawSourceEventBuilder == null) {
throw new IllegalStateException(
"Driving-derived projection input mode EVENTS requires RawSourceDriverTimelineEventBuilder"
);
}
return rawSourceEventBuilder;
}
}

View File

@ -0,0 +1,500 @@
package at.procon.eventhub.tachographfilesession.service;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeActivityInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeDerivedProjectionBundle;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeDrivingInterruptionInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeGeoEvidenceEvent;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimePotentialInVehicleTripInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeProcessingInput;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeRestCoverageInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeVehicleUsageInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeVuCardAbsentInterval;
import at.procon.eventhub.processing.eventprocessing.support.RuntimeSupportEvidenceEvent;
import at.procon.eventhub.tachographfilesession.model.ExtractedSupportEvent;
import at.procon.eventhub.tachographfilesession.model.ResolvedActivityInterval;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval;
import at.procon.eventhub.tachographfilesession.model.TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingDerivedProjectionBundle;
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperGeoEvidenceEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleOvernightStayIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleTripIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;
public final class TachographDriverWorkingTimeAdapter {
private TachographDriverWorkingTimeAdapter() {
}
public static DriverWorkingTimeProcessingInput toProcessingInput(
UUID sessionId,
String driverKey,
ResolvedDriverTimeline timeline,
OffsetDateTime requestedFrom,
OffsetDateTime requestedTo,
int significantDrivingMinutes,
int minimumRestPeriodMinutes,
List<String> notes
) {
return new DriverWorkingTimeProcessingInput(
sessionId,
driverKey,
timeline.sourceKind(),
timeline.loadedFrom(),
timeline.loadedTo(),
requestedFrom,
requestedTo,
significantDrivingMinutes,
minimumRestPeriodMinutes,
safe(timeline.activityIntervals()).stream()
.map(interval -> toActivityInterval(sessionId, driverKey, interval))
.toList(),
safe(timeline.vehicleUsageIntervals()).stream()
.map(TachographDriverWorkingTimeAdapter::toVehicleUsageInterval)
.toList(),
safe(timeline.supportEvents()).stream()
.map(TachographDriverWorkingTimeAdapter::toSupportEvidenceEvent)
.toList(),
notes
);
}
public static DriverWorkingTimeActivityInterval toActivityInterval(
UUID sessionId,
String driverKey,
ResolvedActivityInterval 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(ResolvedVehicleUsageInterval 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(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())
);
}
public static TachographEsperDrivingDerivedProjectionBundle toLegacyBundle(
DriverWorkingTimeDerivedProjectionBundle bundle
) {
if (bundle == null) {
return emptyLegacyBundle();
}
return new TachographEsperDrivingDerivedProjectionBundle(
safe(bundle.drivingInterruptionIntervals()).stream().map(TachographDriverWorkingTimeAdapter::toLegacy).toList(),
safe(bundle.dailyWeeklyRestCandidateIntervals()).stream().map(TachographDriverWorkingTimeAdapter::toLegacy).toList(),
safe(bundle.dailyWeeklyRestCandidateCoverageIntervals()).stream().map(TachographDriverWorkingTimeAdapter::toLegacyCoverage).toList(),
safe(bundle.unclassifiedDailyWeeklyRestCandidateCoverageIntervals()).stream().map(TachographDriverWorkingTimeAdapter::toLegacyCoverage).toList(),
safe(bundle.drivingInterruptionVehicleChangeIntervals()).stream().map(TachographDriverWorkingTimeAdapter::toLegacy).toList(),
safe(bundle.vuCardAbsentIntervals()).stream().map(TachographDriverWorkingTimeAdapter::toLegacy).toList(),
safe(bundle.potentialHomeOvernightStayIntervals()).stream().map(TachographDriverWorkingTimeAdapter::toLegacyPotentialHome).toList(),
safe(bundle.potentialInVehicleOvernightStayIntervals()).stream().map(TachographDriverWorkingTimeAdapter::toLegacyPotentialInVehicle).toList(),
safe(bundle.potentialInVehicleTripIntervals()).stream().map(TachographDriverWorkingTimeAdapter::toLegacy).toList()
);
}
public static TachographEsperDrivingDerivedProjectionBundle mergeLegacyBundles(
List<TachographEsperDrivingDerivedProjectionBundle> bundles
) {
if (bundles == null || bundles.isEmpty()) {
return emptyLegacyBundle();
}
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals = new ArrayList<>();
List<TachographEsperDrivingInterruptionIntervalEvent> dailyWeeklyRestCandidateIntervals = new ArrayList<>();
List<TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent> dailyWeeklyRestCandidateCoverageIntervals = new ArrayList<>();
List<TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent> unclassifiedDailyWeeklyRestCandidateCoverageIntervals = new ArrayList<>();
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionVehicleChangeIntervals = new ArrayList<>();
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals = new ArrayList<>();
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> potentialHomeOvernightStayIntervals = new ArrayList<>();
List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> potentialInVehicleOvernightStayIntervals = new ArrayList<>();
List<TachographEsperPotentialInVehicleTripIntervalEvent> potentialInVehicleTripIntervals = new ArrayList<>();
for (TachographEsperDrivingDerivedProjectionBundle bundle : safe(bundles)) {
if (bundle == null) {
continue;
}
drivingInterruptionIntervals.addAll(safe(bundle.drivingInterruptionIntervals()));
dailyWeeklyRestCandidateIntervals.addAll(safe(bundle.dailyWeeklyRestCandidateIntervals()));
dailyWeeklyRestCandidateCoverageIntervals.addAll(safe(bundle.dailyWeeklyRestCandidateCoverageIntervals()));
unclassifiedDailyWeeklyRestCandidateCoverageIntervals.addAll(safe(bundle.unclassifiedDailyWeeklyRestCandidateCoverageIntervals()));
drivingInterruptionVehicleChangeIntervals.addAll(safe(bundle.drivingInterruptionVehicleChangeIntervals()));
vuCardAbsentIntervals.addAll(safe(bundle.vuCardAbsentIntervals()));
potentialHomeOvernightStayIntervals.addAll(safe(bundle.potentialHomeOvernightStayIntervals()));
potentialInVehicleOvernightStayIntervals.addAll(safe(bundle.potentialInVehicleOvernightStayIntervals()));
potentialInVehicleTripIntervals.addAll(safe(bundle.potentialInVehicleTripIntervals()));
}
return new TachographEsperDrivingDerivedProjectionBundle(
sortDrivingInterruptionIntervals(drivingInterruptionIntervals),
sortDrivingInterruptionIntervals(dailyWeeklyRestCandidateIntervals),
sortCoverageIntervals(dailyWeeklyRestCandidateCoverageIntervals),
sortCoverageIntervals(unclassifiedDailyWeeklyRestCandidateCoverageIntervals),
sortDrivingInterruptionIntervals(drivingInterruptionVehicleChangeIntervals),
sortVuCardAbsentIntervals(vuCardAbsentIntervals),
sortPotentialHomeIntervals(potentialHomeOvernightStayIntervals),
sortPotentialInVehicleIntervals(potentialInVehicleOvernightStayIntervals),
sortPotentialInVehicleTripIntervals(potentialInVehicleTripIntervals)
);
}
public static TachographEsperDrivingDerivedProjectionBundle emptyLegacyBundle() {
return new TachographEsperDrivingDerivedProjectionBundle(
List.of(),
List.of(),
List.of(),
List.of(),
List.of(),
List.of(),
List.of(),
List.of(),
List.of()
);
}
private static TachographEsperDrivingInterruptionIntervalEvent toLegacy(
DriverWorkingTimeDrivingInterruptionInterval value
) {
return new TachographEsperDrivingInterruptionIntervalEvent(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.previousDrivingSourceIntervalId(),
value.nextDrivingSourceIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey()
);
}
private static TachographEsperVuCardAbsentIntervalEvent toLegacy(DriverWorkingTimeVuCardAbsentInterval value) {
return new TachographEsperVuCardAbsentIntervalEvent(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.previousUsageIntervalId(),
value.nextUsageIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey()
);
}
private static TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent toLegacyCoverage(
DriverWorkingTimeRestCoverageInterval value
) {
return new TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.cardAbsentDurationSeconds(),
value.cardAbsentCoveragePercent(),
value.previousDrivingSourceIntervalId(),
value.nextDrivingSourceIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey(),
value.beginBoundaryOdometerKm(),
value.endBoundaryOdometerKm(),
value.beginGeoEventId(),
value.beginGeoEventDomain(),
value.beginGeoOccurredAt(),
value.beginLatitude(),
value.beginLongitude(),
value.beginGeoDistanceSeconds(),
value.beginGeoOdometerKm(),
value.endGeoEventId(),
value.endGeoEventDomain(),
value.endGeoOccurredAt(),
value.endLatitude(),
value.endLongitude(),
value.endGeoDistanceSeconds(),
value.endGeoOdometerKm(),
value.geoEvidenceMovementMeters(),
value.geoEvidenceMovementCategory(),
toLegacy(value.beginGeoEvent()),
toLegacy(value.endGeoEvent())
);
}
private static TachographEsperPotentialHomeOvernightStayIntervalEvent toLegacyPotentialHome(
DriverWorkingTimeRestCoverageInterval value
) {
return new TachographEsperPotentialHomeOvernightStayIntervalEvent(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.cardAbsentDurationSeconds(),
value.cardAbsentCoveragePercent(),
value.previousDrivingSourceIntervalId(),
value.nextDrivingSourceIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey(),
value.beginBoundaryOdometerKm(),
value.endBoundaryOdometerKm(),
value.beginGeoEventId(),
value.beginGeoEventDomain(),
value.beginGeoOccurredAt(),
value.beginLatitude(),
value.beginLongitude(),
value.beginGeoDistanceSeconds(),
value.beginGeoOdometerKm(),
value.endGeoEventId(),
value.endGeoEventDomain(),
value.endGeoOccurredAt(),
value.endLatitude(),
value.endLongitude(),
value.endGeoDistanceSeconds(),
value.endGeoOdometerKm(),
value.geoEvidenceMovementMeters(),
value.geoEvidenceMovementCategory(),
toLegacy(value.beginGeoEvent()),
toLegacy(value.endGeoEvent())
);
}
private static TachographEsperPotentialInVehicleOvernightStayIntervalEvent toLegacyPotentialInVehicle(
DriverWorkingTimeRestCoverageInterval value
) {
return new TachographEsperPotentialInVehicleOvernightStayIntervalEvent(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.cardAbsentDurationSeconds(),
value.cardAbsentCoveragePercent(),
value.previousDrivingSourceIntervalId(),
value.nextDrivingSourceIntervalId(),
value.previousRegistrationKey(),
value.nextRegistrationKey(),
value.previousVehicleKey(),
value.nextVehicleKey(),
value.beginBoundaryOdometerKm(),
value.endBoundaryOdometerKm(),
value.beginGeoEventId(),
value.beginGeoEventDomain(),
value.beginGeoOccurredAt(),
value.beginLatitude(),
value.beginLongitude(),
value.beginGeoDistanceSeconds(),
value.beginGeoOdometerKm(),
value.endGeoEventId(),
value.endGeoEventDomain(),
value.endGeoOccurredAt(),
value.endLatitude(),
value.endLongitude(),
value.endGeoDistanceSeconds(),
value.endGeoOdometerKm(),
value.geoEvidenceMovementMeters(),
value.geoEvidenceMovementCategory(),
toLegacy(value.beginGeoEvent()),
toLegacy(value.endGeoEvent())
);
}
private static TachographEsperPotentialInVehicleTripIntervalEvent toLegacy(
DriverWorkingTimePotentialInVehicleTripInterval value
) {
return new TachographEsperPotentialInVehicleTripIntervalEvent(
value.sessionId(),
value.driverKey(),
value.startedAt(),
value.endedAt(),
value.durationSeconds(),
value.registrationKey(),
value.vehicleKey(),
value.containedPotentialInVehicleOvernightStayIntervalCount(),
value.containedPotentialInVehicleOvernightStayDurationSeconds(),
value.containedCardAbsentDurationSeconds(),
value.firstPotentialInVehicleOvernightStayStartedAt(),
value.lastPotentialInVehicleOvernightStayEndedAt(),
value.firstPreviousDrivingSourceIntervalId(),
value.lastNextDrivingSourceIntervalId(),
safe(value.potentialInVehicleOvernightStayIntervals()).stream()
.map(TachographDriverWorkingTimeAdapter::toLegacyPotentialInVehicle)
.toList()
);
}
private static TachographEsperGeoEvidenceEvent toLegacy(DriverWorkingTimeGeoEvidenceEvent value) {
if (value == null) {
return null;
}
return new TachographEsperGeoEvidenceEvent(
value.eventId(),
value.eventDomain(),
value.occurredAt(),
value.latitude(),
value.longitude(),
value.distanceSeconds(),
value.odometerKm()
);
}
private static List<TachographEsperDrivingInterruptionIntervalEvent> sortDrivingInterruptionIntervals(
List<TachographEsperDrivingInterruptionIntervalEvent> intervals
) {
return safe(intervals).stream()
.sorted(Comparator.comparing(TachographEsperDrivingInterruptionIntervalEvent::startedAt)
.thenComparing(TachographEsperDrivingInterruptionIntervalEvent::endedAt))
.toList();
}
private static List<TachographEsperVuCardAbsentIntervalEvent> sortVuCardAbsentIntervals(
List<TachographEsperVuCardAbsentIntervalEvent> intervals
) {
return safe(intervals).stream()
.sorted(Comparator.comparing(TachographEsperVuCardAbsentIntervalEvent::startedAt)
.thenComparing(TachographEsperVuCardAbsentIntervalEvent::endedAt))
.toList();
}
private static List<TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent> sortCoverageIntervals(
List<TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent> intervals
) {
return safe(intervals).stream()
.sorted(Comparator.comparing(TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent::startedAt)
.thenComparing(TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent::endedAt))
.toList();
}
private static List<TachographEsperPotentialHomeOvernightStayIntervalEvent> sortPotentialHomeIntervals(
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> intervals
) {
return safe(intervals).stream()
.sorted(Comparator.comparing(TachographEsperPotentialHomeOvernightStayIntervalEvent::startedAt)
.thenComparing(TachographEsperPotentialHomeOvernightStayIntervalEvent::endedAt))
.toList();
}
private static List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> sortPotentialInVehicleIntervals(
List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> intervals
) {
return safe(intervals).stream()
.sorted(Comparator.comparing(TachographEsperPotentialInVehicleOvernightStayIntervalEvent::startedAt)
.thenComparing(TachographEsperPotentialInVehicleOvernightStayIntervalEvent::endedAt))
.toList();
}
private static List<TachographEsperPotentialInVehicleTripIntervalEvent> sortPotentialInVehicleTripIntervals(
List<TachographEsperPotentialInVehicleTripIntervalEvent> intervals
) {
return safe(intervals).stream()
.sorted(Comparator.comparing(TachographEsperPotentialInVehicleTripIntervalEvent::startedAt)
.thenComparing(TachographEsperPotentialInVehicleTripIntervalEvent::endedAt))
.toList();
}
private static String firstSourceIntervalId(ResolvedActivityInterval interval) {
return interval.sourceIntervalIds().isEmpty() ? interval.intervalId() : interval.sourceIntervalIds().getFirst();
}
private static String lastSourceIntervalId(ResolvedActivityInterval interval) {
return interval.sourceIntervalIds().isEmpty() ? interval.intervalId() : interval.sourceIntervalIds().getLast();
}
private static String firstSourceIntervalId(ResolvedVehicleUsageInterval interval) {
return interval.sourceIntervalIds().isEmpty() ? interval.intervalId() : interval.sourceIntervalIds().getFirst();
}
private static String lastSourceIntervalId(ResolvedVehicleUsageInterval interval) {
return interval.sourceIntervalIds().isEmpty() ? interval.intervalId() : interval.sourceIntervalIds().getLast();
}
private static <T> List<T> safe(List<T> values) {
return values == null ? List.of() : values;
}
}

View File

@ -4,6 +4,7 @@ import at.procon.eventhub.config.EventHubProperties;
import at.procon.eventhub.processing.driverworkingtime.dto.DriverWorkingTimeProcessingResultDto; import at.procon.eventhub.processing.driverworkingtime.dto.DriverWorkingTimeProcessingResultDto;
import at.procon.eventhub.processing.driverworkingtime.service.DriverWorkingTimeDerivedProjectionEngine; import at.procon.eventhub.processing.driverworkingtime.service.DriverWorkingTimeDerivedProjectionEngine;
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.tachographfilesession.dto.TachographEsperDriverProcessingResultDto; import at.procon.eventhub.tachographfilesession.dto.TachographEsperDriverProcessingResultDto;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -23,12 +24,24 @@ public class TachographEsperProcessingCore {
this.delegate = delegate; this.delegate = delegate;
} }
public TachographEsperProcessingCore(
DriverTimelineBuilder driverTimelineBuilder,
TachographDerivedProjectionCompatibilityFacade compatibilityFacade,
EventHubProperties properties
) {
this(new DriverWorkingTimeProcessingCore(new DriverWorkingTimeDerivedProjectionEngine(
compatibilityFacade.commonBuilder()
)));
}
public TachographEsperProcessingCore( public TachographEsperProcessingCore(
DriverTimelineBuilder driverTimelineBuilder, DriverTimelineBuilder driverTimelineBuilder,
DriverTimelineReusableProjectionBuilder reusableProjectionBuilder, DriverTimelineReusableProjectionBuilder reusableProjectionBuilder,
EventHubProperties properties EventHubProperties properties
) { ) {
this(new DriverWorkingTimeProcessingCore(new DriverWorkingTimeDerivedProjectionEngine(reusableProjectionBuilder))); this(new DriverWorkingTimeProcessingCore(new DriverWorkingTimeDerivedProjectionEngine(
reusableProjectionBuilder.commonBuilder()
)));
} }
public TachographEsperDriverProcessingResultDto process(TachographEsperProcessingInput input) { public TachographEsperDriverProcessingResultDto process(TachographEsperProcessingInput input) {

View File

@ -1,12 +1,7 @@
package at.procon.eventhub.tachographfilesession.service; package at.procon.eventhub.tachographfilesession.service;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeActivityInterval;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeProcessingInput; import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeProcessingInput;
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeVehicleUsageInterval;
import at.procon.eventhub.processing.eventprocessing.support.RuntimeSupportEvidenceEvent;
import at.procon.eventhub.tachographfilesession.model.ExtractedSupportEvent;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline; import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import java.util.List;
final class TachographEsperProcessingInputAdapter { final class TachographEsperProcessingInputAdapter {
@ -15,57 +10,15 @@ final class TachographEsperProcessingInputAdapter {
static DriverWorkingTimeProcessingInput toDriverWorkingTimeInput(TachographEsperProcessingInput input) { static DriverWorkingTimeProcessingInput toDriverWorkingTimeInput(TachographEsperProcessingInput input) {
ResolvedDriverTimeline timeline = input.timeline(); ResolvedDriverTimeline timeline = input.timeline();
String driverKey = input.driverKey(); return TachographDriverWorkingTimeAdapter.toProcessingInput(
return new DriverWorkingTimeProcessingInput(
input.sessionId(), input.sessionId(),
driverKey, input.driverKey(),
timeline.sourceKind(), timeline,
timeline.loadedFrom(),
timeline.loadedTo(),
input.requestedFrom(), input.requestedFrom(),
input.requestedTo(), input.requestedTo(),
input.significantDrivingMinutes(), input.significantDrivingMinutes(),
input.minimumRestPeriodMinutes(), input.minimumRestPeriodMinutes(),
timeline.activityIntervals().stream()
.map(interval -> DriverWorkingTimeActivityInterval.fromResolved(input.sessionId(), driverKey, interval))
.toList(),
timeline.vehicleUsageIntervals().stream()
.map(DriverWorkingTimeVehicleUsageInterval::fromResolved)
.toList(),
timeline.supportEvents().stream()
.map(TachographEsperProcessingInputAdapter::toSupportEvidenceEvent)
.toList(),
input.notes() input.notes()
); );
} }
private static 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())
);
}
} }

View File

@ -0,0 +1,194 @@
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.model.ResolvedDriverTimeline;
import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class TachographEventTimelineReconstructionHelper {
private final UnifiedEventTimelineReconstructor timelineReconstructor;
public TachographEventTimelineReconstructionHelper() {
this(new UnifiedEventTimelineReconstructor());
}
@Autowired
public TachographEventTimelineReconstructionHelper(
UnifiedEventTimelineReconstructor timelineReconstructor
) {
this.timelineReconstructor = timelineReconstructor == null
? new UnifiedEventTimelineReconstructor()
: timelineReconstructor;
}
public Map<String, List<EventHubEventDto>> groupEventsByDriverKey(List<EventHubEventDto> events) {
Map<String, List<EventHubEventDto>> grouped = new LinkedHashMap<>();
for (EventHubEventDto event : safe(events)) {
String driverKey = eventDriverKey(event);
if (driverKey == null || driverKey.isBlank()) {
continue;
}
grouped.computeIfAbsent(driverKey, ignored -> new ArrayList<>()).add(event);
}
return grouped;
}
public ResolvedDriverTimeline reconstructMergedTimelineFromEvents(
UUID fallbackSessionId,
String fallbackDriverKey,
List<EventHubEventDto> events
) {
ResolvedDriverTimeline reconstructed = timelineReconstructor.reconstruct(
fallbackSessionId == null ? new UUID(0L, 0L) : fallbackSessionId,
fallbackDriverKey,
safe(events)
);
return new ResolvedDriverTimeline(
reconstructed.sourceKind(),
reconstructed.loadedFrom(),
reconstructed.loadedTo(),
mergeVehicleUsageIntervals(reconstructed.vehicleUsageIntervals(), reconstructed.sourceKind()),
reconstructed.activityIntervals(),
reconstructed.supportEvents(),
reconstructed.warnings()
);
}
private String eventDriverKey(EventHubEventDto event) {
if (event == null) {
return null;
}
JsonNode payload = event.payload();
JsonNode raw = payload == null || payload.isNull() ? null : (payload.get("raw") == null ? payload : payload.get("raw"));
return firstNonBlank(text(raw, "driverKey"), driverKey(event));
}
private String driverKey(EventHubEventDto event) {
if (event.driverRef() == null) {
return null;
}
if (event.driverRef().driverCard() != null && event.driverRef().driverCard().hasValue()) {
return event.driverRef().driverCard().stableKey();
}
return event.driverRef().sourceEntityId();
}
private List<ResolvedVehicleUsageInterval> mergeVehicleUsageIntervals(
List<ResolvedVehicleUsageInterval> intervals,
String sourceKind
) {
List<ResolvedVehicleUsageInterval> sorted = safe(intervals).stream()
.sorted(Comparator.comparing(ResolvedVehicleUsageInterval::from)
.thenComparing(ResolvedVehicleUsageInterval::to, Comparator.nullsLast(Comparator.naturalOrder())))
.toList();
if (sorted.isEmpty()) {
return List.of();
}
List<ResolvedVehicleUsageInterval> result = new ArrayList<>();
ResolvedVehicleUsageInterval current = sorted.getFirst();
List<String> currentSources = new ArrayList<>(current.sourceIntervalIds());
for (int i = 1; i < sorted.size(); i++) {
ResolvedVehicleUsageInterval next = sorted.get(i);
if (canMergeVehicleUsage(current, next)) {
currentSources.addAll(next.sourceIntervalIds());
current = ResolvedVehicleUsageInterval.resolved(
current.sessionId(),
current.driverKey(),
current.intervalId() + "+" + next.intervalId(),
current.from(),
mergedTo(current.to(), next.to()),
current.odometerBeginKm(),
mergedOdometerEnd(current, next),
current.registrationKey(),
current.vehicleKey(),
sourceKind,
currentSources
);
} else {
result.add(current);
current = next;
currentSources = new ArrayList<>(current.sourceIntervalIds());
}
}
result.add(current);
return result;
}
private boolean canMergeVehicleUsage(ResolvedVehicleUsageInterval left, ResolvedVehicleUsageInterval right) {
return Objects.equals(left.registrationKey(), right.registrationKey())
&& Objects.equals(left.vehicleKey(), right.vehicleKey())
&& !right.from().isAfter(mergeBoundary(left.to()));
}
private Long mergedOdometerEnd(
ResolvedVehicleUsageInterval current,
ResolvedVehicleUsageInterval next
) {
if (current == null) {
return next == null ? null : next.odometerEndKm();
}
if (next == null) {
return current.odometerEndKm();
}
if (current.to() == null || next.to() == null) {
return next.odometerEndKm() != null ? next.odometerEndKm() : current.odometerEndKm();
}
if (next.to().isAfter(current.to()) || next.to().isEqual(current.to())) {
return next.odometerEndKm() != null ? next.odometerEndKm() : current.odometerEndKm();
}
return current.odometerEndKm() != null ? current.odometerEndKm() : next.odometerEndKm();
}
private OffsetDateTime mergedTo(OffsetDateTime left, OffsetDateTime right) {
if (left == null || right == null) {
return null;
}
return left.isAfter(right) ? left : right;
}
private OffsetDateTime mergeBoundary(OffsetDateTime endInclusive) {
return endInclusive == null ? OffsetDateTime.MAX : endInclusive.plusSeconds(1);
}
private 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;
}
private String firstNonBlank(String... values) {
if (values == null) {
return null;
}
for (String value : values) {
if (value != null && !value.isBlank()) {
return value.trim();
}
}
return null;
}
private <T> List<T> safe(List<T> values) {
return values == null ? List.of() : values;
}
}

View File

@ -41,11 +41,26 @@ public class TachographFileSessionProcessingService {
private final TachographFileSessionRepository repository; private final TachographFileSessionRepository repository;
private final DriverTimelineBuilder driverTimelineBuilder; private final DriverTimelineBuilder driverTimelineBuilder;
private final DriverTimelineReusableProjectionBuilder reusableProjectionBuilder;
private final EventBackedDriverTimelineBuilder eventBackedDriverTimelineBuilder; private final EventBackedDriverTimelineBuilder eventBackedDriverTimelineBuilder;
private final TachographEsperProcessingCore esperProcessingCore; private final TachographEsperProcessingCore esperProcessingCore;
private final EventHubProperties properties; private final EventHubProperties properties;
public TachographFileSessionProcessingService(
TachographFileSessionRepository repository,
DriverTimelineBuilder driverTimelineBuilder,
TachographDerivedProjectionCompatibilityFacade compatibilityFacade,
EventBackedDriverTimelineBuilder eventBackedDriverTimelineBuilder,
EventHubProperties properties
) {
this(
repository,
driverTimelineBuilder,
eventBackedDriverTimelineBuilder,
properties,
new TachographEsperProcessingCore(driverTimelineBuilder, compatibilityFacade, properties)
);
}
public TachographFileSessionProcessingService( public TachographFileSessionProcessingService(
TachographFileSessionRepository repository, TachographFileSessionRepository repository,
DriverTimelineBuilder driverTimelineBuilder, DriverTimelineBuilder driverTimelineBuilder,
@ -56,7 +71,6 @@ public class TachographFileSessionProcessingService {
this( this(
repository, repository,
driverTimelineBuilder, driverTimelineBuilder,
reusableProjectionBuilder,
eventBackedDriverTimelineBuilder, eventBackedDriverTimelineBuilder,
properties, properties,
new TachographEsperProcessingCore(driverTimelineBuilder, reusableProjectionBuilder, properties) new TachographEsperProcessingCore(driverTimelineBuilder, reusableProjectionBuilder, properties)
@ -67,14 +81,12 @@ public class TachographFileSessionProcessingService {
public TachographFileSessionProcessingService( public TachographFileSessionProcessingService(
TachographFileSessionRepository repository, TachographFileSessionRepository repository,
DriverTimelineBuilder driverTimelineBuilder, DriverTimelineBuilder driverTimelineBuilder,
DriverTimelineReusableProjectionBuilder reusableProjectionBuilder,
EventBackedDriverTimelineBuilder eventBackedDriverTimelineBuilder, EventBackedDriverTimelineBuilder eventBackedDriverTimelineBuilder,
EventHubProperties properties, EventHubProperties properties,
TachographEsperProcessingCore esperProcessingCore TachographEsperProcessingCore esperProcessingCore
) { ) {
this.repository = repository; this.repository = repository;
this.driverTimelineBuilder = driverTimelineBuilder; this.driverTimelineBuilder = driverTimelineBuilder;
this.reusableProjectionBuilder = reusableProjectionBuilder;
this.eventBackedDriverTimelineBuilder = eventBackedDriverTimelineBuilder; this.eventBackedDriverTimelineBuilder = eventBackedDriverTimelineBuilder;
this.properties = properties; this.properties = properties;
this.esperProcessingCore = esperProcessingCore; this.esperProcessingCore = esperProcessingCore;

View File

@ -35,14 +35,14 @@ class TachographEsperProcessingCoreParityTest {
new EventDetailsFactory(new ObjectMapper()) new EventDetailsFactory(new ObjectMapper())
); );
RawSourceDriverTimelineEventBuilder rawSourceEventBuilder = new RawSourceDriverTimelineEventBuilder(intervalEventBuilder); RawSourceDriverTimelineEventBuilder rawSourceEventBuilder = new RawSourceDriverTimelineEventBuilder(intervalEventBuilder);
DriverTimelineReusableProjectionBuilder projectionBuilder = new DriverTimelineReusableProjectionBuilder( TachographDerivedProjectionCompatibilityFacade projectionFacade = new TachographDerivedProjectionCompatibilityFacade(
driverTimelineBuilder, driverTimelineBuilder,
rawSourceEventBuilder, rawSourceEventBuilder,
properties properties
); );
TachographEsperProcessingCore core = new TachographEsperProcessingCore( TachographEsperProcessingCore core = new TachographEsperProcessingCore(
driverTimelineBuilder, driverTimelineBuilder,
projectionBuilder, projectionFacade,
properties properties
); );

View File

@ -33,7 +33,7 @@ class TachographFileSessionProcessingServiceTest {
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService( TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
repository, repository,
driverTimelineBuilder, driverTimelineBuilder,
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder, new EventHubProperties()), new TachographDerivedProjectionCompatibilityFacade(driverTimelineBuilder, new EventHubProperties()),
new EventBackedDriverTimelineBuilder( new EventBackedDriverTimelineBuilder(
new IntervalBackedDriverTimelineEventBuilder( new IntervalBackedDriverTimelineEventBuilder(
driverTimelineBuilder, driverTimelineBuilder,
@ -119,7 +119,7 @@ class TachographFileSessionProcessingServiceTest {
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService( TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
repository, repository,
driverTimelineBuilder, driverTimelineBuilder,
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder, new EventHubProperties()), new TachographDerivedProjectionCompatibilityFacade(driverTimelineBuilder, new EventHubProperties()),
new EventBackedDriverTimelineBuilder( new EventBackedDriverTimelineBuilder(
new IntervalBackedDriverTimelineEventBuilder( new IntervalBackedDriverTimelineEventBuilder(
driverTimelineBuilder, driverTimelineBuilder,
@ -226,7 +226,7 @@ class TachographFileSessionProcessingServiceTest {
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService( TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
repository, repository,
driverTimelineBuilder, driverTimelineBuilder,
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder, new EventHubProperties()), new TachographDerivedProjectionCompatibilityFacade(driverTimelineBuilder, new EventHubProperties()),
new EventBackedDriverTimelineBuilder( new EventBackedDriverTimelineBuilder(
new IntervalBackedDriverTimelineEventBuilder( new IntervalBackedDriverTimelineEventBuilder(
driverTimelineBuilder, driverTimelineBuilder,
@ -315,7 +315,7 @@ class TachographFileSessionProcessingServiceTest {
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService( TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
repository, repository,
driverTimelineBuilder, driverTimelineBuilder,
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder, new EventHubProperties()), new TachographDerivedProjectionCompatibilityFacade(driverTimelineBuilder, new EventHubProperties()),
new EventBackedDriverTimelineBuilder( new EventBackedDriverTimelineBuilder(
new IntervalBackedDriverTimelineEventBuilder( new IntervalBackedDriverTimelineEventBuilder(
driverTimelineBuilder, driverTimelineBuilder,
@ -415,7 +415,7 @@ class TachographFileSessionProcessingServiceTest {
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService( TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
repository, repository,
driverTimelineBuilder, driverTimelineBuilder,
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder, new EventHubProperties()), new TachographDerivedProjectionCompatibilityFacade(driverTimelineBuilder, new EventHubProperties()),
new EventBackedDriverTimelineBuilder( new EventBackedDriverTimelineBuilder(
new IntervalBackedDriverTimelineEventBuilder( new IntervalBackedDriverTimelineEventBuilder(
driverTimelineBuilder, driverTimelineBuilder,
@ -496,7 +496,7 @@ class TachographFileSessionProcessingServiceTest {
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService( TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
repository, repository,
driverTimelineBuilder, driverTimelineBuilder,
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder, new EventHubProperties()), new TachographDerivedProjectionCompatibilityFacade(driverTimelineBuilder, new EventHubProperties()),
new EventBackedDriverTimelineBuilder( new EventBackedDriverTimelineBuilder(
new IntervalBackedDriverTimelineEventBuilder( new IntervalBackedDriverTimelineEventBuilder(
driverTimelineBuilder, driverTimelineBuilder,
@ -586,7 +586,7 @@ class TachographFileSessionProcessingServiceTest {
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService( TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
repository, repository,
driverTimelineBuilder, driverTimelineBuilder,
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder, new EventHubProperties()), new TachographDerivedProjectionCompatibilityFacade(driverTimelineBuilder, new EventHubProperties()),
new EventBackedDriverTimelineBuilder( new EventBackedDriverTimelineBuilder(
new IntervalBackedDriverTimelineEventBuilder( new IntervalBackedDriverTimelineEventBuilder(
driverTimelineBuilder, driverTimelineBuilder,
@ -660,7 +660,7 @@ class TachographFileSessionProcessingServiceTest {
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService( TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
repository, repository,
driverTimelineBuilder, driverTimelineBuilder,
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder, new EventHubProperties()), new TachographDerivedProjectionCompatibilityFacade(driverTimelineBuilder, new EventHubProperties()),
new EventBackedDriverTimelineBuilder( new EventBackedDriverTimelineBuilder(
new IntervalBackedDriverTimelineEventBuilder( new IntervalBackedDriverTimelineEventBuilder(
driverTimelineBuilder, driverTimelineBuilder,