From 3bccda20e8be5ca88e7dabe10ad0e84644bdf7ca Mon Sep 17 00:00:00 2001
From: trifonovt <87468028+TihomirTrifonov@users.noreply.github.com>
Date: Mon, 25 May 2026 16:33:59 +0200
Subject: [PATCH] Add raw event tachograph projection input path
---
.../eventhub/config/EventHubProperties.java | 19 +
.../service/DriverTimelineEventBuilder.java | 13 +
...iverTimelineReusableProjectionBuilder.java | 556 ++++++++++++++++++
...ervalBackedDriverTimelineEventBuilder.java | 7 +
.../RawSourceDriverTimelineEventBuilder.java | 211 +++++++
...achographFileSessionProcessingService.java | 22 +-
src/main/resources/application.yml | 3 +
...derived-projection-events-preprocessor.epl | 348 +++++++++++
...TimelineReusableProjectionBuilderTest.java | 235 ++++++++
9 files changed, 1407 insertions(+), 7 deletions(-)
create mode 100644 src/main/java/at/procon/eventhub/tachographfilesession/service/RawSourceDriverTimelineEventBuilder.java
create mode 100644 src/main/resources/esper/tachograph-driving-derived-projection-events-preprocessor.epl
diff --git a/src/main/java/at/procon/eventhub/config/EventHubProperties.java b/src/main/java/at/procon/eventhub/config/EventHubProperties.java
index 5dffa74..821cdf6 100644
--- a/src/main/java/at/procon/eventhub/config/EventHubProperties.java
+++ b/src/main/java/at/procon/eventhub/config/EventHubProperties.java
@@ -357,6 +357,7 @@ public class EventHubProperties {
public static class Processing {
private TimelineInputMode timelineInputMode = TimelineInputMode.INTERVALS;
+ private DrivingDerivedProjectionInputMode drivingDerivedProjectionInputMode = DrivingDerivedProjectionInputMode.INTERVALS;
private int operatingSplitIdleHours = 7;
private int significantDrivingMinutes = 3;
private int minimumRestPeriodMinutes = 720;
@@ -377,6 +378,16 @@ public class EventHubProperties {
}
}
+ public DrivingDerivedProjectionInputMode getDrivingDerivedProjectionInputMode() {
+ return drivingDerivedProjectionInputMode;
+ }
+
+ public void setDrivingDerivedProjectionInputMode(DrivingDerivedProjectionInputMode drivingDerivedProjectionInputMode) {
+ if (drivingDerivedProjectionInputMode != null) {
+ this.drivingDerivedProjectionInputMode = drivingDerivedProjectionInputMode;
+ }
+ }
+
public int getOperatingSplitIdleHours() {
return operatingSplitIdleHours;
}
@@ -456,6 +467,14 @@ public class EventHubProperties {
EVENTS
}
+ public enum DrivingDerivedProjectionInputMode {
+ /** Existing stable path: Java resolves intervals and EPL receives interval input streams. */
+ INTERVALS,
+
+ /** New path: EPL receives EventHub point events and reconstructs interval streams internally. */
+ EVENTS
+ }
+
public static class LegalRequirements {
private static final String DEFAULT_BASE_URL = "https://legalrequirements.services.bytebar.eu/ODataV4/LR";
diff --git a/src/main/java/at/procon/eventhub/tachographfilesession/service/DriverTimelineEventBuilder.java b/src/main/java/at/procon/eventhub/tachographfilesession/service/DriverTimelineEventBuilder.java
index 08b56f4..8d16886 100644
--- a/src/main/java/at/procon/eventhub/tachographfilesession/service/DriverTimelineEventBuilder.java
+++ b/src/main/java/at/procon/eventhub/tachographfilesession/service/DriverTimelineEventBuilder.java
@@ -20,6 +20,19 @@ public interface DriverTimelineEventBuilder {
ResolvedDriverTimeline timeline
);
+ /**
+ * Builds the rawest point-event representation supported by the implementation.
+ *
+ *
The default preserves the existing interval-backed behavior. Implementations that can
+ * emit point events directly from source records should override this method.
+ */
+ default TachographTimelineEventBundle buildRawEventBundle(
+ TachographFileSession session,
+ DriverExtractionSession driverSession
+ ) {
+ return buildEventBundle(session, driverSession);
+ }
+
default List buildEvents(
TachographFileSession session,
DriverExtractionSession driverSession
diff --git a/src/main/java/at/procon/eventhub/tachographfilesession/service/DriverTimelineReusableProjectionBuilder.java b/src/main/java/at/procon/eventhub/tachographfilesession/service/DriverTimelineReusableProjectionBuilder.java
index 6af166e..b4e270c 100644
--- a/src/main/java/at/procon/eventhub/tachographfilesession/service/DriverTimelineReusableProjectionBuilder.java
+++ b/src/main/java/at/procon/eventhub/tachographfilesession/service/DriverTimelineReusableProjectionBuilder.java
@@ -10,7 +10,13 @@ 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 com.fasterxml.jackson.databind.JsonNode;
import at.procon.eventhub.config.EventHubProperties;
+import at.procon.eventhub.dto.EventDomain;
+import at.procon.eventhub.dto.EventHubEventDto;
+import at.procon.eventhub.dto.EventLifecycle;
+import at.procon.eventhub.dto.EventType;
+import at.procon.eventhub.processing.service.UnifiedEventTimelineReconstructor;
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
import at.procon.eventhub.tachographfilesession.model.ExtractedSupportEvent;
import at.procon.eventhub.tachographfilesession.model.ResolvedActivityInterval;
@@ -39,6 +45,7 @@ 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.Component;
import org.springframework.util.StreamUtils;
@@ -49,15 +56,31 @@ public class DriverTimelineReusableProjectionBuilder {
private static final AtomicLong RUNTIME_COUNTER = new AtomicLong();
private static final String DRIVING_DERIVED_PROJECTION_BUNDLE_EPL_TEMPLATE =
loadResource("esper/tachograph-driving-derived-projection-bundle.epl");
+ private static final String DRIVING_DERIVED_PROJECTION_EVENTS_PREPROCESSOR_EPL =
+ loadResource("esper/tachograph-driving-derived-projection-events-preprocessor.epl");
private final DriverTimelineBuilder driverTimelineBuilder;
+ private final RawSourceDriverTimelineEventBuilder rawSourceEventBuilder;
+ private final UnifiedEventTimelineReconstructor timelineReconstructor;
private final EventHubProperties properties;
public DriverTimelineReusableProjectionBuilder(
DriverTimelineBuilder driverTimelineBuilder,
EventHubProperties properties
+ ) {
+ this(driverTimelineBuilder, null, new UnifiedEventTimelineReconstructor(), properties);
+ }
+
+ @Autowired
+ public DriverTimelineReusableProjectionBuilder(
+ DriverTimelineBuilder driverTimelineBuilder,
+ RawSourceDriverTimelineEventBuilder rawSourceEventBuilder,
+ UnifiedEventTimelineReconstructor timelineReconstructor,
+ EventHubProperties properties
) {
this.driverTimelineBuilder = driverTimelineBuilder;
+ this.rawSourceEventBuilder = rawSourceEventBuilder;
+ this.timelineReconstructor = timelineReconstructor;
this.properties = properties;
}
@@ -67,6 +90,18 @@ public class DriverTimelineReusableProjectionBuilder {
int significantDrivingMinutes,
int minimumRestPeriodMinutes
) {
+ if (session == null || driverSession == null) {
+ return emptyBundle();
+ }
+ 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(),
@@ -86,6 +121,22 @@ public class DriverTimelineReusableProjectionBuilder {
return emptyBundle();
}
+ if (drivingDerivedProjectionInputMode() == EventHubProperties.DrivingDerivedProjectionInputMode.EVENTS) {
+ List events = new ArrayList<>();
+ for (DriverExtractionSession driverSession : session.driversByKey().values()) {
+ if (driverSession != null && driverSession.driverKey() != null) {
+ events.addAll(rawSourceEventBuilder().buildRawEventBundle(session, driverSession).allEvents());
+ }
+ }
+ return buildEsperDrivingDerivedProjectionBundleFromEvents(
+ session.sessionId(),
+ null,
+ events,
+ significantDrivingMinutes,
+ minimumRestPeriodMinutes
+ );
+ }
+
List