From 0568ae1a0fe9d40590b165edf868ffceb504a01d Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 10 Feb 2025 09:56:01 +0100 Subject: [PATCH 1/5] Return error codes from SiriFuzzyTripMatcher --- .../updater/siri/SiriFuzzyTripMatcher.java | 113 ++++-------------- .../siri/SiriRealTimeTripUpdateAdapter.java | 7 +- .../updater/spi/UpdateError.java | 1 + .../updater/siri/SiriEtBuilder.java | 4 + .../siri/SiriFuzzyTripMatcherTest.java | 79 ++++++++++++ 5 files changed, 114 insertions(+), 90 deletions(-) create mode 100644 application/src/test/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcherTest.java diff --git a/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java b/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java index 2cffc81b440..40bf28f0155 100644 --- a/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java +++ b/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java @@ -1,5 +1,9 @@ package org.opentripplanner.updater.siri; +import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.INVALID_INPUT_STRUCTURE; +import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.NO_FUZZY_TRIP_MATCH; +import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.NO_VALID_STOPS; + import java.time.LocalDate; import java.time.ZonedDateTime; import java.util.ArrayList; @@ -15,16 +19,18 @@ import org.opentripplanner.model.calendar.CalendarService; import org.opentripplanner.transit.model.basic.TransitMode; import org.opentripplanner.transit.model.framework.FeedScopedId; +import org.opentripplanner.transit.model.framework.Result; import org.opentripplanner.transit.model.network.Route; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.timetable.Trip; import org.opentripplanner.transit.model.timetable.TripTimes; import org.opentripplanner.transit.service.TransitService; +import org.opentripplanner.updater.spi.UpdateError; +import org.opentripplanner.utils.collection.CollectionUtils; import org.opentripplanner.utils.time.ServiceDateUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import uk.org.siri.siri20.EstimatedVehicleJourney; -import uk.org.siri.siri20.MonitoredVehicleJourneyStructure; import uk.org.siri.siri20.VehicleModesEnumeration; /** @@ -53,37 +59,11 @@ public SiriFuzzyTripMatcher(TransitService transitService) { initCache(this.transitService); } - /** - * Matches VehicleActivity to a set of possible Trips based on tripId - */ - public Trip match( - MonitoredVehicleJourneyStructure monitoredVehicleJourney, - EntityResolver entityResolver - ) { - if (monitoredVehicleJourney.getDestinationRef() != null) { - String destinationRef = monitoredVehicleJourney.getDestinationRef().getValue(); - ZonedDateTime arrivalTime = monitoredVehicleJourney.getDestinationAimedArrivalTime(); - - if (arrivalTime != null) { - Set trips = getMatchingTripsOnStopOrSiblings( - destinationRef, - arrivalTime, - entityResolver - ); - if (trips.isEmpty()) { - return null; - } - return getTripForJourney(trips, monitoredVehicleJourney); - } - } - return null; - } - /** * Matches EstimatedVehicleJourney to a set of possible Trips based on tripId */ @Nullable - public TripAndPattern match( + public Result match( EstimatedVehicleJourney journey, EntityResolver entityResolver, BiFunction getCurrentTimetable, @@ -92,11 +72,11 @@ public TripAndPattern match( List calls = CallWrapper.of(journey); if (calls.isEmpty()) { - return null; + return Result.failure(NO_VALID_STOPS); } if (calls.getFirst().getAimedDepartureTime() == null) { - return null; + return Result.failure(NO_FUZZY_TRIP_MATCH); } Set trips = null; @@ -116,10 +96,20 @@ public TripAndPattern match( if (arrivalTime != null) { trips = getMatchingTripsOnStopOrSiblings(lastStopPoint, arrivalTime, entityResolver); + if (CollectionUtils.isEmpty(trips)) { + var id = entityResolver.resolveId(lastStopPoint); + trips = + transitService + .findStopByScheduledStopPoint(id) + .map(stop -> + getMatchingTripsOnStopOrSiblings(stop.getId().getId(), arrivalTime, entityResolver) + ) + .orElse(Set.of()); + } } } if (trips == null || trips.isEmpty()) { - return null; + return Result.failure(NO_FUZZY_TRIP_MATCH); } if (journey.getLineRef() != null) { @@ -254,7 +244,7 @@ private Set getCachedTripsByInternalPlanningCode(String internalPlanningCo * Finds the correct trip based on OTP-ServiceDate and SIRI-DepartureTime */ @Nullable - TripAndPattern getTripAndPatternForJourney( + Result getTripAndPatternForJourney( Set trips, List calls, EntityResolver entityResolver, @@ -264,7 +254,7 @@ TripAndPattern getTripAndPatternForJourney( var journeyFirstStop = entityResolver.resolveQuay(calls.getFirst().getStopPointRef()); var journeyLastStop = entityResolver.resolveQuay(calls.getLast().getStopPointRef()); if (journeyFirstStop == null || journeyLastStop == null) { - return null; + return Result.failure(NO_VALID_STOPS); } ZonedDateTime date = calls.getFirst().getAimedDepartureTime(); @@ -310,63 +300,12 @@ TripAndPattern getTripAndPatternForJourney( } if (possibleTrips.isEmpty()) { - return null; + return Result.failure(UpdateError.UpdateErrorType.NO_FUZZY_TRIP_MATCH); } else if (possibleTrips.size() > 1) { LOG.warn("Multiple trip and pattern combinations found, skipping all, {}", possibleTrips); - return null; + return Result.failure(UpdateError.UpdateErrorType.MULTIPLE_FUZZY_TRIP_MATCHES); } else { - return possibleTrips.iterator().next(); - } - } - - /** - * Finds the correct trip based on OTP-ServiceDate and SIRI-DepartureTime - */ - private Trip getTripForJourney( - Set trips, - MonitoredVehicleJourneyStructure monitoredVehicleJourney - ) { - ZonedDateTime date = monitoredVehicleJourney.getOriginAimedDepartureTime(); - if (date == null) { - //If no date is set - assume Realtime-data is reported for 'today'. - date = ZonedDateTime.now(); + return Result.success(possibleTrips.iterator().next()); } - LocalDate serviceDate = date.toLocalDate(); - - List results = new ArrayList<>(); - for (Trip trip : trips) { - Set serviceDatesForServiceId = transitService - .getCalendarService() - .getServiceDatesForServiceId(trip.getServiceId()); - - for (LocalDate next : serviceDatesForServiceId) { - if (next.equals(serviceDate)) { - results.add(trip); - } - } - } - - if (results.size() == 1) { - return results.getFirst(); - } else if (results.size() > 1) { - // Multiple possible matches - check if lineRef/routeId matches - if ( - monitoredVehicleJourney.getLineRef() != null && - monitoredVehicleJourney.getLineRef().getValue() != null - ) { - String lineRef = monitoredVehicleJourney.getLineRef().getValue(); - for (Trip trip : results) { - if (lineRef.equals(trip.getRoute().getId().getId())) { - // Return first trip where the lineRef matches routeId - return trip; - } - } - } - - // Line does not match any routeId - return first result. - return results.getFirst(); - } - - return null; } } diff --git a/application/src/main/java/org/opentripplanner/updater/siri/SiriRealTimeTripUpdateAdapter.java b/application/src/main/java/org/opentripplanner/updater/siri/SiriRealTimeTripUpdateAdapter.java index 35fd5508169..bdb54e6e459 100644 --- a/application/src/main/java/org/opentripplanner/updater/siri/SiriRealTimeTripUpdateAdapter.java +++ b/application/src/main/java/org/opentripplanner/updater/siri/SiriRealTimeTripUpdateAdapter.java @@ -219,21 +219,22 @@ private Result handleModifiedTrip( pattern = transitEditorService.findPattern(trip); } else if (fuzzyTripMatcher != null) { // No exact match found - search for trips based on arrival-times/stop-patterns - TripAndPattern tripAndPattern = fuzzyTripMatcher.match( + var result = fuzzyTripMatcher.match( estimatedVehicleJourney, entityResolver, this::getCurrentTimetable, snapshotManager::getNewTripPatternForModifiedTrip ); - if (tripAndPattern == null) { + if (result.isFailure()) { LOG.debug( "No trips found for EstimatedVehicleJourney. {}", DebugString.of(estimatedVehicleJourney) ); - return UpdateError.result(null, NO_FUZZY_TRIP_MATCH, dataSource); + return UpdateError.result(null, result.failureValue(), dataSource); } + var tripAndPattern = result.successValue(); trip = tripAndPattern.trip(); pattern = tripAndPattern.tripPattern(); } else { diff --git a/application/src/main/java/org/opentripplanner/updater/spi/UpdateError.java b/application/src/main/java/org/opentripplanner/updater/spi/UpdateError.java index 945139e2457..23f9d4e2955 100644 --- a/application/src/main/java/org/opentripplanner/updater/spi/UpdateError.java +++ b/application/src/main/java/org/opentripplanner/updater/spi/UpdateError.java @@ -41,6 +41,7 @@ public enum UpdateErrorType { TRIP_NOT_FOUND, TRIP_NOT_FOUND_IN_PATTERN, NO_FUZZY_TRIP_MATCH, + MULTIPLE_FUZZY_TRIP_MATCHES, EMPTY_STOP_POINT_REF, NO_TRIP_FOR_CANCELLATION_FOUND, TRIP_ALREADY_EXISTS, diff --git a/application/src/test/java/org/opentripplanner/updater/siri/SiriEtBuilder.java b/application/src/test/java/org/opentripplanner/updater/siri/SiriEtBuilder.java index 737fb04917e..793bec905e8 100644 --- a/application/src/test/java/org/opentripplanner/updater/siri/SiriEtBuilder.java +++ b/application/src/test/java/org/opentripplanner/updater/siri/SiriEtBuilder.java @@ -51,6 +51,10 @@ public List buildEstimatedTimetableDeliveri return List.of(etd); } + public EstimatedVehicleJourney buildEstimatedVehicleJourney() { + return evj; + } + public SiriEtBuilder withCancellation(boolean canceled) { evj.setCancellation(canceled); return this; diff --git a/application/src/test/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcherTest.java b/application/src/test/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcherTest.java new file mode 100644 index 00000000000..2e752fa3016 --- /dev/null +++ b/application/src/test/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcherTest.java @@ -0,0 +1,79 @@ +package org.opentripplanner.updater.siri; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.MULTIPLE_FUZZY_TRIP_MATCHES; +import static org.opentripplanner.updater.trip.RealtimeTestConstants.STOP_A1; +import static org.opentripplanner.updater.trip.RealtimeTestConstants.STOP_B1; +import static org.opentripplanner.updater.trip.RealtimeTestConstants.TRIP_1_ID; +import static org.opentripplanner.updater.trip.RealtimeTestConstants.TRIP_2_ID; + +import org.junit.jupiter.api.Test; +import org.opentripplanner.transit.model.framework.Result; +import org.opentripplanner.transit.service.TransitService; +import org.opentripplanner.updater.spi.UpdateError; +import org.opentripplanner.updater.trip.RealtimeTestEnvironment; +import org.opentripplanner.updater.trip.TripInput; +import uk.org.siri.siri20.EstimatedVehicleJourney; + +class SiriFuzzyTripMatcherTest { + + @Test + void match() { + TripInput trip1Input = tripInput(TRIP_1_ID); + + var env = RealtimeTestEnvironment.of().addTrip(trip1Input).build(); + var evj = estimatedVehicleJourney(env); + + var result = match(evj, env); + assertTrue(result.isSuccess()); + } + + @Test + void multipleMatches() { + var trip1input = tripInput(TRIP_1_ID); + var trip2input = tripInput(TRIP_2_ID); + + var env = RealtimeTestEnvironment.of().addTrip(trip1input).addTrip(trip2input).build(); + + var evj = estimatedVehicleJourney(env); + + var result = match(evj, env); + assertTrue(result.isFailure()); + assertEquals(MULTIPLE_FUZZY_TRIP_MATCHES, result.failureValue()); + } + + private static Result match( + EstimatedVehicleJourney evj, + RealtimeTestEnvironment env + ) { + var transitService = env.getTransitService(); + var fuzzyMatcher = new SiriFuzzyTripMatcher(transitService); + return fuzzyMatcher.match( + evj, + new EntityResolver(transitService, env.getFeedId()), + transitService::findTimetable, + transitService::findNewTripPatternForModifiedTrip + ); + } + + private static EstimatedVehicleJourney estimatedVehicleJourney(RealtimeTestEnvironment env) { + return new SiriEtBuilder(env.getDateTimeHelper()) + .withEstimatedCalls(builder -> + builder + .call(STOP_A1) + .departAimedExpected("00:10:00", "00:10:00") + .call(STOP_B1) + .arriveAimedExpected("00:20:00", "00:20:00") + ) + .buildEstimatedVehicleJourney(); + } + + private static TripInput tripInput(String trip1Id) { + return TripInput + .of(trip1Id) + .addStop(STOP_A1, "0:10:00", "0:10:00") + .addStop(STOP_B1, "0:20:00", "0:20:00") + .build(); + } +} From 3247c47757450117beef4ec42c07e80a7f443e3b Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 10 Feb 2025 10:27:17 +0100 Subject: [PATCH 2/5] Add support for scheduled stop points in fuzzy trip matcher --- .../updater/siri/SiriFuzzyTripMatcher.java | 20 ++++++--------- .../siri/SiriFuzzyTripMatcherTest.java | 25 ++++++++++++++++++- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java b/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java index 40bf28f0155..c587265abf7 100644 --- a/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java +++ b/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java @@ -22,6 +22,7 @@ import org.opentripplanner.transit.model.framework.Result; import org.opentripplanner.transit.model.network.Route; import org.opentripplanner.transit.model.network.TripPattern; +import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.model.timetable.Trip; import org.opentripplanner.transit.model.timetable.TripTimes; import org.opentripplanner.transit.service.TransitService; @@ -89,23 +90,18 @@ public Result match( if (trips == null || trips.isEmpty()) { CallWrapper lastStop = calls.getLast(); - String lastStopPoint = lastStop.getStopPointRef(); + // resolves a scheduled stop point id to a quay (regular stop) if necessary + // quay ids also work + RegularStop stop = entityResolver.resolveQuay(lastStop.getStopPointRef()); + if (stop == null) { + return Result.failure(NO_FUZZY_TRIP_MATCH); + } ZonedDateTime arrivalTime = lastStop.getAimedArrivalTime() != null ? lastStop.getAimedArrivalTime() : lastStop.getAimedDepartureTime(); if (arrivalTime != null) { - trips = getMatchingTripsOnStopOrSiblings(lastStopPoint, arrivalTime, entityResolver); - if (CollectionUtils.isEmpty(trips)) { - var id = entityResolver.resolveId(lastStopPoint); - trips = - transitService - .findStopByScheduledStopPoint(id) - .map(stop -> - getMatchingTripsOnStopOrSiblings(stop.getId().getId(), arrivalTime, entityResolver) - ) - .orElse(Set.of()); - } + trips = getMatchingTripsOnStopOrSiblings(stop.getId().getId(), arrivalTime, entityResolver); } } if (trips == null || trips.isEmpty()) { diff --git a/application/src/test/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcherTest.java b/application/src/test/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcherTest.java index 2e752fa3016..7a3dd791b94 100644 --- a/application/src/test/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcherTest.java +++ b/application/src/test/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcherTest.java @@ -2,15 +2,16 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.opentripplanner.transit.model._data.TimetableRepositoryForTest.id; import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.MULTIPLE_FUZZY_TRIP_MATCHES; import static org.opentripplanner.updater.trip.RealtimeTestConstants.STOP_A1; import static org.opentripplanner.updater.trip.RealtimeTestConstants.STOP_B1; import static org.opentripplanner.updater.trip.RealtimeTestConstants.TRIP_1_ID; import static org.opentripplanner.updater.trip.RealtimeTestConstants.TRIP_2_ID; +import java.util.Map; import org.junit.jupiter.api.Test; import org.opentripplanner.transit.model.framework.Result; -import org.opentripplanner.transit.service.TransitService; import org.opentripplanner.updater.spi.UpdateError; import org.opentripplanner.updater.trip.RealtimeTestEnvironment; import org.opentripplanner.updater.trip.TripInput; @@ -43,6 +44,28 @@ void multipleMatches() { assertEquals(MULTIPLE_FUZZY_TRIP_MATCHES, result.failureValue()); } + @Test + void scheduledStopPoint() { + var scheduledStopPointId = "ssp-1"; + var trip1input = tripInput(TRIP_1_ID); + + var env = RealtimeTestEnvironment.of().addTrip(trip1input).build(); + env.timetableRepository.addScheduledStopPointMapping(Map.of(id(scheduledStopPointId), STOP_B1)); + + var journey = new SiriEtBuilder(env.getDateTimeHelper()) + .withEstimatedCalls(builder -> + builder + .call(STOP_A1) + .departAimedExpected("00:10:00", "00:10:00") + .call(scheduledStopPointId) + .arriveAimedExpected("00:20:00", "00:20:00") + ) + .buildEstimatedVehicleJourney(); + + var result = match(journey, env); + assertTrue(result.isSuccess()); + } + private static Result match( EstimatedVehicleJourney evj, RealtimeTestEnvironment env From 6fa1e684d9cddd608ef8433fc5c2ef88b2cd22a7 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 10 Feb 2025 11:37:35 +0100 Subject: [PATCH 3/5] Rename stop to call --- .../updater/siri/SiriFuzzyTripMatcher.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java b/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java index c587265abf7..edfb3a5798d 100644 --- a/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java +++ b/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java @@ -1,6 +1,5 @@ package org.opentripplanner.updater.siri; -import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.INVALID_INPUT_STRUCTURE; import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.NO_FUZZY_TRIP_MATCH; import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.NO_VALID_STOPS; @@ -27,7 +26,6 @@ import org.opentripplanner.transit.model.timetable.TripTimes; import org.opentripplanner.transit.service.TransitService; import org.opentripplanner.updater.spi.UpdateError; -import org.opentripplanner.utils.collection.CollectionUtils; import org.opentripplanner.utils.time.ServiceDateUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,16 +87,16 @@ public Result match( } if (trips == null || trips.isEmpty()) { - CallWrapper lastStop = calls.getLast(); + CallWrapper lastCall = calls.getLast(); // resolves a scheduled stop point id to a quay (regular stop) if necessary // quay ids also work - RegularStop stop = entityResolver.resolveQuay(lastStop.getStopPointRef()); + RegularStop stop = entityResolver.resolveQuay(lastCall.getStopPointRef()); if (stop == null) { return Result.failure(NO_FUZZY_TRIP_MATCH); } - ZonedDateTime arrivalTime = lastStop.getAimedArrivalTime() != null - ? lastStop.getAimedArrivalTime() - : lastStop.getAimedDepartureTime(); + ZonedDateTime arrivalTime = lastCall.getAimedArrivalTime() != null + ? lastCall.getAimedArrivalTime() + : lastCall.getAimedDepartureTime(); if (arrivalTime != null) { trips = getMatchingTripsOnStopOrSiblings(stop.getId().getId(), arrivalTime, entityResolver); From 99650d46df01d2645f18b0e2356554e6297c783b Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 11 Feb 2025 12:05:08 +0100 Subject: [PATCH 4/5] Remove Nullable annotation --- .../opentripplanner/updater/siri/SiriFuzzyTripMatcher.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java b/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java index edfb3a5798d..896db3afbb4 100644 --- a/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java +++ b/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java @@ -13,7 +13,6 @@ import java.util.Set; import java.util.function.BiFunction; import java.util.stream.Collectors; -import javax.annotation.Nullable; import org.opentripplanner.model.Timetable; import org.opentripplanner.model.calendar.CalendarService; import org.opentripplanner.transit.model.basic.TransitMode; @@ -61,7 +60,6 @@ public SiriFuzzyTripMatcher(TransitService transitService) { /** * Matches EstimatedVehicleJourney to a set of possible Trips based on tripId */ - @Nullable public Result match( EstimatedVehicleJourney journey, EntityResolver entityResolver, @@ -237,8 +235,7 @@ private Set getCachedTripsByInternalPlanningCode(String internalPlanningCo /** * Finds the correct trip based on OTP-ServiceDate and SIRI-DepartureTime */ - @Nullable - Result getTripAndPatternForJourney( + private Result getTripAndPatternForJourney( Set trips, List calls, EntityResolver entityResolver, From 59888c31eee9ae480c626e67f5404312e3777617 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 11 Feb 2025 12:17:54 +0100 Subject: [PATCH 5/5] Use resolved stop to build cache --- .../updater/siri/SiriFuzzyTripMatcher.java | 23 +++++++++---------- .../siri/SiriFuzzyTripMatcherTest.java | 23 +++++++++++++++++++ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java b/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java index 896db3afbb4..7a9c64703c1 100644 --- a/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java +++ b/application/src/main/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcher.java @@ -97,7 +97,7 @@ public Result match( : lastCall.getAimedDepartureTime(); if (arrivalTime != null) { - trips = getMatchingTripsOnStopOrSiblings(stop.getId().getId(), arrivalTime, entityResolver); + trips = getMatchingTripsOnStopOrSiblings(stop, arrivalTime); } } if (trips == null || trips.isEmpty()) { @@ -173,14 +173,17 @@ private void initCache(TransitService index) { LOG.info("Built start-stop-cache [{}].", startStopTripCache.size()); } + private static String createStartStopKey(RegularStop stop, int lastStopArrivalTime) { + return createStartStopKey(stop.getId().getId(), lastStopArrivalTime); + } + private static String createStartStopKey(String lastStopId, int lastStopArrivalTime) { return lastStopId + ":" + lastStopArrivalTime; } private Set getMatchingTripsOnStopOrSiblings( - String lastStopPoint, - ZonedDateTime arrivalTime, - EntityResolver entityResolver + RegularStop lastStop, + ZonedDateTime arrivalTime ) { int secondsSinceMidnight = ServiceDateUtils.secondsSinceStartOfService( arrivalTime, @@ -193,13 +196,10 @@ private Set getMatchingTripsOnStopOrSiblings( transitService.getTimeZone() ); - Set trips = startStopTripCache.get( - createStartStopKey(lastStopPoint, secondsSinceMidnight) - ); + Set trips = startStopTripCache.get(createStartStopKey(lastStop, secondsSinceMidnight)); if (trips == null) { //Attempt to fetch trips that started yesterday - i.e. add 24 hours to arrival-time - trips = - startStopTripCache.get(createStartStopKey(lastStopPoint, secondsSinceMidnightYesterday)); + trips = startStopTripCache.get(createStartStopKey(lastStop, secondsSinceMidnightYesterday)); } if (trips != null) { @@ -207,13 +207,12 @@ private Set getMatchingTripsOnStopOrSiblings( } //SIRI-data may report other platform, but still on the same Parent-stop - var stop = entityResolver.resolveQuay(lastStopPoint); - if (stop == null || !stop.isPartOfStation()) { + if (!lastStop.isPartOfStation()) { return Set.of(); } trips = new HashSet<>(); - var allQuays = stop.getParentStation().getChildStops(); + var allQuays = lastStop.getParentStation().getChildStops(); for (var quay : allQuays) { Set tripSet = startStopTripCache.get( createStartStopKey(quay.getId().getId(), secondsSinceMidnight) diff --git a/application/src/test/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcherTest.java b/application/src/test/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcherTest.java index 7a3dd791b94..8de77a8b951 100644 --- a/application/src/test/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcherTest.java +++ b/application/src/test/java/org/opentripplanner/updater/siri/SiriFuzzyTripMatcherTest.java @@ -1,9 +1,11 @@ package org.opentripplanner.updater.siri; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.opentripplanner.transit.model._data.TimetableRepositoryForTest.id; import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.MULTIPLE_FUZZY_TRIP_MATCHES; +import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.NO_FUZZY_TRIP_MATCH; import static org.opentripplanner.updater.trip.RealtimeTestConstants.STOP_A1; import static org.opentripplanner.updater.trip.RealtimeTestConstants.STOP_B1; import static org.opentripplanner.updater.trip.RealtimeTestConstants.TRIP_1_ID; @@ -66,6 +68,27 @@ void scheduledStopPoint() { assertTrue(result.isSuccess()); } + @Test + void unknownStopPointRef() { + var trip1input = tripInput(TRIP_1_ID); + + var env = RealtimeTestEnvironment.of().addTrip(trip1input).build(); + + var journey = new SiriEtBuilder(env.getDateTimeHelper()) + .withEstimatedCalls(builder -> + builder + .call(STOP_A1) + .departAimedExpected("00:10:00", "00:10:00") + .call("SOME_MADE_UP_ID") + .arriveAimedExpected("00:20:00", "00:20:00") + ) + .buildEstimatedVehicleJourney(); + + var result = match(journey, env); + assertTrue(result.isFailure()); + assertEquals(NO_FUZZY_TRIP_MATCH, result.failureValue()); + } + private static Result match( EstimatedVehicleJourney evj, RealtimeTestEnvironment env