Compare commits
3 Commits
91c2da02fc
...
ce81bfe868
| Author | SHA1 | Date |
|---|---|---|
|
|
ce81bfe868 | |
|
|
08b3cbf073 | |
|
|
8a106c02c5 |
|
|
@ -5,3 +5,4 @@ target/
|
|||
.project
|
||||
.settings/
|
||||
.DS_Store
|
||||
logs/eventhub-ingestion-service.log
|
||||
|
|
|
|||
|
|
@ -1,207 +0,0 @@
|
|||
2026-05-12T11:15:13.519+02:00 INFO 12264 --- [http-nio-8085-exec-5] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-8' version 9.0.0
|
||||
2026-05-12T11:15:14.119+02:00 INFO 12264 --- [http-nio-8085-exec-5] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-8'
|
||||
2026-05-12T11:15:14.122+02:00 INFO 12264 --- [http-nio-8085-exec-5] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-9' version 9.0.0
|
||||
2026-05-12T11:15:14.293+02:00 INFO 12264 --- [http-nio-8085-exec-5] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-9'
|
||||
2026-05-12T11:15:14.299+02:00 INFO 12264 --- [http-nio-8085-exec-5] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-operating-period-2' version 9.0.0
|
||||
2026-05-12T11:15:14.348+02:00 INFO 12264 --- [http-nio-8085-exec-5] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-operating-period-2'
|
||||
2026-05-12T11:15:14.353+02:00 INFO 12264 --- [http-nio-8085-exec-5] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-10' version 9.0.0
|
||||
2026-05-12T11:15:14.391+02:00 INFO 12264 --- [http-nio-8085-exec-5] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-10'
|
||||
2026-05-12T11:15:14.395+02:00 INFO 12264 --- [http-nio-8085-exec-5] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-11' version 9.0.0
|
||||
2026-05-12T11:15:14.438+02:00 INFO 12264 --- [http-nio-8085-exec-5] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-11'
|
||||
2026-05-12T11:15:14.440+02:00 INFO 12264 --- [http-nio-8085-exec-5] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-12' version 9.0.0
|
||||
2026-05-12T11:15:14.481+02:00 INFO 12264 --- [http-nio-8085-exec-5] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-12'
|
||||
2026-05-12T11:15:14.484+02:00 INFO 12264 --- [http-nio-8085-exec-5] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-13' version 9.0.0
|
||||
2026-05-12T11:15:14.526+02:00 INFO 12264 --- [http-nio-8085-exec-5] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-13'
|
||||
2026-05-12T11:15:14.528+02:00 INFO 12264 --- [http-nio-8085-exec-5] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-14' version 9.0.0
|
||||
2026-05-12T11:15:14.568+02:00 INFO 12264 --- [http-nio-8085-exec-5] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-14'
|
||||
2026-05-12T11:15:14.569+02:00 INFO 12264 --- [http-nio-8085-exec-5] a.p.e.e.s.EsperOperatingPeriodEvaluationService : Esper operating-period evaluation tenant=Procon driverId=026598bf-002d-460d-8b06-ccbd05fb46b7 requestedFrom=2026-04-01T00:00Z requestedTo=2026-05-01T00:00Z loadedFrom=2026-03-31T00:00Z loadedTo=2026-05-02T00:00Z unknownMode=AS_BREAK_REST engineMode=STREAM_COLLECTOR rawEvents=708 cardRawEvents=354 vuRawEvents=354 cardIntervals=176 vuIntervals=168 resolvedKnownIntervals=176 evaluationIntervals=113 periodizedIntervals=113 mergedIntervals=113 nonDrivingIntervals=31 operatingPeriods=5 timingsMs={{dbRetrieve=347, cardIntervalEsper=939, vuIntervalEsper=174, vuGapFill=2, synthUnknown=1, periodizeEsper=51, merge=1, nonDriving=0, total=1738}}
|
||||
2026-05-12T11:16:09.058+02:00 INFO 12264 --- [SpringApplicationShutdownHook] o.s.boot.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete
|
||||
2026-05-12T11:16:09.272+02:00 INFO 12264 --- [tomcat-shutdown] o.s.boot.tomcat.GracefulShutdown : Graceful shutdown complete
|
||||
2026-05-12T11:16:09.310+02:00 INFO 12264 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Apache Camel 4.18.2 (camel-1) is shutting down (timeout:45s)
|
||||
2026-05-12T11:16:11.015+02:00 INFO 12264 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Routes stopped (total:10)
|
||||
2026-05-12T11:16:11.016+02:00 INFO 12264 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped yellowfox-d8-import-start-route (direct://yellowfox-d8-import-start)
|
||||
2026-05-12T11:16:11.016+02:00 INFO 12264 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped yellowfox-d8-booking-input-route (direct://yellowfox-d8-booking-input)
|
||||
2026-05-12T11:16:11.144+02:00 INFO 12264 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped tachograph-import-start-route (direct://tachograph-import-start)
|
||||
2026-05-12T11:16:11.145+02:00 INFO 12264 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped tachograph-activity-input-route (direct://tachograph-activity-input)
|
||||
2026-05-12T11:16:11.146+02:00 INFO 12264 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped telematics-position-input-route (direct://telematics-position-input)
|
||||
2026-05-12T11:16:11.147+02:00 INFO 12264 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped eventhub-manual-input-route (direct://eventhub-manual-input)
|
||||
2026-05-12T11:16:11.149+02:00 INFO 12264 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped eventhub-package-input-route (direct://eventhub-package-input)
|
||||
2026-05-12T11:16:11.149+02:00 INFO 12264 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped eventhub-direct-batch-persist-route (direct://eventhub-batch-persist-input)
|
||||
2026-05-12T11:16:11.149+02:00 INFO 12264 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped eventhub-batch-and-persist-route (seda://eventhub-batch-input)
|
||||
2026-05-12T11:16:11.149+02:00 INFO 12264 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped eventhub-normalized-input-route (direct://eventhub-normalized-input)
|
||||
2026-05-12T11:16:11.352+02:00 INFO 12264 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Apache Camel 4.18.2 (camel-1) shutdown in 2s8ms (uptime:18h55m)
|
||||
2026-05-12T11:16:11.582+02:00 INFO 12264 --- [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
|
||||
2026-05-12T11:16:11.614+02:00 INFO 12264 --- [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
|
||||
2026-05-12T11:23:05.801+02:00 INFO 9580 --- [background-preinit] o.h.validator.internal.util.Version : HV000001: Hibernate Validator 9.0.1.Final
|
||||
2026-05-12T11:23:06.558+02:00 INFO 9580 --- [main] a.p.e.EventHubIngestionApplication : Starting EventHubIngestionApplication using Java 21.0.2 with PID 9580 (C:\Work\java\gite\eventhub-spring-boot\eventhub-spring-boot\target\classes started by Parzival in C:\Work\java\gite\eventhub-spring-boot\eventhub-spring-boot)
|
||||
2026-05-12T11:23:06.566+02:00 INFO 9580 --- [main] a.p.e.EventHubIngestionApplication : No active profile set, falling back to 1 default profile: "default"
|
||||
2026-05-12T11:23:11.900+02:00 INFO 9580 --- [main] o.s.boot.tomcat.TomcatWebServer : Tomcat initialized with port 8085 (http)
|
||||
2026-05-12T11:23:11.930+02:00 INFO 9580 --- [main] o.a.coyote.http11.Http11NioProtocol : Initializing ProtocolHandler ["http-nio-8085"]
|
||||
2026-05-12T11:23:11.933+02:00 INFO 9580 --- [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
||||
2026-05-12T11:23:11.933+02:00 INFO 9580 --- [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/11.0.21]
|
||||
2026-05-12T11:23:12.061+02:00 INFO 9580 --- [main] o.s.b.w.c.s.WebApplicationContextInitializer : Root WebApplicationContext: initialization completed in 5194 ms
|
||||
2026-05-12T11:23:15.477+02:00 INFO 9580 --- [main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 4 endpoints beneath base path '/actuator'
|
||||
2026-05-12T11:23:15.639+02:00 INFO 9580 --- [main] o.a.coyote.http11.Http11NioProtocol : Starting ProtocolHandler ["http-nio-8085"]
|
||||
2026-05-12T11:23:15.673+02:00 INFO 9580 --- [main] o.s.boot.tomcat.TomcatWebServer : Tomcat started on port 8085 (http) with context path '/'
|
||||
2026-05-12T11:23:20.172+02:00 INFO 9580 --- [main] o.a.c.impl.engine.AbstractCamelContext : Apache Camel 4.18.2 (camel-1) is starting
|
||||
2026-05-12T11:23:20.203+02:00 INFO 9580 --- [main] o.a.c.p.aggregate.AggregateProcessor : Defaulting to MemoryAggregationRepository
|
||||
2026-05-12T11:23:20.204+02:00 INFO 9580 --- [main] o.a.c.p.aggregate.AggregateProcessor : Using CompletionTimeout to trigger after 5000 millis of inactivity.
|
||||
2026-05-12T11:23:20.276+02:00 INFO 9580 --- [main] o.a.c.impl.engine.AbstractCamelContext : Routes startup (total:10)
|
||||
2026-05-12T11:23:20.277+02:00 INFO 9580 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started eventhub-normalized-input-route (direct://eventhub-normalized-input)
|
||||
2026-05-12T11:23:20.279+02:00 INFO 9580 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started eventhub-batch-and-persist-route (seda://eventhub-batch-input)
|
||||
2026-05-12T11:23:20.281+02:00 INFO 9580 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started eventhub-direct-batch-persist-route (direct://eventhub-batch-persist-input)
|
||||
2026-05-12T11:23:20.281+02:00 INFO 9580 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started eventhub-package-input-route (direct://eventhub-package-input)
|
||||
2026-05-12T11:23:20.282+02:00 INFO 9580 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started eventhub-manual-input-route (direct://eventhub-manual-input)
|
||||
2026-05-12T11:23:20.282+02:00 INFO 9580 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started telematics-position-input-route (direct://telematics-position-input)
|
||||
2026-05-12T11:23:20.283+02:00 INFO 9580 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started tachograph-activity-input-route (direct://tachograph-activity-input)
|
||||
2026-05-12T11:23:20.284+02:00 INFO 9580 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started tachograph-import-start-route (direct://tachograph-import-start)
|
||||
2026-05-12T11:23:20.286+02:00 INFO 9580 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started yellowfox-d8-booking-input-route (direct://yellowfox-d8-booking-input)
|
||||
2026-05-12T11:23:20.286+02:00 INFO 9580 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started yellowfox-d8-import-start-route (direct://yellowfox-d8-import-start)
|
||||
2026-05-12T11:23:20.286+02:00 INFO 9580 --- [main] o.a.c.impl.engine.AbstractCamelContext : Apache Camel 4.18.2 (camel-1) started in 110ms (build:0ms init:0ms start:110ms boot:7s769ms)
|
||||
2026-05-12T11:23:20.336+02:00 INFO 9580 --- [main] a.p.e.EventHubIngestionApplication : Started EventHubIngestionApplication in 18.093 seconds (process running for 22.74)
|
||||
2026-05-12T11:23:30.575+02:00 INFO 9580 --- [RMI TCP Connection(5)-169.254.53.84] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
|
||||
2026-05-12T11:23:30.576+02:00 INFO 9580 --- [RMI TCP Connection(5)-169.254.53.84] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
|
||||
2026-05-12T11:23:30.590+02:00 INFO 9580 --- [RMI TCP Connection(5)-169.254.53.84] o.s.web.servlet.DispatcherServlet : Completed initialization in 13 ms
|
||||
2026-05-12T11:23:35.926+02:00 INFO 9580 --- [RMI TCP Connection(3)-169.254.53.84] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
|
||||
2026-05-12T11:23:36.395+02:00 INFO 9580 --- [RMI TCP Connection(3)-169.254.53.84] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@1a7ba505
|
||||
2026-05-12T11:23:36.417+02:00 INFO 9580 --- [RMI TCP Connection(3)-169.254.53.84] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
|
||||
2026-05-12T11:23:56.009+02:00 INFO 9580 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-1' version 9.0.0
|
||||
2026-05-12T11:23:58.662+02:00 INFO 9580 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-1'
|
||||
2026-05-12T11:23:58.675+02:00 INFO 9580 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-2' version 9.0.0
|
||||
2026-05-12T11:23:59.023+02:00 INFO 9580 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-2'
|
||||
2026-05-12T11:23:59.045+02:00 INFO 9580 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-operating-period-1' version 9.0.0
|
||||
2026-05-12T11:23:59.127+02:00 INFO 9580 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-operating-period-1'
|
||||
2026-05-12T11:23:59.150+02:00 INFO 9580 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-3' version 9.0.0
|
||||
2026-05-12T11:23:59.212+02:00 INFO 9580 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-3'
|
||||
2026-05-12T11:23:59.216+02:00 INFO 9580 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-4' version 9.0.0
|
||||
2026-05-12T11:23:59.297+02:00 INFO 9580 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-4'
|
||||
2026-05-12T11:23:59.301+02:00 INFO 9580 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-5' version 9.0.0
|
||||
2026-05-12T11:23:59.357+02:00 INFO 9580 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-5'
|
||||
2026-05-12T11:23:59.360+02:00 INFO 9580 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-6' version 9.0.0
|
||||
2026-05-12T11:23:59.409+02:00 INFO 9580 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-6'
|
||||
2026-05-12T11:23:59.412+02:00 INFO 9580 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-7' version 9.0.0
|
||||
2026-05-12T11:23:59.464+02:00 INFO 9580 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-7'
|
||||
2026-05-12T11:23:59.464+02:00 INFO 9580 --- [http-nio-8085-exec-2] a.p.e.e.s.EsperOperatingPeriodEvaluationService : Esper operating-period evaluation tenant=Procon driverId=026598bf-002d-460d-8b06-ccbd05fb46b7 requestedFrom=2026-04-01T00:00Z requestedTo=2026-05-01T00:00Z loadedFrom=2026-03-31T00:00Z loadedTo=2026-05-02T00:00Z unknownMode=AS_BREAK_REST engineMode=STREAM_COLLECTOR rawEvents=708 cardRawEvents=354 vuRawEvents=354 cardIntervals=176 vuIntervals=168 resolvedKnownIntervals=176 evaluationIntervals=113 periodizedIntervals=113 mergedIntervals=113 nonDrivingIntervals=31 operatingPeriods=5 timingsMs={{dbRetrieve=411, cardIntervalEsper=2793, vuIntervalEsper=355, vuGapFill=9, synthUnknown=4, periodizeEsper=93, merge=3, nonDriving=2, total=4001}}
|
||||
2026-05-12T11:24:58.174+02:00 WARN 9580 --- [HikariPool-1:housekeeper] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Thread starvation or clock leap detected (housekeeper delta=49s488ms454µs500ns).
|
||||
2026-05-12T11:26:51.871+02:00 WARN 9580 --- [HikariPool-1:housekeeper] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Thread starvation or clock leap detected (housekeeper delta=1m9s537ms744µs800ns).
|
||||
2026-05-12T11:29:00.780+02:00 WARN 9580 --- [HikariPool-1:housekeeper] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Thread starvation or clock leap detected (housekeeper delta=2m8s908ms981µs900ns).
|
||||
2026-05-12T11:29:00.971+02:00 INFO 9580 --- [SpringApplicationShutdownHook] o.s.boot.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete
|
||||
2026-05-12T11:29:01.419+02:00 INFO 9580 --- [tomcat-shutdown] o.s.boot.tomcat.GracefulShutdown : Graceful shutdown complete
|
||||
2026-05-12T11:29:01.425+02:00 INFO 9580 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Apache Camel 4.18.2 (camel-1) is shutting down (timeout:45s)
|
||||
2026-05-12T11:29:01.857+02:00 INFO 9580 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Routes stopped (total:10)
|
||||
2026-05-12T11:29:01.858+02:00 INFO 9580 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped yellowfox-d8-import-start-route (direct://yellowfox-d8-import-start)
|
||||
2026-05-12T11:29:01.858+02:00 INFO 9580 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped yellowfox-d8-booking-input-route (direct://yellowfox-d8-booking-input)
|
||||
2026-05-12T11:29:01.858+02:00 INFO 9580 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped tachograph-import-start-route (direct://tachograph-import-start)
|
||||
2026-05-12T11:29:01.858+02:00 INFO 9580 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped tachograph-activity-input-route (direct://tachograph-activity-input)
|
||||
2026-05-12T11:29:01.858+02:00 INFO 9580 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped telematics-position-input-route (direct://telematics-position-input)
|
||||
2026-05-12T11:29:01.858+02:00 INFO 9580 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped eventhub-manual-input-route (direct://eventhub-manual-input)
|
||||
2026-05-12T11:29:01.860+02:00 INFO 9580 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped eventhub-package-input-route (direct://eventhub-package-input)
|
||||
2026-05-12T11:29:01.863+02:00 INFO 9580 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped eventhub-direct-batch-persist-route (direct://eventhub-batch-persist-input)
|
||||
2026-05-12T11:29:01.863+02:00 INFO 9580 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped eventhub-batch-and-persist-route (seda://eventhub-batch-input)
|
||||
2026-05-12T11:29:01.863+02:00 INFO 9580 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped eventhub-normalized-input-route (direct://eventhub-normalized-input)
|
||||
2026-05-12T11:29:01.885+02:00 INFO 9580 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Apache Camel 4.18.2 (camel-1) shutdown in 459ms (uptime:5m41s)
|
||||
2026-05-12T11:29:01.998+02:00 INFO 9580 --- [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
|
||||
2026-05-12T11:29:02.548+02:00 INFO 9580 --- [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
|
||||
2026-05-12T11:47:04.173+02:00 INFO 29032 --- [background-preinit] o.h.validator.internal.util.Version : HV000001: Hibernate Validator 9.0.1.Final
|
||||
2026-05-12T11:47:04.534+02:00 INFO 29032 --- [main] a.p.e.EventHubIngestionApplication : Starting EventHubIngestionApplication using Java 21.0.2 with PID 29032 (C:\Work\java\gite\eventhub-spring-boot\eventhub-spring-boot\target\classes started by Parzival in C:\Work\java\gite\eventhub-spring-boot\eventhub-spring-boot)
|
||||
2026-05-12T11:47:04.536+02:00 INFO 29032 --- [main] a.p.e.EventHubIngestionApplication : No active profile set, falling back to 1 default profile: "default"
|
||||
2026-05-12T11:47:08.931+02:00 INFO 29032 --- [main] o.s.boot.tomcat.TomcatWebServer : Tomcat initialized with port 8085 (http)
|
||||
2026-05-12T11:47:08.966+02:00 INFO 29032 --- [main] o.a.coyote.http11.Http11NioProtocol : Initializing ProtocolHandler ["http-nio-8085"]
|
||||
2026-05-12T11:47:08.970+02:00 INFO 29032 --- [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
||||
2026-05-12T11:47:08.970+02:00 INFO 29032 --- [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/11.0.21]
|
||||
2026-05-12T11:47:09.120+02:00 INFO 29032 --- [main] o.s.b.w.c.s.WebApplicationContextInitializer : Root WebApplicationContext: initialization completed in 4466 ms
|
||||
2026-05-12T11:47:12.877+02:00 INFO 29032 --- [main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 4 endpoints beneath base path '/actuator'
|
||||
2026-05-12T11:47:13.064+02:00 INFO 29032 --- [main] o.a.coyote.http11.Http11NioProtocol : Starting ProtocolHandler ["http-nio-8085"]
|
||||
2026-05-12T11:47:13.108+02:00 INFO 29032 --- [main] o.s.boot.tomcat.TomcatWebServer : Tomcat started on port 8085 (http) with context path '/'
|
||||
2026-05-12T11:47:17.510+02:00 INFO 29032 --- [main] o.a.c.impl.engine.AbstractCamelContext : Apache Camel 4.18.2 (camel-1) is starting
|
||||
2026-05-12T11:47:17.593+02:00 INFO 29032 --- [main] o.a.c.p.aggregate.AggregateProcessor : Defaulting to MemoryAggregationRepository
|
||||
2026-05-12T11:47:17.600+02:00 INFO 29032 --- [main] o.a.c.p.aggregate.AggregateProcessor : Using CompletionTimeout to trigger after 5000 millis of inactivity.
|
||||
2026-05-12T11:47:17.646+02:00 INFO 29032 --- [main] o.a.c.impl.engine.AbstractCamelContext : Routes startup (total:10)
|
||||
2026-05-12T11:47:17.646+02:00 INFO 29032 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started eventhub-normalized-input-route (direct://eventhub-normalized-input)
|
||||
2026-05-12T11:47:17.646+02:00 INFO 29032 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started eventhub-batch-and-persist-route (seda://eventhub-batch-input)
|
||||
2026-05-12T11:47:17.646+02:00 INFO 29032 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started eventhub-direct-batch-persist-route (direct://eventhub-batch-persist-input)
|
||||
2026-05-12T11:47:17.646+02:00 INFO 29032 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started eventhub-package-input-route (direct://eventhub-package-input)
|
||||
2026-05-12T11:47:17.647+02:00 INFO 29032 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started eventhub-manual-input-route (direct://eventhub-manual-input)
|
||||
2026-05-12T11:47:17.647+02:00 INFO 29032 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started telematics-position-input-route (direct://telematics-position-input)
|
||||
2026-05-12T11:47:17.648+02:00 INFO 29032 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started tachograph-activity-input-route (direct://tachograph-activity-input)
|
||||
2026-05-12T11:47:17.648+02:00 INFO 29032 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started tachograph-import-start-route (direct://tachograph-import-start)
|
||||
2026-05-12T11:47:17.648+02:00 INFO 29032 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started yellowfox-d8-booking-input-route (direct://yellowfox-d8-booking-input)
|
||||
2026-05-12T11:47:17.648+02:00 INFO 29032 --- [main] o.a.c.impl.engine.AbstractCamelContext : Started yellowfox-d8-import-start-route (direct://yellowfox-d8-import-start)
|
||||
2026-05-12T11:47:17.649+02:00 INFO 29032 --- [main] o.a.c.impl.engine.AbstractCamelContext : Apache Camel 4.18.2 (camel-1) started in 137ms (build:0ms init:0ms start:137ms boot:7s937ms)
|
||||
2026-05-12T11:47:17.672+02:00 INFO 29032 --- [main] a.p.e.EventHubIngestionApplication : Started EventHubIngestionApplication in 15.724 seconds (process running for 19.226)
|
||||
2026-05-12T11:47:22.629+02:00 INFO 29032 --- [RMI TCP Connection(8)-169.254.53.84] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
|
||||
2026-05-12T11:47:22.629+02:00 INFO 29032 --- [RMI TCP Connection(8)-169.254.53.84] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
|
||||
2026-05-12T11:47:22.637+02:00 INFO 29032 --- [RMI TCP Connection(8)-169.254.53.84] o.s.web.servlet.DispatcherServlet : Completed initialization in 7 ms
|
||||
2026-05-12T11:47:28.596+02:00 INFO 29032 --- [RMI TCP Connection(6)-169.254.53.84] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
|
||||
2026-05-12T11:47:29.328+02:00 INFO 29032 --- [RMI TCP Connection(6)-169.254.53.84] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@40294cec
|
||||
2026-05-12T11:47:29.337+02:00 INFO 29032 --- [RMI TCP Connection(6)-169.254.53.84] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
|
||||
2026-05-12T11:47:47.390+02:00 INFO 29032 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-1' version 9.0.0
|
||||
2026-05-12T11:47:50.506+02:00 INFO 29032 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-1'
|
||||
2026-05-12T11:47:50.516+02:00 INFO 29032 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-2' version 9.0.0
|
||||
2026-05-12T11:47:50.761+02:00 INFO 29032 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-2'
|
||||
2026-05-12T11:47:50.785+02:00 INFO 29032 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-operating-period-1' version 9.0.0
|
||||
2026-05-12T11:47:50.874+02:00 INFO 29032 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-operating-period-1'
|
||||
2026-05-12T11:47:50.896+02:00 INFO 29032 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-3' version 9.0.0
|
||||
2026-05-12T11:47:50.961+02:00 INFO 29032 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-3'
|
||||
2026-05-12T11:47:50.968+02:00 INFO 29032 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-4' version 9.0.0
|
||||
2026-05-12T11:47:51.069+02:00 INFO 29032 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-4'
|
||||
2026-05-12T11:47:51.072+02:00 INFO 29032 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-5' version 9.0.0
|
||||
2026-05-12T11:47:51.143+02:00 INFO 29032 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-5'
|
||||
2026-05-12T11:47:51.148+02:00 INFO 29032 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-6' version 9.0.0
|
||||
2026-05-12T11:47:51.233+02:00 INFO 29032 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-6'
|
||||
2026-05-12T11:47:51.238+02:00 INFO 29032 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-7' version 9.0.0
|
||||
2026-05-12T11:47:51.328+02:00 INFO 29032 --- [http-nio-8085-exec-2] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-7'
|
||||
2026-05-12T11:47:51.331+02:00 INFO 29032 --- [http-nio-8085-exec-2] a.p.e.e.s.EsperOperatingPeriodEvaluationService : Esper operating-period evaluation tenant=Procon driverId=026598bf-002d-460d-8b06-ccbd05fb46b7 requestedFrom=2026-04-01T00:00Z requestedTo=2026-05-01T00:00Z loadedFrom=2026-03-31T00:00Z loadedTo=2026-05-02T00:00Z sourceSelectionMode=MIXED unknownMode=AS_BREAK_REST engineMode=STREAM_COLLECTOR rawEvents=708 cardRawEvents=354 vuRawEvents=354 cardIntervals=176 vuIntervals=168 resolvedKnownIntervals=176 evaluationIntervals=113 periodizedIntervals=113 mergedIntervals=113 nonDrivingIntervals=31 operatingPeriods=5 timingsMs={{dbRetrieve=636, cardIntervalEsper=3333, vuIntervalEsper=251, vuGapFill=13, synthUnknown=5, periodizeEsper=96, merge=3, nonDriving=2, total=4792}}
|
||||
2026-05-12T11:50:30.990+02:00 WARN 29032 --- [HikariPool-1:housekeeper] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Thread starvation or clock leap detected (housekeeper delta=2m28s615ms199µs300ns).
|
||||
2026-05-12T11:50:42.829+02:00 INFO 29032 --- [http-nio-8085-exec-4] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-8' version 9.0.0
|
||||
2026-05-12T11:50:43.060+02:00 INFO 29032 --- [http-nio-8085-exec-4] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-8'
|
||||
2026-05-12T11:50:43.065+02:00 INFO 29032 --- [http-nio-8085-exec-4] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-9' version 9.0.0
|
||||
2026-05-12T11:50:43.248+02:00 INFO 29032 --- [http-nio-8085-exec-4] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-9'
|
||||
2026-05-12T11:50:43.257+02:00 INFO 29032 --- [http-nio-8085-exec-4] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-operating-period-2' version 9.0.0
|
||||
2026-05-12T11:50:43.310+02:00 INFO 29032 --- [http-nio-8085-exec-4] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-operating-period-2'
|
||||
2026-05-12T11:50:43.314+02:00 INFO 29032 --- [http-nio-8085-exec-4] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-10' version 9.0.0
|
||||
2026-05-12T11:50:43.364+02:00 INFO 29032 --- [http-nio-8085-exec-4] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-10'
|
||||
2026-05-12T11:50:43.368+02:00 INFO 29032 --- [http-nio-8085-exec-4] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-11' version 9.0.0
|
||||
2026-05-12T11:50:43.418+02:00 INFO 29032 --- [http-nio-8085-exec-4] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-11'
|
||||
2026-05-12T11:50:43.421+02:00 INFO 29032 --- [http-nio-8085-exec-4] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-12' version 9.0.0
|
||||
2026-05-12T11:50:43.471+02:00 INFO 29032 --- [http-nio-8085-exec-4] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-12'
|
||||
2026-05-12T11:50:43.474+02:00 INFO 29032 --- [http-nio-8085-exec-4] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-13' version 9.0.0
|
||||
2026-05-12T11:50:43.537+02:00 INFO 29032 --- [http-nio-8085-exec-4] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-13'
|
||||
2026-05-12T11:50:43.541+02:00 INFO 29032 --- [http-nio-8085-exec-4] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-14' version 9.0.0
|
||||
2026-05-12T11:50:43.590+02:00 INFO 29032 --- [http-nio-8085-exec-4] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-14'
|
||||
2026-05-12T11:50:43.590+02:00 INFO 29032 --- [http-nio-8085-exec-4] a.p.e.e.s.EsperOperatingPeriodEvaluationService : Esper operating-period evaluation tenant=Procon driverId=026598bf-002d-460d-8b06-ccbd05fb46b7 requestedFrom=2026-04-01T00:00Z requestedTo=2026-05-01T00:00Z loadedFrom=2026-03-31T00:00Z loadedTo=2026-05-02T00:00Z sourceSelectionMode=MIXED unknownMode=AS_BREAK_REST engineMode=STREAM_COLLECTOR rawEvents=708 cardRawEvents=354 vuRawEvents=354 cardIntervals=176 vuIntervals=168 resolvedKnownIntervals=176 evaluationIntervals=113 periodizedIntervals=113 mergedIntervals=113 nonDrivingIntervals=31 operatingPeriods=5 timingsMs={{dbRetrieve=25, cardIntervalEsper=236, vuIntervalEsper=189, vuGapFill=3, synthUnknown=2, periodizeEsper=56, merge=1, nonDriving=0, total=790}}
|
||||
2026-05-12T11:51:45.110+02:00 WARN 29032 --- [HikariPool-1:housekeeper] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Thread starvation or clock leap detected (housekeeper delta=1m14s121ms587µs300ns).
|
||||
2026-05-12T11:52:29.604+02:00 INFO 29032 --- [http-nio-8085-exec-7] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-15' version 9.0.0
|
||||
2026-05-12T11:52:29.671+02:00 INFO 29032 --- [SpringApplicationShutdownHook] o.s.boot.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete
|
||||
2026-05-12T11:52:29.787+02:00 INFO 29032 --- [http-nio-8085-exec-7] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-15'
|
||||
2026-05-12T11:52:29.789+02:00 INFO 29032 --- [http-nio-8085-exec-7] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-16' version 9.0.0
|
||||
2026-05-12T11:52:29.991+02:00 INFO 29032 --- [http-nio-8085-exec-7] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-16'
|
||||
2026-05-12T11:52:29.995+02:00 INFO 29032 --- [http-nio-8085-exec-7] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-operating-period-3' version 9.0.0
|
||||
2026-05-12T11:52:30.034+02:00 INFO 29032 --- [http-nio-8085-exec-7] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-operating-period-3'
|
||||
2026-05-12T11:52:30.038+02:00 INFO 29032 --- [http-nio-8085-exec-7] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-17' version 9.0.0
|
||||
2026-05-12T11:52:30.072+02:00 INFO 29032 --- [http-nio-8085-exec-7] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-17'
|
||||
2026-05-12T11:52:30.073+02:00 INFO 29032 --- [http-nio-8085-exec-7] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-18' version 9.0.0
|
||||
2026-05-12T11:52:30.102+02:00 INFO 29032 --- [http-nio-8085-exec-7] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-18'
|
||||
2026-05-12T11:52:30.104+02:00 INFO 29032 --- [http-nio-8085-exec-7] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-19' version 9.0.0
|
||||
2026-05-12T11:52:30.130+02:00 INFO 29032 --- [http-nio-8085-exec-7] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-19'
|
||||
2026-05-12T11:52:30.132+02:00 INFO 29032 --- [http-nio-8085-exec-7] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-20' version 9.0.0
|
||||
2026-05-12T11:52:30.171+02:00 INFO 29032 --- [http-nio-8085-exec-7] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-20'
|
||||
2026-05-12T11:52:30.176+02:00 INFO 29032 --- [http-nio-8085-exec-7] c.e.e.r.i.kernel.service.EPRuntimeImpl : Initializing runtime URI 'eventhub-esper-poc-21' version 9.0.0
|
||||
2026-05-12T11:52:30.406+02:00 INFO 29032 --- [http-nio-8085-exec-7] c.e.e.r.i.kernel.service.EPRuntimeImpl : Destroying runtime URI 'eventhub-esper-poc-21'
|
||||
2026-05-12T11:52:30.408+02:00 INFO 29032 --- [http-nio-8085-exec-7] a.p.e.e.s.EsperOperatingPeriodEvaluationService : Esper operating-period evaluation tenant=Procon driverId=026598bf-002d-460d-8b06-ccbd05fb46b7 requestedFrom=2026-04-01T00:00Z requestedTo=2026-05-01T00:00Z loadedFrom=2026-03-31T00:00Z loadedTo=2026-05-02T00:00Z sourceSelectionMode=MIXED unknownMode=AS_BREAK_REST engineMode=STREAM_COLLECTOR rawEvents=708 cardRawEvents=354 vuRawEvents=354 cardIntervals=176 vuIntervals=168 resolvedKnownIntervals=176 evaluationIntervals=113 periodizedIntervals=113 mergedIntervals=113 nonDrivingIntervals=31 operatingPeriods=5 timingsMs={{dbRetrieve=39, cardIntervalEsper=186, vuIntervalEsper=203, vuGapFill=2, synthUnknown=1, periodizeEsper=41, merge=0, nonDriving=0, total=845}}
|
||||
2026-05-12T11:52:30.449+02:00 INFO 29032 --- [tomcat-shutdown] o.s.boot.tomcat.GracefulShutdown : Graceful shutdown complete
|
||||
2026-05-12T11:52:30.458+02:00 INFO 29032 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Apache Camel 4.18.2 (camel-1) is shutting down (timeout:45s)
|
||||
2026-05-12T11:52:30.590+02:00 INFO 29032 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Routes stopped (total:10)
|
||||
2026-05-12T11:52:30.591+02:00 INFO 29032 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped yellowfox-d8-import-start-route (direct://yellowfox-d8-import-start)
|
||||
2026-05-12T11:52:30.591+02:00 INFO 29032 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped yellowfox-d8-booking-input-route (direct://yellowfox-d8-booking-input)
|
||||
2026-05-12T11:52:30.591+02:00 INFO 29032 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped tachograph-import-start-route (direct://tachograph-import-start)
|
||||
2026-05-12T11:52:30.591+02:00 INFO 29032 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped tachograph-activity-input-route (direct://tachograph-activity-input)
|
||||
2026-05-12T11:52:30.591+02:00 INFO 29032 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped telematics-position-input-route (direct://telematics-position-input)
|
||||
2026-05-12T11:52:30.591+02:00 INFO 29032 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped eventhub-manual-input-route (direct://eventhub-manual-input)
|
||||
2026-05-12T11:52:30.591+02:00 INFO 29032 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped eventhub-package-input-route (direct://eventhub-package-input)
|
||||
2026-05-12T11:52:30.591+02:00 INFO 29032 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped eventhub-direct-batch-persist-route (direct://eventhub-batch-persist-input)
|
||||
2026-05-12T11:52:30.591+02:00 INFO 29032 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped eventhub-batch-and-persist-route (seda://eventhub-batch-input)
|
||||
2026-05-12T11:52:30.591+02:00 INFO 29032 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Stopped eventhub-normalized-input-route (direct://eventhub-normalized-input)
|
||||
2026-05-12T11:52:30.599+02:00 INFO 29032 --- [SpringApplicationShutdownHook] o.a.c.impl.engine.AbstractCamelContext : Apache Camel 4.18.2 (camel-1) shutdown in 140ms (uptime:5m13s)
|
||||
2026-05-12T11:52:30.611+02:00 INFO 29032 --- [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
|
||||
2026-05-12T11:52:30.615+02:00 INFO 29032 --- [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
|
||||
|
|
@ -11,6 +11,8 @@ import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionListDri
|
|||
import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionSummaryDto;
|
||||
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionProcessingService;
|
||||
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionService;
|
||||
import at.procon.eventhub.tachographfilesession.dto.TachographUploadWorkflowResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import java.util.UUID;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
|
@ -44,10 +46,21 @@ public class TachographFileSessionController {
|
|||
@RequestParam("file") MultipartFile file,
|
||||
@RequestParam(required = false) String tenantKey,
|
||||
@RequestParam(required = false) String sourceInstanceKey,
|
||||
@RequestParam(required = false) String sessionLabel
|
||||
@RequestParam(required = false) String sessionLabel,
|
||||
HttpSession webSession
|
||||
) {
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(service.createSession(file, tenantKey, sourceInstanceKey, sessionLabel));
|
||||
.body(service.createSession(file, tenantKey, sourceInstanceKey, sessionLabel, webSession));
|
||||
}
|
||||
|
||||
@PostMapping("/workflow/reset")
|
||||
public ResponseEntity<TachographUploadWorkflowResponse> resetUploadWorkflow(HttpSession webSession) {
|
||||
return ResponseEntity.ok(service.resetUploadWorkflow(webSession));
|
||||
}
|
||||
|
||||
@GetMapping("/workflow")
|
||||
public ResponseEntity<TachographUploadWorkflowResponse> getUploadWorkflow(HttpSession webSession) {
|
||||
return ResponseEntity.ok(service.getUploadWorkflow(webSession));
|
||||
}
|
||||
|
||||
@GetMapping("/{sessionId}")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
package at.procon.eventhub.tachographfilesession.dto;
|
||||
|
||||
public record CreateTachographFileSessionResponse(
|
||||
TachographFileSessionSummaryDto session
|
||||
TachographFileSessionSummaryDto session,
|
||||
TachographUploadWorkflowDto workflow,
|
||||
TachographCompositeSessionSummaryDto compositeSession
|
||||
) {
|
||||
|
||||
public CreateTachographFileSessionResponse(TachographFileSessionSummaryDto session) {
|
||||
this(session, null, null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
package at.procon.eventhub.tachographfilesession.dto;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public record TachographUploadWorkflowDto(
|
||||
boolean driverCardUploaded,
|
||||
UUID driverCardSessionId,
|
||||
List<UUID> uploadedSessionIds,
|
||||
List<UUID> vehicleUnitSessionIds,
|
||||
UUID compositeSessionId
|
||||
) {
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package at.procon.eventhub.tachographfilesession.dto;
|
||||
|
||||
public record TachographUploadWorkflowResponse(
|
||||
TachographUploadWorkflowDto workflow
|
||||
) {
|
||||
}
|
||||
|
|
@ -28,10 +28,8 @@ public class LegalRequirementsClient {
|
|||
|
||||
public LegalRequirementsUploadResult uploadTachographFile(byte[] fileBytes, String fileName) {
|
||||
EventHubProperties.LegalRequirements config = properties.getTachographFileSession().getLegalRequirements();
|
||||
HttpClient client = HttpClient.newBuilder()
|
||||
.connectTimeout(config.getConnectTimeout())
|
||||
.cookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ALL))
|
||||
.build();
|
||||
CookieManager cookieManager = newCookieManager();
|
||||
HttpClient client = httpClient(config, cookieManager);
|
||||
try {
|
||||
String dataPackageId = uploadDataPackage(client, config, fileBytes, fileName);
|
||||
String xml = downloadXml(client, config, dataPackageId);
|
||||
|
|
@ -43,6 +41,23 @@ public class LegalRequirementsClient {
|
|||
}
|
||||
}
|
||||
|
||||
public LegalRequirementsUploadResult uploadTachographFile(CookieManager cookieManager, byte[] fileBytes, String fileName) {
|
||||
EventHubProperties.LegalRequirements config = properties.getTachographFileSession().getLegalRequirements();
|
||||
HttpClient client = httpClient(config, cookieManager);
|
||||
String dataPackageId = uploadDataPackage(client, config, fileBytes, fileName);
|
||||
String xml = downloadXml(client, config, dataPackageId);
|
||||
return new LegalRequirementsUploadResult(dataPackageId, xml);
|
||||
}
|
||||
|
||||
public void resetSession(CookieManager cookieManager) {
|
||||
EventHubProperties.LegalRequirements config = properties.getTachographFileSession().getLegalRequirements();
|
||||
resetSessionQuietly(httpClient(config, cookieManager), config);
|
||||
}
|
||||
|
||||
public CookieManager newCookieManager() {
|
||||
return new CookieManager(null, CookiePolicy.ACCEPT_ALL);
|
||||
}
|
||||
|
||||
private String uploadDataPackage(HttpClient client, EventHubProperties.LegalRequirements config, byte[] fileBytes, String fileName) {
|
||||
try {
|
||||
String payload = objectMapper.createObjectNode()
|
||||
|
|
@ -115,6 +130,13 @@ public class LegalRequirementsClient {
|
|||
return HttpRequest.newBuilder(URI.create(url)).timeout(timeout);
|
||||
}
|
||||
|
||||
private HttpClient httpClient(EventHubProperties.LegalRequirements config, CookieManager cookieManager) {
|
||||
return HttpClient.newBuilder()
|
||||
.connectTimeout(config.getConnectTimeout())
|
||||
.cookieHandler(cookieManager == null ? newCookieManager() : cookieManager)
|
||||
.build();
|
||||
}
|
||||
|
||||
private String basicAuth(EventHubProperties.LegalRequirements config) {
|
||||
String user = config.getUsername() == null ? "" : config.getUsername();
|
||||
String password = config.getPassword() == null ? "" : config.getPassword();
|
||||
|
|
|
|||
|
|
@ -56,10 +56,20 @@ public class TachographCompositeSessionService {
|
|||
}
|
||||
|
||||
public CreateTachographCompositeSessionResponse createCompositeSession(CreateTachographCompositeSessionRequest request) {
|
||||
if (request == null || request.sessionIds() == null || request.sessionIds().isEmpty()) {
|
||||
return new CreateTachographCompositeSessionResponse(
|
||||
upsertCompositeSession(null, request == null ? null : request.sessionIds(), request == null ? null : request.label())
|
||||
);
|
||||
}
|
||||
|
||||
public TachographCompositeSessionSummaryDto upsertCompositeSession(
|
||||
UUID compositeSessionId,
|
||||
List<UUID> requestedSessionIds,
|
||||
String label
|
||||
) {
|
||||
if (requestedSessionIds == null || requestedSessionIds.isEmpty()) {
|
||||
throw new IllegalArgumentException("sessionIds must not be empty.");
|
||||
}
|
||||
List<UUID> memberSessionIds = request.sessionIds().stream()
|
||||
List<UUID> memberSessionIds = requestedSessionIds.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.toList();
|
||||
|
|
@ -72,14 +82,20 @@ public class TachographCompositeSessionService {
|
|||
.filter(value -> value != null && !value.isBlank())
|
||||
.findFirst()
|
||||
.orElse("default");
|
||||
UUID id = compositeSessionId == null ? UUID.randomUUID() : compositeSessionId;
|
||||
Instant createdAt = compositeSessionId == null
|
||||
? Instant.now()
|
||||
: compositeRepository.find(compositeSessionId)
|
||||
.map(TachographCompositeSession::createdAt)
|
||||
.orElseGet(Instant::now);
|
||||
TachographCompositeSession compositeSession = compositeRepository.save(new TachographCompositeSession(
|
||||
UUID.randomUUID(),
|
||||
id,
|
||||
tenantKey,
|
||||
blankToNull(request.label()),
|
||||
blankToNull(label),
|
||||
memberSessionIds,
|
||||
Instant.now()
|
||||
createdAt
|
||||
));
|
||||
return new CreateTachographCompositeSessionResponse(toSummary(compositeSession, sessions));
|
||||
return toSummary(compositeSession, sessions);
|
||||
}
|
||||
|
||||
public TachographCompositeSessionSummaryDto getCompositeSession(UUID compositeSessionId) {
|
||||
|
|
|
|||
|
|
@ -2,14 +2,18 @@ package at.procon.eventhub.tachographfilesession.service;
|
|||
|
||||
import at.procon.eventhub.config.EventHubProperties;
|
||||
import at.procon.eventhub.tachographfilesession.dto.CreateTachographFileSessionResponse;
|
||||
import at.procon.eventhub.tachographfilesession.dto.TachographCompositeSessionSummaryDto;
|
||||
import at.procon.eventhub.tachographfilesession.dto.TachographFileDriverDetailDto;
|
||||
import at.procon.eventhub.tachographfilesession.dto.TachographFileDriverSummaryDto;
|
||||
import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionDeleteResponse;
|
||||
import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionListDriversResponse;
|
||||
import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionSummaryDto;
|
||||
import at.procon.eventhub.tachographfilesession.dto.TachographUploadWorkflowResponse;
|
||||
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographFileSessionMetadata;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import java.net.CookieManager;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
|
@ -27,9 +31,14 @@ import org.springframework.web.multipart.MultipartFile;
|
|||
public class TachographFileSessionService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(TachographFileSessionService.class);
|
||||
private static final String LEGAL_REQUIREMENTS_COOKIE_MANAGER_ATTRIBUTE =
|
||||
TachographFileSessionService.class.getName() + ".legalRequirementsCookieManager";
|
||||
private static final String WORKFLOW_STATE_ATTRIBUTE =
|
||||
TachographFileSessionService.class.getName() + ".uploadWorkflowState";
|
||||
|
||||
private final EventHubProperties properties;
|
||||
private final TachographFileSessionRepository repository;
|
||||
private final TachographCompositeSessionService compositeSessionService;
|
||||
private final LegalRequirementsClient legalRequirementsClient;
|
||||
private final TachographXmlParser tachographXmlParser;
|
||||
private final DriverCardXmlExtractionService driverCardExtractionService;
|
||||
|
|
@ -38,6 +47,7 @@ public class TachographFileSessionService {
|
|||
public TachographFileSessionService(
|
||||
EventHubProperties properties,
|
||||
TachographFileSessionRepository repository,
|
||||
TachographCompositeSessionService compositeSessionService,
|
||||
LegalRequirementsClient legalRequirementsClient,
|
||||
TachographXmlParser tachographXmlParser,
|
||||
DriverCardXmlExtractionService driverCardExtractionService,
|
||||
|
|
@ -45,6 +55,7 @@ public class TachographFileSessionService {
|
|||
) {
|
||||
this.properties = properties;
|
||||
this.repository = repository;
|
||||
this.compositeSessionService = compositeSessionService;
|
||||
this.legalRequirementsClient = legalRequirementsClient;
|
||||
this.tachographXmlParser = tachographXmlParser;
|
||||
this.driverCardExtractionService = driverCardExtractionService;
|
||||
|
|
@ -55,14 +66,21 @@ public class TachographFileSessionService {
|
|||
MultipartFile file,
|
||||
String tenantKey,
|
||||
String sourceInstanceKey,
|
||||
String sessionLabel
|
||||
String sessionLabel,
|
||||
HttpSession webSession
|
||||
) {
|
||||
try {
|
||||
if (webSession == null) {
|
||||
throw new IllegalArgumentException("HTTP session is required for tachograph upload workflow.");
|
||||
}
|
||||
validateFile(file);
|
||||
byte[] fileBytes = file.getBytes();
|
||||
validateFileBytes(fileBytes);
|
||||
CookieManager cookieManager = cookieManager(webSession);
|
||||
TachographUploadWorkflowState workflowState = workflowState(webSession);
|
||||
long uploadStartedAt = System.nanoTime();
|
||||
LegalRequirementsUploadResult uploadResult = legalRequirementsClient.uploadTachographFile(fileBytes, file.getOriginalFilename());
|
||||
LegalRequirementsUploadResult uploadResult =
|
||||
legalRequirementsClient.uploadTachographFile(cookieManager, fileBytes, file.getOriginalFilename());
|
||||
long uploadDurationMs = elapsedMillis(uploadStartedAt);
|
||||
|
||||
long parseStartedAt = System.nanoTime();
|
||||
|
|
@ -72,6 +90,7 @@ public class TachographFileSessionService {
|
|||
Instant createdAt = Instant.now();
|
||||
Instant expiresAt = createdAt.plus(properties.getTachographFileSession().getTtl());
|
||||
boolean driverCardFile = "DriverCard".equals(parsedXml.rootElementName());
|
||||
validateWorkflowSequence(webSession, workflowState, cookieManager, driverCardFile);
|
||||
TachographFileSessionMetadata metadata = new TachographFileSessionMetadata(
|
||||
tenant(tenantKey),
|
||||
sourceInstance(sourceInstanceKey, driverCardFile),
|
||||
|
|
@ -100,7 +119,10 @@ public class TachographFileSessionService {
|
|||
fileBytes.length
|
||||
);
|
||||
TachographFileSession saved = repository.save(session);
|
||||
return new CreateTachographFileSessionResponse(toSummary(saved));
|
||||
workflowState.recordUploadedSession(saved.sessionId(), driverCardFile);
|
||||
TachographCompositeSessionSummaryDto compositeSession = updateCompositeSession(workflowState, sessionLabel);
|
||||
webSession.setAttribute(WORKFLOW_STATE_ATTRIBUTE, workflowState);
|
||||
return new CreateTachographFileSessionResponse(toSummary(saved), workflowState.toDto(), compositeSession);
|
||||
} catch (Exception e) {
|
||||
if (e instanceof RuntimeException runtimeException) {
|
||||
throw runtimeException;
|
||||
|
|
@ -109,6 +131,27 @@ public class TachographFileSessionService {
|
|||
}
|
||||
}
|
||||
|
||||
public TachographUploadWorkflowResponse resetUploadWorkflow(HttpSession webSession) {
|
||||
if (webSession == null) {
|
||||
throw new IllegalArgumentException("HTTP session is required for tachograph upload workflow.");
|
||||
}
|
||||
CookieManager existingCookieManager = existingCookieManager(webSession);
|
||||
if (existingCookieManager != null) {
|
||||
legalRequirementsClient.resetSession(existingCookieManager);
|
||||
}
|
||||
webSession.setAttribute(LEGAL_REQUIREMENTS_COOKIE_MANAGER_ATTRIBUTE, legalRequirementsClient.newCookieManager());
|
||||
TachographUploadWorkflowState state = new TachographUploadWorkflowState();
|
||||
webSession.setAttribute(WORKFLOW_STATE_ATTRIBUTE, state);
|
||||
return new TachographUploadWorkflowResponse(state.toDto());
|
||||
}
|
||||
|
||||
public TachographUploadWorkflowResponse getUploadWorkflow(HttpSession webSession) {
|
||||
if (webSession == null) {
|
||||
throw new IllegalArgumentException("HTTP session is required for tachograph upload workflow.");
|
||||
}
|
||||
return new TachographUploadWorkflowResponse(workflowState(webSession).toDto());
|
||||
}
|
||||
|
||||
public TachographFileSessionSummaryDto getSession(UUID sessionId) {
|
||||
return toSummary(requireSession(sessionId));
|
||||
}
|
||||
|
|
@ -146,6 +189,27 @@ public class TachographFileSessionService {
|
|||
return repository.find(sessionId).orElseThrow(() -> new TachographFileSessionNotFoundException(sessionId));
|
||||
}
|
||||
|
||||
private TachographCompositeSessionSummaryDto updateCompositeSession(
|
||||
TachographUploadWorkflowState workflowState,
|
||||
String sessionLabel
|
||||
) {
|
||||
if (workflowState.uploadedSessionIds().size() < 2) {
|
||||
return null;
|
||||
}
|
||||
TachographCompositeSessionSummaryDto compositeSession = compositeSessionService.upsertCompositeSession(
|
||||
workflowState.compositeSessionId(),
|
||||
workflowState.uploadedSessionIds(),
|
||||
compositeSessionLabel(sessionLabel)
|
||||
);
|
||||
workflowState.compositeSessionId(compositeSession.compositeSessionId());
|
||||
return compositeSession;
|
||||
}
|
||||
|
||||
private String compositeSessionLabel(String sessionLabel) {
|
||||
String normalizedLabel = blankToNull(sessionLabel);
|
||||
return normalizedLabel == null ? "tachograph-upload-workflow" : normalizedLabel;
|
||||
}
|
||||
|
||||
private TachographFileSessionSummaryDto toSummary(TachographFileSession session) {
|
||||
return new TachographFileSessionSummaryDto(
|
||||
session.sessionId(),
|
||||
|
|
@ -207,6 +271,63 @@ public class TachographFileSessionService {
|
|||
return driverCardFile ? "legalrequirements-drivercard" : "legalrequirements-vehicleunit";
|
||||
}
|
||||
|
||||
private void validateWorkflowSequence(
|
||||
HttpSession webSession,
|
||||
TachographUploadWorkflowState workflowState,
|
||||
CookieManager cookieManager,
|
||||
boolean driverCardFile
|
||||
) {
|
||||
try {
|
||||
validateWorkflowSequenceInternal(workflowState, driverCardFile);
|
||||
} catch (IllegalArgumentException exception) {
|
||||
resetWorkflowState(webSession, cookieManager);
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
private void validateWorkflowSequenceInternal(TachographUploadWorkflowState workflowState, boolean driverCardFile) {
|
||||
if (!workflowState.driverCardUploaded() && !workflowState.uploadedSessionIds().isEmpty() && driverCardFile) {
|
||||
throw new IllegalArgumentException("Workflow already contains uploaded files. Reset the workflow before starting a new driver card import.");
|
||||
}
|
||||
if (!workflowState.driverCardUploaded() && !driverCardFile) {
|
||||
throw new IllegalArgumentException("Driver card file must be uploaded first after workflow reset.");
|
||||
}
|
||||
if (workflowState.driverCardUploaded() && driverCardFile) {
|
||||
throw new IllegalArgumentException("Workflow already contains a driver card file. Upload vehicle-unit files next or reset the workflow.");
|
||||
}
|
||||
}
|
||||
|
||||
private CookieManager cookieManager(HttpSession webSession) {
|
||||
CookieManager existing = existingCookieManager(webSession);
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
}
|
||||
CookieManager created = legalRequirementsClient.newCookieManager();
|
||||
webSession.setAttribute(LEGAL_REQUIREMENTS_COOKIE_MANAGER_ATTRIBUTE, created);
|
||||
return created;
|
||||
}
|
||||
|
||||
private CookieManager existingCookieManager(HttpSession webSession) {
|
||||
Object value = webSession.getAttribute(LEGAL_REQUIREMENTS_COOKIE_MANAGER_ATTRIBUTE);
|
||||
return value instanceof CookieManager cookieManager ? cookieManager : null;
|
||||
}
|
||||
|
||||
private TachographUploadWorkflowState workflowState(HttpSession webSession) {
|
||||
Object value = webSession.getAttribute(WORKFLOW_STATE_ATTRIBUTE);
|
||||
if (value instanceof TachographUploadWorkflowState state) {
|
||||
return state;
|
||||
}
|
||||
TachographUploadWorkflowState state = new TachographUploadWorkflowState();
|
||||
webSession.setAttribute(WORKFLOW_STATE_ATTRIBUTE, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
private void resetWorkflowState(HttpSession webSession, CookieManager cookieManager) {
|
||||
legalRequirementsClient.resetSession(cookieManager);
|
||||
webSession.setAttribute(LEGAL_REQUIREMENTS_COOKIE_MANAGER_ATTRIBUTE, legalRequirementsClient.newCookieManager());
|
||||
webSession.setAttribute(WORKFLOW_STATE_ATTRIBUTE, new TachographUploadWorkflowState());
|
||||
}
|
||||
|
||||
private String blankToNull(String value) {
|
||||
return value == null || value.isBlank() ? null : value.trim();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
package at.procon.eventhub.tachographfilesession.service;
|
||||
|
||||
import at.procon.eventhub.tachographfilesession.dto.TachographUploadWorkflowDto;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
final class TachographUploadWorkflowState {
|
||||
|
||||
private UUID driverCardSessionId;
|
||||
private final List<UUID> uploadedSessionIds = new ArrayList<>();
|
||||
private final List<UUID> vehicleUnitSessionIds = new ArrayList<>();
|
||||
private UUID compositeSessionId;
|
||||
|
||||
boolean driverCardUploaded() {
|
||||
return driverCardSessionId != null;
|
||||
}
|
||||
|
||||
UUID driverCardSessionId() {
|
||||
return driverCardSessionId;
|
||||
}
|
||||
|
||||
List<UUID> uploadedSessionIds() {
|
||||
return List.copyOf(uploadedSessionIds);
|
||||
}
|
||||
|
||||
List<UUID> vehicleUnitSessionIds() {
|
||||
return List.copyOf(vehicleUnitSessionIds);
|
||||
}
|
||||
|
||||
UUID compositeSessionId() {
|
||||
return compositeSessionId;
|
||||
}
|
||||
|
||||
void recordUploadedSession(UUID sessionId, boolean driverCardFile) {
|
||||
uploadedSessionIds.add(sessionId);
|
||||
if (driverCardFile) {
|
||||
driverCardSessionId = sessionId;
|
||||
return;
|
||||
}
|
||||
vehicleUnitSessionIds.add(sessionId);
|
||||
}
|
||||
|
||||
void compositeSessionId(UUID compositeSessionId) {
|
||||
this.compositeSessionId = compositeSessionId;
|
||||
}
|
||||
|
||||
TachographUploadWorkflowDto toDto() {
|
||||
return new TachographUploadWorkflowDto(
|
||||
driverCardUploaded(),
|
||||
driverCardSessionId,
|
||||
uploadedSessionIds(),
|
||||
vehicleUnitSessionIds(),
|
||||
compositeSessionId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,10 @@ import java.io.ByteArrayInputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.HexFormat;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
|
@ -21,6 +25,9 @@ import org.xml.sax.SAXException;
|
|||
public class TachographXmlParser {
|
||||
|
||||
private static final String JAXP_MAX_OCCUR_LIMIT = "http://www.oracle.com/xml/jaxp/properties/maxOccurLimit";
|
||||
private static final Pattern MANUFACTURER_SPECIFIC_ERROR_CODE_PATTERN = Pattern.compile(
|
||||
"(<manufacturerSpecificErrorCode>)([^<\\s]+)(</manufacturerSpecificErrorCode>)"
|
||||
);
|
||||
|
||||
private final Schema schema;
|
||||
|
||||
|
|
@ -62,11 +69,45 @@ public class TachographXmlParser {
|
|||
}
|
||||
}
|
||||
|
||||
private String normalizeXmlContent(String xmlContent) {
|
||||
String normalizeXmlContent(String xmlContent) {
|
||||
if (xmlContent == null || xmlContent.isEmpty()) {
|
||||
return xmlContent;
|
||||
}
|
||||
return xmlContent.charAt(0) == '\uFEFF' ? xmlContent.substring(1) : xmlContent;
|
||||
String normalized = xmlContent.charAt(0) == '\uFEFF' ? xmlContent.substring(1) : xmlContent;
|
||||
return normalizeManufacturerSpecificErrorCodes(normalized);
|
||||
}
|
||||
|
||||
private String normalizeManufacturerSpecificErrorCodes(String xmlContent) {
|
||||
Matcher matcher = MANUFACTURER_SPECIFIC_ERROR_CODE_PATTERN.matcher(xmlContent);
|
||||
StringBuffer normalized = new StringBuffer(xmlContent.length());
|
||||
while (matcher.find()) {
|
||||
String rawValue = matcher.group(2);
|
||||
String replacementValue = normalizeThreeByteOctetString(rawValue);
|
||||
matcher.appendReplacement(
|
||||
normalized,
|
||||
Matcher.quoteReplacement(matcher.group(1) + replacementValue + matcher.group(3))
|
||||
);
|
||||
}
|
||||
matcher.appendTail(normalized);
|
||||
return normalized.toString();
|
||||
}
|
||||
|
||||
private String normalizeThreeByteOctetString(String rawValue) {
|
||||
if (rawValue == null || rawValue.isBlank()) {
|
||||
return rawValue;
|
||||
}
|
||||
if (rawValue.matches("(?i)[0-9a-f]{6}")) {
|
||||
return rawValue.toUpperCase();
|
||||
}
|
||||
try {
|
||||
byte[] decoded = Base64.getDecoder().decode(rawValue);
|
||||
if (decoded.length == 3) {
|
||||
return HexFormat.of().formatHex(decoded).toUpperCase();
|
||||
}
|
||||
return rawValue;
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
return rawValue;
|
||||
}
|
||||
}
|
||||
|
||||
private Schema loadSchema() {
|
||||
|
|
|
|||
|
|
@ -226,90 +226,122 @@ public class VehicleUnitXmlExtractionService {
|
|||
VehicleContext vehicleContext,
|
||||
List<ExtractionWarning> warnings
|
||||
) {
|
||||
NodeList dayRecords = nodes(document, "/VehicleUnit/Activities/vuActivityDailyData");
|
||||
if (dayRecords.getLength() == 0) {
|
||||
NodeList activitySections = nodes(document, "/VehicleUnit/Activities");
|
||||
if (activitySections.getLength() == 0) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
LocalDate startDate = vehicleContext.defaultActivityStartDate();
|
||||
if (startDate == null) {
|
||||
warnings.add(new ExtractionWarning(
|
||||
"VU_ACTIVITY_DATE_INFERENCE_FAILED",
|
||||
"Vehicle-unit activity daily data is present but no base date could be inferred from the VU downloadable period.",
|
||||
"/VehicleUnit/Activities/vuActivityDailyData"
|
||||
));
|
||||
return List.of();
|
||||
}
|
||||
|
||||
LocalDate maxDate = vehicleContext.defaultActivityEndDate();
|
||||
if (maxDate != null) {
|
||||
LocalDate inferredEndDate = startDate.plusDays(dayRecords.getLength() - 1L);
|
||||
if (inferredEndDate.isAfter(maxDate)) {
|
||||
warnings.add(new ExtractionWarning(
|
||||
"VU_ACTIVITY_DATE_INFERENCE_RANGE",
|
||||
"Vehicle-unit activity daily records exceed the VU downloadable-period range when mapped by sequence order.",
|
||||
"/VehicleUnit/Activities/vuActivityDailyData"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
List<ExtractedCardActivityInterval> intervals = new ArrayList<>();
|
||||
int intervalNo = 0;
|
||||
for (int dayIndex = 0; dayIndex < dayRecords.getLength(); dayIndex++) {
|
||||
Element dayRecord = (Element) dayRecords.item(dayIndex);
|
||||
LocalDate date = startDate.plusDays(dayIndex);
|
||||
String dayPath = "/VehicleUnit/Activities[" + (dayIndex + 1) + "]/vuActivityDailyData";
|
||||
NodeList changes = nodes(dayRecord, "activityChangeInfos");
|
||||
List<ActivityChange> parsedChanges = new ArrayList<>();
|
||||
for (int changeIndex = 0; changeIndex < changes.getLength(); changeIndex++) {
|
||||
Element change = (Element) changes.item(changeIndex);
|
||||
OffsetDateTime from = combine(date, text(change, "timeOfChange"));
|
||||
if (from == null) {
|
||||
warnings.add(new ExtractionWarning(
|
||||
"INVALID_VU_ACTIVITY_CHANGE_TIME",
|
||||
"Vehicle-unit activity change has invalid timeOfChange.",
|
||||
int fallbackDayIndex = 0;
|
||||
for (int activityIndex = 0; activityIndex < activitySections.getLength(); activityIndex++) {
|
||||
Element activities = (Element) activitySections.item(activityIndex);
|
||||
NodeList dayRecords = nodes(activities, "vuActivityDailyData");
|
||||
for (int dayIndex = 0; dayIndex < dayRecords.getLength(); dayIndex++) {
|
||||
Element dayRecord = (Element) dayRecords.item(dayIndex);
|
||||
String dayPath = dayRecords.getLength() == 1
|
||||
? "/VehicleUnit/Activities[" + (activityIndex + 1) + "]/vuActivityDailyData"
|
||||
: "/VehicleUnit/Activities[" + (activityIndex + 1) + "]/vuActivityDailyData[" + (dayIndex + 1) + "]";
|
||||
LocalDate date = resolveActivityDate(
|
||||
activities,
|
||||
vehicleContext,
|
||||
activityIndex,
|
||||
fallbackDayIndex + dayIndex,
|
||||
dayPath,
|
||||
warnings
|
||||
);
|
||||
if (date == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NodeList changes = nodes(dayRecord, "activityChangeInfos");
|
||||
List<ActivityChange> parsedChanges = new ArrayList<>();
|
||||
for (int changeIndex = 0; changeIndex < changes.getLength(); changeIndex++) {
|
||||
Element change = (Element) changes.item(changeIndex);
|
||||
OffsetDateTime from = combine(date, text(change, "timeOfChange"));
|
||||
if (from == null) {
|
||||
warnings.add(new ExtractionWarning(
|
||||
"INVALID_VU_ACTIVITY_CHANGE_TIME",
|
||||
"Vehicle-unit activity change has invalid timeOfChange.",
|
||||
dayPath + "/activityChangeInfos[" + (changeIndex + 1) + "]"
|
||||
));
|
||||
continue;
|
||||
}
|
||||
parsedChanges.add(new ActivityChange(
|
||||
from,
|
||||
normalizeActivity(text(change, "activity")),
|
||||
normalizeToken(text(change, "slot")),
|
||||
normalizeToken(text(change, "cardStatus")),
|
||||
normalizeToken(text(change, "drivingStatus")),
|
||||
dayPath + "/activityChangeInfos[" + (changeIndex + 1) + "]"
|
||||
));
|
||||
continue;
|
||||
}
|
||||
parsedChanges.add(new ActivityChange(
|
||||
from,
|
||||
normalizeActivity(text(change, "activity")),
|
||||
normalizeToken(text(change, "slot")),
|
||||
normalizeToken(text(change, "cardStatus")),
|
||||
normalizeToken(text(change, "drivingStatus")),
|
||||
dayPath + "/activityChangeInfos[" + (changeIndex + 1) + "]"
|
||||
));
|
||||
}
|
||||
parsedChanges.sort(Comparator.comparing(ActivityChange::from));
|
||||
for (int i = 0; i < parsedChanges.size(); i++) {
|
||||
ActivityChange current = parsedChanges.get(i);
|
||||
OffsetDateTime to = i + 1 < parsedChanges.size()
|
||||
? parsedChanges.get(i + 1).from()
|
||||
: OffsetDateTime.of(date.plusDays(1), LocalTime.MIDNIGHT, ZoneOffset.UTC);
|
||||
if (!current.from().isBefore(to)) {
|
||||
continue;
|
||||
parsedChanges.sort(Comparator.comparing(ActivityChange::from));
|
||||
for (int i = 0; i < parsedChanges.size(); i++) {
|
||||
ActivityChange current = parsedChanges.get(i);
|
||||
OffsetDateTime to = i + 1 < parsedChanges.size()
|
||||
? parsedChanges.get(i + 1).from()
|
||||
: OffsetDateTime.of(date.plusDays(1), LocalTime.MIDNIGHT, ZoneOffset.UTC);
|
||||
if (!current.from().isBefore(to)) {
|
||||
continue;
|
||||
}
|
||||
intervalNo++;
|
||||
intervals.add(new ExtractedCardActivityInterval(
|
||||
"VUACT-" + intervalNo,
|
||||
current.from(),
|
||||
to,
|
||||
current.activityType(),
|
||||
current.slot(),
|
||||
current.cardStatus(),
|
||||
current.drivingStatus(),
|
||||
null,
|
||||
null,
|
||||
current.rawRecordPath()
|
||||
));
|
||||
}
|
||||
intervalNo++;
|
||||
intervals.add(new ExtractedCardActivityInterval(
|
||||
"VUACT-" + intervalNo,
|
||||
current.from(),
|
||||
to,
|
||||
current.activityType(),
|
||||
current.slot(),
|
||||
current.cardStatus(),
|
||||
current.drivingStatus(),
|
||||
null,
|
||||
null,
|
||||
current.rawRecordPath()
|
||||
));
|
||||
}
|
||||
fallbackDayIndex += dayRecords.getLength();
|
||||
}
|
||||
|
||||
intervals.sort(Comparator.comparing(ExtractedCardActivityInterval::from));
|
||||
return intervals;
|
||||
}
|
||||
|
||||
private LocalDate resolveActivityDate(
|
||||
Element activities,
|
||||
VehicleContext vehicleContext,
|
||||
int activityIndex,
|
||||
int fallbackDayIndex,
|
||||
String dayPath,
|
||||
List<ExtractionWarning> warnings
|
||||
) {
|
||||
OffsetDateTime downloadTime = offsetDateTime(text(activities, "downloadTime"));
|
||||
if (downloadTime != null) {
|
||||
return downloadTime.withOffsetSameInstant(ZoneOffset.UTC).toLocalDate();
|
||||
}
|
||||
|
||||
LocalDate fallbackDate = vehicleContext.defaultActivityStartDate();
|
||||
if (fallbackDate == null) {
|
||||
warnings.add(new ExtractionWarning(
|
||||
"VU_ACTIVITY_DATE_INFERENCE_FAILED",
|
||||
"Vehicle-unit activity daily data is present but neither Activities/downloadTime nor the VU downloadable period can provide its date.",
|
||||
dayPath
|
||||
));
|
||||
return null;
|
||||
}
|
||||
|
||||
LocalDate resolvedDate = fallbackDate.plusDays(fallbackDayIndex);
|
||||
LocalDate maxDate = vehicleContext.defaultActivityEndDate();
|
||||
if (maxDate != null && resolvedDate.isAfter(maxDate)) {
|
||||
warnings.add(new ExtractionWarning(
|
||||
"VU_ACTIVITY_DATE_INFERENCE_RANGE",
|
||||
"Vehicle-unit activity daily records exceed the VU downloadable-period range when mapped by sequence order.",
|
||||
"/VehicleUnit/Activities[" + (activityIndex + 1) + "]"
|
||||
));
|
||||
}
|
||||
return resolvedDate;
|
||||
}
|
||||
|
||||
private void assignActivityCoverage(
|
||||
List<ExtractedCardActivityInterval> vuActivityIntervals,
|
||||
List<VuCardIwInterval> vuCardIwIntervals,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import at.procon.eventhub.tachographfilesession.dto.TachographFileDriverSummaryD
|
|||
import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionDeleteResponse;
|
||||
import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionListDriversResponse;
|
||||
import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionSummaryDto;
|
||||
import at.procon.eventhub.tachographfilesession.dto.TachographUploadWorkflowDto;
|
||||
import at.procon.eventhub.tachographfilesession.dto.TachographUploadWorkflowResponse;
|
||||
import at.procon.eventhub.tachographfilesession.model.ExtractionStats;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent;
|
||||
|
|
@ -34,6 +36,7 @@ import java.time.Instant;
|
|||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
|
@ -49,6 +52,7 @@ class TachographFileSessionControllerTest {
|
|||
.setControllerAdvice(new TachographFileSessionExceptionHandler())
|
||||
.build();
|
||||
UUID sessionId = UUID.randomUUID();
|
||||
MockHttpSession webSession = new MockHttpSession();
|
||||
TachographFileDriverSummaryDto driver = new TachographFileDriverSummaryDto("12:123", "Muster", "Max", "12", "123", 3, 2);
|
||||
TachographFileSessionSummaryDto summary = new TachographFileSessionSummaryDto(
|
||||
sessionId,
|
||||
|
|
@ -64,8 +68,26 @@ class TachographFileSessionControllerTest {
|
|||
Instant.parse("2026-05-12T10:00:00Z"),
|
||||
Instant.parse("2026-05-12T14:00:00Z")
|
||||
);
|
||||
when(service.createSession(org.mockito.ArgumentMatchers.any(), eq("default"), eq("src"), eq("sample")))
|
||||
.thenReturn(new CreateTachographFileSessionResponse(summary));
|
||||
when(service.createSession(
|
||||
org.mockito.ArgumentMatchers.any(),
|
||||
eq("default"),
|
||||
eq("src"),
|
||||
eq("sample"),
|
||||
org.mockito.ArgumentMatchers.any(jakarta.servlet.http.HttpSession.class)
|
||||
))
|
||||
.thenReturn(new CreateTachographFileSessionResponse(
|
||||
summary,
|
||||
new TachographUploadWorkflowDto(true, sessionId, List.of(sessionId), List.of(), null),
|
||||
null
|
||||
));
|
||||
when(service.resetUploadWorkflow(org.mockito.ArgumentMatchers.any(jakarta.servlet.http.HttpSession.class)))
|
||||
.thenReturn(new TachographUploadWorkflowResponse(
|
||||
new TachographUploadWorkflowDto(false, null, List.of(), List.of(), null)
|
||||
));
|
||||
when(service.getUploadWorkflow(org.mockito.ArgumentMatchers.any(jakarta.servlet.http.HttpSession.class)))
|
||||
.thenReturn(new TachographUploadWorkflowResponse(
|
||||
new TachographUploadWorkflowDto(true, sessionId, List.of(sessionId), List.of(), null)
|
||||
));
|
||||
when(service.getSession(sessionId)).thenReturn(summary);
|
||||
when(service.listDrivers(sessionId)).thenReturn(new TachographFileSessionListDriversResponse(sessionId, List.of(driver)));
|
||||
when(service.getDriver(sessionId, "12:123")).thenReturn(new TachographFileDriverDetailDto(sessionId, "12:123", null, null, List.of(), List.of(), List.of(), List.of(), List.of(), List.of()));
|
||||
|
|
@ -319,13 +341,23 @@ class TachographFileSessionControllerTest {
|
|||
));
|
||||
when(service.deleteSession(sessionId)).thenReturn(new TachographFileSessionDeleteResponse(sessionId, true));
|
||||
|
||||
mockMvc.perform(post("/api/eventhub/tachograph-file-sessions/workflow/reset").session(webSession))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.workflow.driverCardUploaded").value(false));
|
||||
|
||||
mockMvc.perform(multipart("/api/eventhub/tachograph-file-sessions")
|
||||
.file(new MockMultipartFile("file", "sample.ddd", "application/octet-stream", "abc".getBytes()))
|
||||
.param("tenantKey", "default")
|
||||
.param("sourceInstanceKey", "src")
|
||||
.param("sessionLabel", "sample"))
|
||||
.param("sessionLabel", "sample")
|
||||
.session(webSession))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("$.session.sessionId").value(sessionId.toString()));
|
||||
.andExpect(jsonPath("$.session.sessionId").value(sessionId.toString()))
|
||||
.andExpect(jsonPath("$.workflow.driverCardUploaded").value(true));
|
||||
|
||||
mockMvc.perform(get("/api/eventhub/tachograph-file-sessions/workflow").session(webSession))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.workflow.driverCardSessionId").value(sessionId.toString()));
|
||||
|
||||
mockMvc.perform(get("/api/eventhub/tachograph-file-sessions/{sessionId}", sessionId))
|
||||
.andExpect(status().isOk())
|
||||
|
|
|
|||
|
|
@ -3,22 +3,27 @@ package at.procon.eventhub.tachographfilesession.service;
|
|||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyList;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import at.procon.eventhub.config.EventHubProperties;
|
||||
import at.procon.eventhub.tachographfilesession.dto.CreateTachographFileSessionResponse;
|
||||
import at.procon.eventhub.tachographfilesession.dto.TachographCompositeSessionSummaryDto;
|
||||
import at.procon.eventhub.tachographfilesession.dto.TachographFileDriverSummaryDto;
|
||||
import at.procon.eventhub.tachographfilesession.model.ExtractionStats;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographFileSessionMetadata;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
|
||||
class TachographFileSessionServiceTest {
|
||||
|
||||
|
|
@ -26,6 +31,7 @@ class TachographFileSessionServiceTest {
|
|||
void createsAndLoadsSession() {
|
||||
EventHubProperties properties = new EventHubProperties();
|
||||
TachographFileSessionRepository repository = new InMemoryTachographFileSessionRepository(properties);
|
||||
TachographCompositeSessionService compositeSessionService = Mockito.mock(TachographCompositeSessionService.class);
|
||||
LegalRequirementsClient client = Mockito.mock(LegalRequirementsClient.class);
|
||||
TachographXmlParser parser = Mockito.mock(TachographXmlParser.class);
|
||||
DriverCardXmlExtractionService driverCardExtractor = Mockito.mock(DriverCardXmlExtractionService.class);
|
||||
|
|
@ -33,14 +39,17 @@ class TachographFileSessionServiceTest {
|
|||
TachographFileSessionService service = new TachographFileSessionService(
|
||||
properties,
|
||||
repository,
|
||||
compositeSessionService,
|
||||
client,
|
||||
parser,
|
||||
driverCardExtractor,
|
||||
vehicleUnitExtractor
|
||||
);
|
||||
when(client.newCookieManager()).thenReturn(new java.net.CookieManager());
|
||||
|
||||
MockMultipartFile file = new MockMultipartFile("file", "sample.ddd", "application/octet-stream", "abc".getBytes(StandardCharsets.UTF_8));
|
||||
when(client.uploadTachographFile(any(), eq("sample.ddd"))).thenReturn(new LegalRequirementsUploadResult("42", "<DriverCard/>"));
|
||||
when(client.uploadTachographFile(any(java.net.CookieManager.class), any(), eq("sample.ddd")))
|
||||
.thenReturn(new LegalRequirementsUploadResult("42", "<DriverCard/>"));
|
||||
TachographXmlParser.ParsedTachographXml parsed = Mockito.mock(TachographXmlParser.ParsedTachographXml.class);
|
||||
when(parsed.rootElementName()).thenReturn("DriverCard");
|
||||
when(parser.parse("<DriverCard/>")).thenReturn(parsed);
|
||||
|
|
@ -55,9 +64,12 @@ class TachographFileSessionServiceTest {
|
|||
);
|
||||
when(driverCardExtractor.extract(eq(parsed), any(), any(), any())).thenReturn(extracted);
|
||||
|
||||
CreateTachographFileSessionResponse response = service.createSession(file, null, null, "sample");
|
||||
CreateTachographFileSessionResponse response = service.createSession(file, null, null, "sample", new MockHttpSession());
|
||||
|
||||
assertThat(response.session().sessionId()).isEqualTo(extracted.sessionId());
|
||||
assertThat(response.workflow()).isNotNull();
|
||||
assertThat(response.workflow().driverCardUploaded()).isTrue();
|
||||
assertThat(response.compositeSession()).isNull();
|
||||
assertThat(service.getSession(extracted.sessionId()).sessionId()).isEqualTo(extracted.sessionId());
|
||||
}
|
||||
|
||||
|
|
@ -66,6 +78,7 @@ class TachographFileSessionServiceTest {
|
|||
EventHubProperties properties = new EventHubProperties();
|
||||
properties.getTachographFileSession().setMaxFileSizeBytes(1024);
|
||||
TachographFileSessionRepository repository = new InMemoryTachographFileSessionRepository(properties);
|
||||
TachographCompositeSessionService compositeSessionService = Mockito.mock(TachographCompositeSessionService.class);
|
||||
LegalRequirementsClient client = Mockito.mock(LegalRequirementsClient.class);
|
||||
TachographXmlParser parser = Mockito.mock(TachographXmlParser.class);
|
||||
DriverCardXmlExtractionService driverCardExtractor = Mockito.mock(DriverCardXmlExtractionService.class);
|
||||
|
|
@ -73,6 +86,7 @@ class TachographFileSessionServiceTest {
|
|||
TachographFileSessionService service = new TachographFileSessionService(
|
||||
properties,
|
||||
repository,
|
||||
compositeSessionService,
|
||||
client,
|
||||
parser,
|
||||
driverCardExtractor,
|
||||
|
|
@ -81,17 +95,18 @@ class TachographFileSessionServiceTest {
|
|||
|
||||
MockMultipartFile file = new MockMultipartFile("file", "sample.ddd", "application/octet-stream", new byte[1025]);
|
||||
|
||||
assertThatThrownBy(() -> service.createSession(file, null, null, "sample"))
|
||||
assertThatThrownBy(() -> service.createSession(file, null, null, "sample", new MockHttpSession()))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("size limit");
|
||||
|
||||
verifyNoInteractions(client, parser, driverCardExtractor, vehicleUnitExtractor);
|
||||
verifyNoInteractions(compositeSessionService, client, parser, driverCardExtractor, vehicleUnitExtractor);
|
||||
}
|
||||
|
||||
@Test
|
||||
void usesVehicleUnitDefaultsAndExtractorForVehicleUnitXml() {
|
||||
EventHubProperties properties = new EventHubProperties();
|
||||
TachographFileSessionRepository repository = new InMemoryTachographFileSessionRepository(properties);
|
||||
TachographCompositeSessionService compositeSessionService = Mockito.mock(TachographCompositeSessionService.class);
|
||||
LegalRequirementsClient client = Mockito.mock(LegalRequirementsClient.class);
|
||||
TachographXmlParser parser = Mockito.mock(TachographXmlParser.class);
|
||||
DriverCardXmlExtractionService driverCardExtractor = Mockito.mock(DriverCardXmlExtractionService.class);
|
||||
|
|
@ -99,14 +114,17 @@ class TachographFileSessionServiceTest {
|
|||
TachographFileSessionService service = new TachographFileSessionService(
|
||||
properties,
|
||||
repository,
|
||||
compositeSessionService,
|
||||
client,
|
||||
parser,
|
||||
driverCardExtractor,
|
||||
vehicleUnitExtractor
|
||||
);
|
||||
when(client.newCookieManager()).thenReturn(new java.net.CookieManager());
|
||||
|
||||
MockMultipartFile file = new MockMultipartFile("file", "vu.ddd", "application/octet-stream", "vu".getBytes(StandardCharsets.UTF_8));
|
||||
when(client.uploadTachographFile(any(), eq("vu.ddd"))).thenReturn(new LegalRequirementsUploadResult("77", "<VehicleUnit/>"));
|
||||
when(client.uploadTachographFile(any(java.net.CookieManager.class), any(), eq("vu.ddd")))
|
||||
.thenReturn(new LegalRequirementsUploadResult("77", "<VehicleUnit/>"));
|
||||
TachographXmlParser.ParsedTachographXml parsed = Mockito.mock(TachographXmlParser.ParsedTachographXml.class);
|
||||
when(parsed.rootElementName()).thenReturn("VehicleUnit");
|
||||
when(parser.parse("<VehicleUnit/>")).thenReturn(parsed);
|
||||
|
|
@ -121,9 +139,74 @@ class TachographFileSessionServiceTest {
|
|||
);
|
||||
when(vehicleUnitExtractor.extract(eq(parsed), any(), any(), any())).thenReturn(extracted);
|
||||
|
||||
CreateTachographFileSessionResponse response = service.createSession(file, null, null, "vu");
|
||||
MockHttpSession webSession = new MockHttpSession();
|
||||
service.resetUploadWorkflow(webSession);
|
||||
MockMultipartFile driverCardFile = new MockMultipartFile("file", "driver.ddd", "application/octet-stream", "dc".getBytes(StandardCharsets.UTF_8));
|
||||
when(client.uploadTachographFile(any(java.net.CookieManager.class), any(), eq("driver.ddd")))
|
||||
.thenReturn(new LegalRequirementsUploadResult("42", "<DriverCard/>"));
|
||||
TachographXmlParser.ParsedTachographXml driverParsed = Mockito.mock(TachographXmlParser.ParsedTachographXml.class);
|
||||
when(driverParsed.rootElementName()).thenReturn("DriverCard");
|
||||
when(parser.parse("<DriverCard/>")).thenReturn(driverParsed);
|
||||
TachographFileSession driverExtracted = new TachographFileSession(
|
||||
UUID.randomUUID(),
|
||||
new TachographFileSessionMetadata("default", "legalrequirements-drivercard", "sample", "driver.ddd", "a", 2, "42", "b", true, null),
|
||||
Map.of(),
|
||||
new ExtractionStats(0, 0, 0, 0, 0, 0),
|
||||
java.util.List.of(),
|
||||
Instant.now(),
|
||||
Instant.now().plusSeconds(10)
|
||||
);
|
||||
when(driverCardExtractor.extract(eq(driverParsed), any(), any(), any())).thenReturn(driverExtracted);
|
||||
when(compositeSessionService.upsertCompositeSession(any(), anyList(), any()))
|
||||
.thenReturn(new TachographCompositeSessionSummaryDto(
|
||||
UUID.randomUUID(),
|
||||
"default",
|
||||
"vu",
|
||||
List.of(driverExtracted.sessionId(), extracted.sessionId()),
|
||||
List.<TachographFileDriverSummaryDto>of(),
|
||||
Instant.now()
|
||||
));
|
||||
|
||||
service.createSession(driverCardFile, null, null, "sample", webSession);
|
||||
CreateTachographFileSessionResponse response = service.createSession(file, null, null, "vu", webSession);
|
||||
|
||||
assertThat(response.session().driverCardFile()).isFalse();
|
||||
assertThat(response.session().sourceInstanceKey()).isEqualTo("legalrequirements-vehicleunit");
|
||||
assertThat(response.compositeSession()).isNotNull();
|
||||
assertThat(response.workflow().uploadedSessionIds()).hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsVehicleUnitBeforeDriverCardInWorkflow() {
|
||||
EventHubProperties properties = new EventHubProperties();
|
||||
TachographFileSessionRepository repository = new InMemoryTachographFileSessionRepository(properties);
|
||||
TachographCompositeSessionService compositeSessionService = Mockito.mock(TachographCompositeSessionService.class);
|
||||
LegalRequirementsClient client = Mockito.mock(LegalRequirementsClient.class);
|
||||
TachographXmlParser parser = Mockito.mock(TachographXmlParser.class);
|
||||
TachographFileSessionService service = new TachographFileSessionService(
|
||||
properties,
|
||||
repository,
|
||||
compositeSessionService,
|
||||
client,
|
||||
parser,
|
||||
Mockito.mock(DriverCardXmlExtractionService.class),
|
||||
Mockito.mock(VehicleUnitXmlExtractionService.class)
|
||||
);
|
||||
when(client.newCookieManager()).thenReturn(new java.net.CookieManager());
|
||||
when(client.uploadTachographFile(any(java.net.CookieManager.class), any(), eq("vu.ddd")))
|
||||
.thenReturn(new LegalRequirementsUploadResult("77", "<VehicleUnit/>"));
|
||||
TachographXmlParser.ParsedTachographXml parsed = Mockito.mock(TachographXmlParser.ParsedTachographXml.class);
|
||||
when(parsed.rootElementName()).thenReturn("VehicleUnit");
|
||||
when(parser.parse("<VehicleUnit/>")).thenReturn(parsed);
|
||||
|
||||
assertThatThrownBy(() -> service.createSession(
|
||||
new MockMultipartFile("file", "vu.ddd", "application/octet-stream", "vu".getBytes(StandardCharsets.UTF_8)),
|
||||
null,
|
||||
null,
|
||||
"vu",
|
||||
new MockHttpSession()
|
||||
))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("Driver card file must be uploaded first");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,26 @@ class TachographXmlParserTest {
|
|||
.isInstanceOf(TachographXmlValidationException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void normalizesManufacturerSpecificErrorCodeFromBase64ToHex() {
|
||||
String normalized = parser.normalizeXmlContent("""
|
||||
<VehicleUnit>
|
||||
<EventsFaults>
|
||||
<vuFaultData>
|
||||
<vuFaultRecords>
|
||||
<manufacturerSpecificEventFaultData>
|
||||
<manufacturerCode>0</manufacturerCode>
|
||||
<manufacturerSpecificErrorCode>////</manufacturerSpecificErrorCode>
|
||||
</manufacturerSpecificEventFaultData>
|
||||
</vuFaultRecords>
|
||||
</vuFaultData>
|
||||
</EventsFaults>
|
||||
</VehicleUnit>
|
||||
""");
|
||||
|
||||
assertThat(normalized).contains("<manufacturerSpecificErrorCode>FFFFFF</manufacturerSpecificErrorCode>");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsXmlWithDoctype() {
|
||||
String xmlWithDoctype = """
|
||||
|
|
|
|||
|
|
@ -111,6 +111,35 @@ class VehicleUnitXmlExtractionServiceTest {
|
|||
assertThat(secondDriver.cardActivityIntervals().get(0).from().toString()).isEqualTo("2026-04-02T07:30Z");
|
||||
}
|
||||
|
||||
@Test
|
||||
void usesActivitiesDownloadTimeAsVuActivityRecordDate() throws Exception {
|
||||
TachographFileSession session = service.extract(
|
||||
new TachographXmlParser.ParsedTachographXml(document(VehicleUnitXmlSamples.vehicleUnitXmlWithActivityDownloadTime()), "VehicleUnit"),
|
||||
new TachographFileSessionMetadata(
|
||||
"default",
|
||||
"legalrequirements-vehicleunit",
|
||||
"sample-vu",
|
||||
"sample-vu.ddd",
|
||||
"abc",
|
||||
10,
|
||||
"42",
|
||||
"def",
|
||||
false,
|
||||
null
|
||||
),
|
||||
Instant.now(),
|
||||
Instant.now().plus(4, ChronoUnit.HOURS)
|
||||
);
|
||||
|
||||
DriverExtractionSession driver = session.driversByKey().get("12:12345678901200");
|
||||
assertThat(driver).isNotNull();
|
||||
assertThat(driver.cardActivityIntervals()).hasSize(2);
|
||||
assertThat(driver.cardActivityIntervals().get(0).from()).isEqualTo(OffsetDateTime.parse("2026-05-25T08:00:00Z"));
|
||||
assertThat(driver.cardActivityIntervals().get(1).from()).isEqualTo(OffsetDateTime.parse("2026-05-25T09:00:00Z"));
|
||||
assertThat(driver.cardActivityIntervals().get(1).to()).isEqualTo(OffsetDateTime.parse("2026-05-26T00:00:00Z"));
|
||||
assertThat(session.warnings()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void keepsOpenVuCardUsageRecordWithoutClosingItAtDownloadPeriodEnd() throws Exception {
|
||||
TachographFileSession session = service.extract(
|
||||
|
|
|
|||
|
|
@ -254,4 +254,64 @@ final class VehicleUnitXmlSamples {
|
|||
.replace("<timeOfChange>11:00:00Z</timeOfChange>", "<timeOfChange>11:00:00</timeOfChange>")
|
||||
.replace("<timeOfChange>07:30:00Z</timeOfChange>", "<timeOfChange>07:30:00</timeOfChange>");
|
||||
}
|
||||
|
||||
static String vehicleUnitXmlWithActivityDownloadTime() {
|
||||
return """
|
||||
<VehicleUnit>
|
||||
<Overview>
|
||||
<vehicleIdentificationNumber>VINVU123456789012</vehicleIdentificationNumber>
|
||||
<vehicleRegistrationIdentification>
|
||||
<vehicleRegistrationNation>12</vehicleRegistrationNation>
|
||||
<vehicleRegistrationNumber><vehicleRegNumber>W-1000V</vehicleRegNumber></vehicleRegistrationNumber>
|
||||
</vehicleRegistrationIdentification>
|
||||
<vuDownloadablePeriod>
|
||||
<minDownloadableTime>2026-05-20T00:00:00Z</minDownloadableTime>
|
||||
<maxDownloadableTime>2026-05-20T23:59:59Z</maxDownloadableTime>
|
||||
</vuDownloadablePeriod>
|
||||
</Overview>
|
||||
<Activities Generation="3">
|
||||
<downloadTime>2026-05-25T23:59:59Z</downloadTime>
|
||||
<odometerValueMidnight>3756</odometerValueMidnight>
|
||||
<vuCardIWData>
|
||||
<vuCardIWRecords>
|
||||
<cardHolderName>
|
||||
<holderSurname><name>Muster</name></holderSurname>
|
||||
<holderFirstNames><name>Max</name></holderFirstNames>
|
||||
</cardHolderName>
|
||||
<fullCardNumber>
|
||||
<cardType>DRIVER_CARD</cardType>
|
||||
<cardIssuingMemberState>12</cardIssuingMemberState>
|
||||
<cardNumber>
|
||||
<driverIdentification>123456789012</driverIdentification>
|
||||
<cardReplacementIndex>0</cardReplacementIndex>
|
||||
<cardRenewalIndex>0</cardRenewalIndex>
|
||||
</cardNumber>
|
||||
<generation>3</generation>
|
||||
</fullCardNumber>
|
||||
<cardInsertionTime>2026-05-25T08:00:00Z</cardInsertionTime>
|
||||
<vehicleOdometerValueAtInsertion>3700</vehicleOdometerValueAtInsertion>
|
||||
<cardSlotNumber>DRIVER</cardSlotNumber>
|
||||
</vuCardIWRecords>
|
||||
</vuCardIWData>
|
||||
<vuActivityDailyData>
|
||||
<noOfActivityChanges>2</noOfActivityChanges>
|
||||
<activityChangeInfos>
|
||||
<slot>DRIVER</slot>
|
||||
<drivingStatus>SINGLE</drivingStatus>
|
||||
<cardStatus>INSERTED</cardStatus>
|
||||
<activity>WORK</activity>
|
||||
<timeOfChange>08:00:00Z</timeOfChange>
|
||||
</activityChangeInfos>
|
||||
<activityChangeInfos>
|
||||
<slot>DRIVER</slot>
|
||||
<drivingStatus>SINGLE</drivingStatus>
|
||||
<cardStatus>INSERTED</cardStatus>
|
||||
<activity>DRIVING</activity>
|
||||
<timeOfChange>09:00:00Z</timeOfChange>
|
||||
</activityChangeInfos>
|
||||
</vuActivityDailyData>
|
||||
</Activities>
|
||||
</VehicleUnit>
|
||||
""";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue