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;
|
||||
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
|
||||
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.TachographEsperSupportGeoEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
||||
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeActivityInterval;
|
||||
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeDrivingInterruptionInterval;
|
||||
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 java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
|
@ -34,19 +32,19 @@ public record DriverWorkingTimeProcessingResultDto(
|
|||
int vehicleUsageIntervalCount,
|
||||
int vuCardAbsentIntervalCount,
|
||||
int supportGeoEventCount,
|
||||
List<TachographEsperActivityIntervalEvent> activityIntervals,
|
||||
List<TachographEsperActivityIntervalEvent> drivingIntervals,
|
||||
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals,
|
||||
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionVehicleChangeIntervals,
|
||||
List<TachographEsperDrivingInterruptionIntervalEvent> dailyWeeklyRestCandidateIntervals,
|
||||
List<TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent> dailyWeeklyRestCandidateCoverageIntervals,
|
||||
List<TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent> unclassifiedDailyWeeklyRestCandidateCoverageIntervals,
|
||||
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> potentialHomeOvernightStayIntervals,
|
||||
List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> potentialInVehicleOvernightStayIntervals,
|
||||
List<TachographEsperPotentialInVehicleTripIntervalEvent> potentialInVehicleTripIntervals,
|
||||
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageIntervals,
|
||||
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals,
|
||||
List<TachographEsperSupportGeoEvent> supportGeoEvents,
|
||||
List<DriverWorkingTimeActivityInterval> activityIntervals,
|
||||
List<DriverWorkingTimeActivityInterval> drivingIntervals,
|
||||
List<DriverWorkingTimeDrivingInterruptionInterval> drivingInterruptionIntervals,
|
||||
List<DriverWorkingTimeDrivingInterruptionInterval> drivingInterruptionVehicleChangeIntervals,
|
||||
List<DriverWorkingTimeDrivingInterruptionInterval> dailyWeeklyRestCandidateIntervals,
|
||||
List<DriverWorkingTimeRestCoverageInterval> dailyWeeklyRestCandidateCoverageIntervals,
|
||||
List<DriverWorkingTimeRestCoverageInterval> unclassifiedDailyWeeklyRestCandidateCoverageIntervals,
|
||||
List<DriverWorkingTimeRestCoverageInterval> potentialHomeOvernightStayIntervals,
|
||||
List<DriverWorkingTimeRestCoverageInterval> potentialInVehicleOvernightStayIntervals,
|
||||
List<DriverWorkingTimePotentialInVehicleTripInterval> potentialInVehicleTripIntervals,
|
||||
List<DriverWorkingTimeVehicleUsageInterval> vehicleUsageIntervals,
|
||||
List<DriverWorkingTimeVuCardAbsentInterval> vuCardAbsentIntervals,
|
||||
List<DriverWorkingTimeSupportGeoEvent> supportGeoEvents,
|
||||
List<String> notes
|
||||
) {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package at.procon.eventhub.processing.driverworkingtime.model;
|
||||
|
||||
import at.procon.eventhub.tachographfilesession.model.ResolvedActivityInterval;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
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")
|
||||
private static List<String> castStringList(Object value) {
|
||||
return value instanceof List<?> list ? (List<String>) list : List.of();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package at.procon.eventhub.processing.driverworkingtime.model;
|
||||
|
||||
import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
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")
|
||||
private static List<String> castStringList(Object value) {
|
||||
return value instanceof List<?> list ? (List<String>) list : List.of();
|
||||
|
|
|
|||
|
|
@ -1,426 +1,23 @@
|
|||
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.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 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.UUID;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class DriverWorkingTimeDerivedProjectionEngine {
|
||||
|
||||
private final DriverTimelineReusableProjectionBuilder legacyProjectionBuilder;
|
||||
private final DriverWorkingTimeReusableProjectionBuilder projectionBuilder;
|
||||
|
||||
public DriverWorkingTimeDerivedProjectionEngine(
|
||||
DriverTimelineReusableProjectionBuilder legacyProjectionBuilder
|
||||
DriverWorkingTimeReusableProjectionBuilder projectionBuilder
|
||||
) {
|
||||
this.legacyProjectionBuilder = legacyProjectionBuilder;
|
||||
this.projectionBuilder = projectionBuilder;
|
||||
}
|
||||
|
||||
public DriverWorkingTimeDerivedProjectionBundle build(DriverWorkingTimeProcessingInput input) {
|
||||
Objects.requireNonNull(input, "input must not be null");
|
||||
ResolvedDriverTimeline timeline = toResolvedTimeline(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;
|
||||
return projectionBuilder.buildDerivedProjectionBundle(input);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
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.tachographfilesession.model.ResolvedDriverTimeline;
|
||||
import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval;
|
||||
import at.procon.eventhub.tachographfilesession.service.TachographDriverWorkingTimeAdapter;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -67,7 +68,7 @@ public class RuntimeDriverVehicleEvidenceAttachmentService {
|
|||
);
|
||||
List<DriverWorkingTimeVehicleUsageInterval> vehicleUsageIntervals = mergeVehicleUsageIntervals(timeline.vehicleUsageIntervals())
|
||||
.stream()
|
||||
.map(DriverWorkingTimeVehicleUsageInterval::fromResolved)
|
||||
.map(TachographDriverWorkingTimeAdapter::toVehicleUsageInterval)
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
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.DriverWorkingTimeVehicleUsageInterval;
|
||||
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.RuntimeSupportEvidenceEvent;
|
||||
import at.procon.eventhub.processing.eventprocessing.support.RuntimeSupportEvidenceNormalizer;
|
||||
import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle;
|
||||
import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest;
|
||||
import at.procon.eventhub.processing.driverworkingtime.dto.DriverWorkingTimeProcessingResultDto;
|
||||
import at.procon.eventhub.tachographfilesession.service.TachographDriverWorkingTimeAdapter;
|
||||
import at.procon.eventhub.tachographfilesession.model.ExtractedSupportEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
|
||||
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.TachographEsperVehicleUsageIntervalEvent;
|
||||
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.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
|
|
@ -47,8 +47,6 @@ public class UnifiedRuntimeDerivedProjectionService {
|
|||
|
||||
private final UnifiedRuntimeEventAssemblyService runtimeEventAssemblyService;
|
||||
private final UnifiedEventTimelineReconstructor timelineReconstructor;
|
||||
private final DriverTimelineBuilder driverTimelineBuilder;
|
||||
private final DriverTimelineReusableProjectionBuilder reusableProjectionBuilder;
|
||||
private final DriverWorkingTimeProcessingCore workingTimeProcessingCore;
|
||||
private final RuntimeSupportEvidenceNormalizer supportEvidenceNormalizer;
|
||||
private final EventHubProperties properties;
|
||||
|
|
@ -56,18 +54,17 @@ public class UnifiedRuntimeDerivedProjectionService {
|
|||
public UnifiedRuntimeDerivedProjectionService(
|
||||
UnifiedRuntimeEventAssemblyService runtimeEventAssemblyService,
|
||||
UnifiedEventTimelineReconstructor timelineReconstructor,
|
||||
DriverTimelineBuilder driverTimelineBuilder,
|
||||
DriverTimelineReusableProjectionBuilder reusableProjectionBuilder,
|
||||
EventHubProperties properties,
|
||||
DriverWorkingTimeReusableProjectionBuilder reusableProjectionBuilder,
|
||||
RuntimeSupportEvidenceNormalizer supportEvidenceNormalizer
|
||||
) {
|
||||
this(
|
||||
runtimeEventAssemblyService,
|
||||
timelineReconstructor,
|
||||
driverTimelineBuilder,
|
||||
reusableProjectionBuilder,
|
||||
properties,
|
||||
new DriverWorkingTimeProcessingCore(new DriverWorkingTimeDerivedProjectionEngine(reusableProjectionBuilder)),
|
||||
new DriverWorkingTimeProcessingCore(new DriverWorkingTimeDerivedProjectionEngine(
|
||||
reusableProjectionBuilder
|
||||
)),
|
||||
supportEvidenceNormalizer
|
||||
);
|
||||
}
|
||||
|
|
@ -76,16 +73,12 @@ public class UnifiedRuntimeDerivedProjectionService {
|
|||
public UnifiedRuntimeDerivedProjectionService(
|
||||
UnifiedRuntimeEventAssemblyService runtimeEventAssemblyService,
|
||||
UnifiedEventTimelineReconstructor timelineReconstructor,
|
||||
DriverTimelineBuilder driverTimelineBuilder,
|
||||
DriverTimelineReusableProjectionBuilder reusableProjectionBuilder,
|
||||
EventHubProperties properties,
|
||||
DriverWorkingTimeProcessingCore workingTimeProcessingCore,
|
||||
RuntimeSupportEvidenceNormalizer supportEvidenceNormalizer
|
||||
) {
|
||||
this.runtimeEventAssemblyService = runtimeEventAssemblyService;
|
||||
this.timelineReconstructor = timelineReconstructor;
|
||||
this.driverTimelineBuilder = driverTimelineBuilder;
|
||||
this.reusableProjectionBuilder = reusableProjectionBuilder;
|
||||
this.properties = properties;
|
||||
this.workingTimeProcessingCore = workingTimeProcessingCore;
|
||||
this.supportEvidenceNormalizer = supportEvidenceNormalizer;
|
||||
|
|
@ -156,11 +149,15 @@ public class UnifiedRuntimeDerivedProjectionService {
|
|||
significantDrivingMinutes,
|
||||
minimumRestPeriodMinutes,
|
||||
timeline.activityIntervals().stream()
|
||||
.map(interval -> DriverWorkingTimeActivityInterval.fromResolved(runtimeSessionId(request), driverKey, interval))
|
||||
.map(interval -> TachographDriverWorkingTimeAdapter.toActivityInterval(
|
||||
runtimeSessionId(request),
|
||||
driverKey,
|
||||
interval
|
||||
))
|
||||
.filter(Objects::nonNull)
|
||||
.toList(),
|
||||
timeline.vehicleUsageIntervals().stream()
|
||||
.map(DriverWorkingTimeVehicleUsageInterval::fromResolved)
|
||||
.map(TachographDriverWorkingTimeAdapter::toVehicleUsageInterval)
|
||||
.filter(Objects::nonNull)
|
||||
.toList(),
|
||||
timeline.supportEvents().stream()
|
||||
|
|
|
|||
|
|
@ -1,9 +1,18 @@
|
|||
package at.procon.eventhub.tachographfilesession.dto;
|
||||
|
||||
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.TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent;
|
||||
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;
|
||||
|
|
@ -78,19 +87,19 @@ public record TachographEsperDriverProcessingResultDto(
|
|||
result.vehicleUsageIntervalCount(),
|
||||
result.vuCardAbsentIntervalCount(),
|
||||
result.supportGeoEventCount(),
|
||||
result.activityIntervals(),
|
||||
result.drivingIntervals(),
|
||||
result.drivingInterruptionIntervals(),
|
||||
result.drivingInterruptionVehicleChangeIntervals(),
|
||||
result.dailyWeeklyRestCandidateIntervals(),
|
||||
result.dailyWeeklyRestCandidateCoverageIntervals(),
|
||||
result.unclassifiedDailyWeeklyRestCandidateCoverageIntervals(),
|
||||
result.potentialHomeOvernightStayIntervals(),
|
||||
result.potentialInVehicleOvernightStayIntervals(),
|
||||
result.potentialInVehicleTripIntervals(),
|
||||
result.vehicleUsageIntervals(),
|
||||
result.vuCardAbsentIntervals(),
|
||||
result.supportGeoEvents(),
|
||||
mapActivityIntervalsToLegacy(result.activityIntervals()),
|
||||
mapActivityIntervalsToLegacy(result.drivingIntervals()),
|
||||
mapDrivingInterruptionsToLegacy(result.drivingInterruptionIntervals()),
|
||||
mapDrivingInterruptionsToLegacy(result.drivingInterruptionVehicleChangeIntervals()),
|
||||
mapDrivingInterruptionsToLegacy(result.dailyWeeklyRestCandidateIntervals()),
|
||||
mapCoverageIntervalsToLegacy(result.dailyWeeklyRestCandidateCoverageIntervals()),
|
||||
mapCoverageIntervalsToLegacy(result.unclassifiedDailyWeeklyRestCandidateCoverageIntervals()),
|
||||
mapPotentialHomeIntervalsToLegacy(result.potentialHomeOvernightStayIntervals()),
|
||||
mapPotentialInVehicleIntervalsToLegacy(result.potentialInVehicleOvernightStayIntervals()),
|
||||
mapPotentialTripsToLegacy(result.potentialInVehicleTripIntervals()),
|
||||
mapVehicleUsageIntervalsToLegacy(result.vehicleUsageIntervals()),
|
||||
mapVuCardAbsentIntervalsToLegacy(result.vuCardAbsentIntervals()),
|
||||
mapSupportGeoEventsToLegacy(result.supportGeoEvents()),
|
||||
result.notes()
|
||||
);
|
||||
}
|
||||
|
|
@ -117,20 +126,689 @@ public record TachographEsperDriverProcessingResultDto(
|
|||
vehicleUsageIntervalCount,
|
||||
vuCardAbsentIntervalCount,
|
||||
supportGeoEventCount,
|
||||
activityIntervals,
|
||||
drivingIntervals,
|
||||
drivingInterruptionIntervals,
|
||||
drivingInterruptionVehicleChangeIntervals,
|
||||
dailyWeeklyRestCandidateIntervals,
|
||||
dailyWeeklyRestCandidateCoverageIntervals,
|
||||
unclassifiedDailyWeeklyRestCandidateCoverageIntervals,
|
||||
potentialHomeOvernightStayIntervals,
|
||||
potentialInVehicleOvernightStayIntervals,
|
||||
potentialInVehicleTripIntervals,
|
||||
vehicleUsageIntervals,
|
||||
vuCardAbsentIntervals,
|
||||
supportGeoEvents,
|
||||
mapActivityIntervalsFromLegacy(activityIntervals),
|
||||
mapActivityIntervalsFromLegacy(drivingIntervals),
|
||||
mapDrivingInterruptionsFromLegacy(drivingInterruptionIntervals),
|
||||
mapDrivingInterruptionsFromLegacy(drivingInterruptionVehicleChangeIntervals),
|
||||
mapDrivingInterruptionsFromLegacy(dailyWeeklyRestCandidateIntervals),
|
||||
mapCoverageIntervalsFromLegacy(dailyWeeklyRestCandidateCoverageIntervals),
|
||||
mapCoverageIntervalsFromLegacy(unclassifiedDailyWeeklyRestCandidateCoverageIntervals),
|
||||
mapPotentialHomeIntervalsFromLegacy(potentialHomeOvernightStayIntervals),
|
||||
mapPotentialInVehicleIntervalsFromLegacy(potentialInVehicleOvernightStayIntervals),
|
||||
mapPotentialTripsFromLegacy(potentialInVehicleTripIntervals),
|
||||
mapVehicleUsageIntervalsFromLegacy(vehicleUsageIntervals),
|
||||
mapVuCardAbsentIntervalsFromLegacy(vuCardAbsentIntervals),
|
||||
mapSupportGeoEventsFromLegacy(supportGeoEvents),
|
||||
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.service.DriverWorkingTimeDerivedProjectionEngine;
|
||||
import at.procon.eventhub.processing.driverworkingtime.service.DriverWorkingTimeProcessingCore;
|
||||
import at.procon.eventhub.processing.driverworkingtime.service.DriverWorkingTimeReusableProjectionBuilder;
|
||||
import at.procon.eventhub.tachographfilesession.dto.TachographEsperDriverProcessingResultDto;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
|
@ -23,12 +24,24 @@ public class TachographEsperProcessingCore {
|
|||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public TachographEsperProcessingCore(
|
||||
DriverTimelineBuilder driverTimelineBuilder,
|
||||
TachographDerivedProjectionCompatibilityFacade compatibilityFacade,
|
||||
EventHubProperties properties
|
||||
) {
|
||||
this(new DriverWorkingTimeProcessingCore(new DriverWorkingTimeDerivedProjectionEngine(
|
||||
compatibilityFacade.commonBuilder()
|
||||
)));
|
||||
}
|
||||
|
||||
public TachographEsperProcessingCore(
|
||||
DriverTimelineBuilder driverTimelineBuilder,
|
||||
DriverTimelineReusableProjectionBuilder reusableProjectionBuilder,
|
||||
EventHubProperties properties
|
||||
) {
|
||||
this(new DriverWorkingTimeProcessingCore(new DriverWorkingTimeDerivedProjectionEngine(reusableProjectionBuilder)));
|
||||
this(new DriverWorkingTimeProcessingCore(new DriverWorkingTimeDerivedProjectionEngine(
|
||||
reusableProjectionBuilder.commonBuilder()
|
||||
)));
|
||||
}
|
||||
|
||||
public TachographEsperDriverProcessingResultDto process(TachographEsperProcessingInput input) {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,7 @@
|
|||
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.DriverWorkingTimeVehicleUsageInterval;
|
||||
import at.procon.eventhub.processing.eventprocessing.support.RuntimeSupportEvidenceEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.ExtractedSupportEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
|
||||
import java.util.List;
|
||||
|
||||
final class TachographEsperProcessingInputAdapter {
|
||||
|
||||
|
|
@ -15,57 +10,15 @@ final class TachographEsperProcessingInputAdapter {
|
|||
|
||||
static DriverWorkingTimeProcessingInput toDriverWorkingTimeInput(TachographEsperProcessingInput input) {
|
||||
ResolvedDriverTimeline timeline = input.timeline();
|
||||
String driverKey = input.driverKey();
|
||||
return new DriverWorkingTimeProcessingInput(
|
||||
return TachographDriverWorkingTimeAdapter.toProcessingInput(
|
||||
input.sessionId(),
|
||||
driverKey,
|
||||
timeline.sourceKind(),
|
||||
timeline.loadedFrom(),
|
||||
timeline.loadedTo(),
|
||||
input.driverKey(),
|
||||
timeline,
|
||||
input.requestedFrom(),
|
||||
input.requestedTo(),
|
||||
input.significantDrivingMinutes(),
|
||||
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()
|
||||
);
|
||||
}
|
||||
|
||||
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 DriverTimelineBuilder driverTimelineBuilder;
|
||||
private final DriverTimelineReusableProjectionBuilder reusableProjectionBuilder;
|
||||
private final EventBackedDriverTimelineBuilder eventBackedDriverTimelineBuilder;
|
||||
private final TachographEsperProcessingCore esperProcessingCore;
|
||||
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(
|
||||
TachographFileSessionRepository repository,
|
||||
DriverTimelineBuilder driverTimelineBuilder,
|
||||
|
|
@ -56,7 +71,6 @@ public class TachographFileSessionProcessingService {
|
|||
this(
|
||||
repository,
|
||||
driverTimelineBuilder,
|
||||
reusableProjectionBuilder,
|
||||
eventBackedDriverTimelineBuilder,
|
||||
properties,
|
||||
new TachographEsperProcessingCore(driverTimelineBuilder, reusableProjectionBuilder, properties)
|
||||
|
|
@ -67,14 +81,12 @@ public class TachographFileSessionProcessingService {
|
|||
public TachographFileSessionProcessingService(
|
||||
TachographFileSessionRepository repository,
|
||||
DriverTimelineBuilder driverTimelineBuilder,
|
||||
DriverTimelineReusableProjectionBuilder reusableProjectionBuilder,
|
||||
EventBackedDriverTimelineBuilder eventBackedDriverTimelineBuilder,
|
||||
EventHubProperties properties,
|
||||
TachographEsperProcessingCore esperProcessingCore
|
||||
) {
|
||||
this.repository = repository;
|
||||
this.driverTimelineBuilder = driverTimelineBuilder;
|
||||
this.reusableProjectionBuilder = reusableProjectionBuilder;
|
||||
this.eventBackedDriverTimelineBuilder = eventBackedDriverTimelineBuilder;
|
||||
this.properties = properties;
|
||||
this.esperProcessingCore = esperProcessingCore;
|
||||
|
|
|
|||
|
|
@ -35,14 +35,14 @@ class TachographEsperProcessingCoreParityTest {
|
|||
new EventDetailsFactory(new ObjectMapper())
|
||||
);
|
||||
RawSourceDriverTimelineEventBuilder rawSourceEventBuilder = new RawSourceDriverTimelineEventBuilder(intervalEventBuilder);
|
||||
DriverTimelineReusableProjectionBuilder projectionBuilder = new DriverTimelineReusableProjectionBuilder(
|
||||
TachographDerivedProjectionCompatibilityFacade projectionFacade = new TachographDerivedProjectionCompatibilityFacade(
|
||||
driverTimelineBuilder,
|
||||
rawSourceEventBuilder,
|
||||
properties
|
||||
);
|
||||
TachographEsperProcessingCore core = new TachographEsperProcessingCore(
|
||||
driverTimelineBuilder,
|
||||
projectionBuilder,
|
||||
projectionFacade,
|
||||
properties
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class TachographFileSessionProcessingServiceTest {
|
|||
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
|
||||
repository,
|
||||
driverTimelineBuilder,
|
||||
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder, new EventHubProperties()),
|
||||
new TachographDerivedProjectionCompatibilityFacade(driverTimelineBuilder, new EventHubProperties()),
|
||||
new EventBackedDriverTimelineBuilder(
|
||||
new IntervalBackedDriverTimelineEventBuilder(
|
||||
driverTimelineBuilder,
|
||||
|
|
@ -119,7 +119,7 @@ class TachographFileSessionProcessingServiceTest {
|
|||
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
|
||||
repository,
|
||||
driverTimelineBuilder,
|
||||
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder, new EventHubProperties()),
|
||||
new TachographDerivedProjectionCompatibilityFacade(driverTimelineBuilder, new EventHubProperties()),
|
||||
new EventBackedDriverTimelineBuilder(
|
||||
new IntervalBackedDriverTimelineEventBuilder(
|
||||
driverTimelineBuilder,
|
||||
|
|
@ -226,7 +226,7 @@ class TachographFileSessionProcessingServiceTest {
|
|||
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
|
||||
repository,
|
||||
driverTimelineBuilder,
|
||||
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder, new EventHubProperties()),
|
||||
new TachographDerivedProjectionCompatibilityFacade(driverTimelineBuilder, new EventHubProperties()),
|
||||
new EventBackedDriverTimelineBuilder(
|
||||
new IntervalBackedDriverTimelineEventBuilder(
|
||||
driverTimelineBuilder,
|
||||
|
|
@ -315,7 +315,7 @@ class TachographFileSessionProcessingServiceTest {
|
|||
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
|
||||
repository,
|
||||
driverTimelineBuilder,
|
||||
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder, new EventHubProperties()),
|
||||
new TachographDerivedProjectionCompatibilityFacade(driverTimelineBuilder, new EventHubProperties()),
|
||||
new EventBackedDriverTimelineBuilder(
|
||||
new IntervalBackedDriverTimelineEventBuilder(
|
||||
driverTimelineBuilder,
|
||||
|
|
@ -415,7 +415,7 @@ class TachographFileSessionProcessingServiceTest {
|
|||
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
|
||||
repository,
|
||||
driverTimelineBuilder,
|
||||
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder, new EventHubProperties()),
|
||||
new TachographDerivedProjectionCompatibilityFacade(driverTimelineBuilder, new EventHubProperties()),
|
||||
new EventBackedDriverTimelineBuilder(
|
||||
new IntervalBackedDriverTimelineEventBuilder(
|
||||
driverTimelineBuilder,
|
||||
|
|
@ -496,7 +496,7 @@ class TachographFileSessionProcessingServiceTest {
|
|||
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
|
||||
repository,
|
||||
driverTimelineBuilder,
|
||||
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder, new EventHubProperties()),
|
||||
new TachographDerivedProjectionCompatibilityFacade(driverTimelineBuilder, new EventHubProperties()),
|
||||
new EventBackedDriverTimelineBuilder(
|
||||
new IntervalBackedDriverTimelineEventBuilder(
|
||||
driverTimelineBuilder,
|
||||
|
|
@ -586,7 +586,7 @@ class TachographFileSessionProcessingServiceTest {
|
|||
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
|
||||
repository,
|
||||
driverTimelineBuilder,
|
||||
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder, new EventHubProperties()),
|
||||
new TachographDerivedProjectionCompatibilityFacade(driverTimelineBuilder, new EventHubProperties()),
|
||||
new EventBackedDriverTimelineBuilder(
|
||||
new IntervalBackedDriverTimelineEventBuilder(
|
||||
driverTimelineBuilder,
|
||||
|
|
@ -660,7 +660,7 @@ class TachographFileSessionProcessingServiceTest {
|
|||
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
|
||||
repository,
|
||||
driverTimelineBuilder,
|
||||
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder, new EventHubProperties()),
|
||||
new TachographDerivedProjectionCompatibilityFacade(driverTimelineBuilder, new EventHubProperties()),
|
||||
new EventBackedDriverTimelineBuilder(
|
||||
new IntervalBackedDriverTimelineEventBuilder(
|
||||
driverTimelineBuilder,
|
||||
|
|
|
|||
Loading…
Reference in New Issue