Finalize neutral working-time projection architecture
This commit is contained in:
parent
cd090010c6
commit
927ac3b903
|
|
@ -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
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue