From 5fcdf4aecebd782548b6e87ed5fc874eca2205e6 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Fri, 8 Nov 2024 11:21:14 +0000 Subject: [PATCH 01/16] add test for #6242 --- .../updater/trip/TimetableSnapshotSource.java | 5 +- .../apis/gtfs/GraphQLIntegrationTest.java | 113 +++++++++++++++-- .../updater/trip/TripUpdateBuilder.java | 29 +++-- .../apis/gtfs/expectations/patterns.json | 47 ++++++++ .../apis/gtfs/expectations/realtime-trip.json | 114 ++++++++++++++++++ .../apis/gtfs/queries/realtime-trip.graphql | 38 ++++++ 6 files changed, 327 insertions(+), 19 deletions(-) create mode 100644 application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/realtime-trip.json create mode 100644 application/src/test/resources/org/opentripplanner/apis/gtfs/queries/realtime-trip.graphql diff --git a/application/src/main/java/org/opentripplanner/updater/trip/TimetableSnapshotSource.java b/application/src/main/java/org/opentripplanner/updater/trip/TimetableSnapshotSource.java index 54c3901f3e8..1ea0542eda0 100644 --- a/application/src/main/java/org/opentripplanner/updater/trip/TimetableSnapshotSource.java +++ b/application/src/main/java/org/opentripplanner/updater/trip/TimetableSnapshotSource.java @@ -114,10 +114,9 @@ public TimetableSnapshotSource( } /** - * Constructor is package local to allow unit-tests to provide their own clock, not using system - * time. + * Constructor to allow tests to provide their own clock, not using system time. */ - TimetableSnapshotSource( + public TimetableSnapshotSource( TimetableSnapshotSourceParameters parameters, TimetableRepository timetableRepository, Supplier localDateNow diff --git a/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java index 3aad9075f73..0e64db8979f 100644 --- a/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java +++ b/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java @@ -16,13 +16,16 @@ import static org.opentripplanner.transit.model.basic.TransitMode.FERRY; import static org.opentripplanner.transit.model.timetable.OccupancyStatus.FEW_SEATS_AVAILABLE; +import com.google.transit.realtime.GtfsRealtime; import jakarta.ws.rs.core.Response; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.time.Instant; +import java.time.LocalDate; import java.time.OffsetDateTime; +import java.time.ZoneId; import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.Comparator; @@ -42,7 +45,9 @@ import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.framework.model.Grams; +import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.model.FeedInfo; +import org.opentripplanner.model.calendar.CalendarServiceData; import org.opentripplanner.model.fare.FareMedium; import org.opentripplanner.model.fare.FareProduct; import org.opentripplanner.model.fare.ItineraryFares; @@ -60,6 +65,10 @@ import org.opentripplanner.routing.alertpatch.EntitySelector; import org.opentripplanner.routing.alertpatch.TimePeriod; import org.opentripplanner.routing.alertpatch.TransitAlert; +import org.opentripplanner.routing.algorithm.raptoradapter.transit.TransitLayer; +import org.opentripplanner.routing.algorithm.raptoradapter.transit.TransitTuningParameters; +import org.opentripplanner.routing.algorithm.raptoradapter.transit.mappers.TransitLayerMapper; +import org.opentripplanner.routing.algorithm.raptoradapter.transit.mappers.TransitLayerUpdater; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.graphfinder.GraphFinder; @@ -91,11 +100,18 @@ import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.timetable.RealTimeTripTimes; +import org.opentripplanner.transit.model.timetable.Trip; import org.opentripplanner.transit.model.timetable.TripTimesFactory; import org.opentripplanner.transit.service.DefaultTransitService; import org.opentripplanner.transit.service.TimetableRepository; import org.opentripplanner.transit.service.TransitEditorService; import org.opentripplanner.transit.service.TransitService; +import org.opentripplanner.updater.GtfsRealtimeFuzzyTripMatcher; +import org.opentripplanner.updater.TimetableSnapshotSourceParameters; +import org.opentripplanner.updater.trip.BackwardsDelayPropagationType; +import org.opentripplanner.updater.trip.TimetableSnapshotSource; +import org.opentripplanner.updater.trip.TripUpdateBuilder; +import org.opentripplanner.updater.trip.UpdateIncrementality; import org.opentripplanner.utils.collection.ListUtils; class GraphQLIntegrationTest { @@ -116,6 +132,10 @@ class GraphQLIntegrationTest { .map(p -> (RegularStop) p.stop) .toList(); private static final Route ROUTE = TimetableRepositoryForTest.route("a-route").build(); + private static final String ADDED_TRIP_ID = "ADDED_TRIP"; + private static final String REPLACEMENT_TRIP_ID = "REPLACEMENT_TRIP"; + public static final ZoneId TIME_ZONE = ZoneIds.BERLIN; + public static final String FEED_ID = TimetableRepositoryForTest.FEED_ID; private static VehicleRentalStation VEHICLE_RENTAL_STATION = new TestVehicleRentalStationBuilder() .withVehicles(10) @@ -137,6 +157,8 @@ class GraphQLIntegrationTest { static final Instant ALERT_END_TIME = ALERT_START_TIME.plus(1, ChronoUnit.DAYS); private static final int TEN_MINUTES = 10 * 60; + private static final LocalDate SERVICE_DATE = LocalDate.of(2024, 1, 1); + private static GraphQLRequestContext context; private static final Deduplicator DEDUPLICATOR = new Deduplicator(); @@ -157,10 +179,10 @@ static void setup() { List.of() ); - var siteRepository = TEST_MODEL.siteRepositoryBuilder(); - STOP_LOCATIONS.forEach(siteRepository::withRegularStop); - var model = siteRepository.build(); - var timetableRepository = new TimetableRepository(model, DEDUPLICATOR); + var siteRepositoryBuilder = TEST_MODEL.siteRepositoryBuilder(); + STOP_LOCATIONS.forEach(siteRepositoryBuilder::withRegularStop); + var siteRepository = siteRepositoryBuilder.build(); + var timetableRepository = new TimetableRepository(siteRepository, DEDUPLICATOR); var trip = TimetableRepositoryForTest .trip("123") @@ -168,27 +190,48 @@ static void setup() { .build(); var stopTimes = TEST_MODEL.stopTimesEvery5Minutes(3, trip, T11_00); var tripTimes = TripTimesFactory.tripTimes(trip, stopTimes, DEDUPLICATOR); + + var calendar = new CalendarServiceData(); + FeedScopedId serviceId = calendar.getOrCreateServiceIdForDate(SERVICE_DATE); + + var tripToBeReplaced = TimetableRepositoryForTest + .trip(REPLACEMENT_TRIP_ID) + .withServiceId(serviceId) + .build(); final TripPattern pattern = TEST_MODEL .pattern(BUS) - .withScheduledTimeTableBuilder(builder -> builder.addTripTimes(tripTimes)) + .withScheduledTimeTableBuilder(builder -> + builder + .addTripTimes(tripTimes) + .addTripTimes( + TripTimesFactory.tripTimes( + tripToBeReplaced, + TEST_MODEL.stopTimesEvery5Minutes(3, tripToBeReplaced, T11_30), + DEDUPLICATOR + ) + ) + ) .build(); timetableRepository.addTripPattern(id("pattern-1"), pattern); - var feedId = "testfeed"; - var feedInfo = FeedInfo.dummyForTest(feedId); + var feedInfo = FeedInfo.dummyForTest(FEED_ID); timetableRepository.addFeedInfo(feedInfo); var agency = Agency - .of(new FeedScopedId(feedId, "agency-xx")) + .of(new FeedScopedId(FEED_ID, "agency-xx")) .withName("speedtransit") .withUrl("www.otp-foo.bar") .withTimezone("Europe/Berlin") .build(); timetableRepository.addAgency(agency); - timetableRepository.initTimeZone(ZoneIds.BERLIN); + timetableRepository.initTimeZone(TIME_ZONE); + var serviceCodes = timetableRepository.getServiceCodes(); + serviceCodes.put(serviceId, serviceCodes.size()); + timetableRepository.updateCalendarServiceData(true, calendar, DataImportIssueStore.NOOP); timetableRepository.index(); + var routes = Arrays .stream(TransitMode.values()) .sorted(Comparator.comparing(Enum::name)) @@ -226,6 +269,29 @@ public Set getRoutesForStop(StopLocation stop) { }; routes.forEach(transitService::addRoutes); + timetableRepository.setTransitLayer( + TransitLayerMapper.map(TransitTuningParameters.FOR_TEST, timetableRepository) + ); + timetableRepository.setRealtimeTransitLayer( + new TransitLayer(timetableRepository.getTransitLayer()) + ); + var transitLayerUpdater = new TransitLayerUpdater(transitService); + timetableRepository.setTransitLayerUpdater(transitLayerUpdater); + + var timetableSnapshotProvider = new TimetableSnapshotSource( + TimetableSnapshotSourceParameters.DEFAULT, + timetableRepository, + () -> SERVICE_DATE + ); + timetableSnapshotProvider.applyTripUpdates( + new GtfsRealtimeFuzzyTripMatcher(transitService), + BackwardsDelayPropagationType.REQUIRED_NO_DATA, + UpdateIncrementality.FULL_DATASET, + List.of(getAddedTrip(busRoute), getReplacementTrip(tripToBeReplaced)), + FEED_ID + ); + timetableSnapshotProvider.flushBuffer(); + var step1 = walkStep("street") .withRelativeDirection(RelativeDirection.DEPART) .withAbsoluteDirection(20) @@ -323,6 +389,35 @@ public Set getRoutesForStop(StopLocation stop) { ); } + private static GtfsRealtime.TripUpdate getAddedTrip(Route route) { + var tripUpdateBuilder = new TripUpdateBuilder( + route.getId().getId(), + ADDED_TRIP_ID, + SERVICE_DATE, + GtfsRealtime.TripDescriptor.ScheduleRelationship.ADDED, + TIME_ZONE + ); + tripUpdateBuilder.addStopTime(A.stop.getId().getId(), 0); + tripUpdateBuilder.addStopTime(B.stop.getId().getId(), 300); + tripUpdateBuilder.addStopTime(C.stop.getId().getId(), 600); + tripUpdateBuilder.addStopTime(D.stop.getId().getId(), 900); + return tripUpdateBuilder.build(); + } + + private static GtfsRealtime.TripUpdate getReplacementTrip(Trip trip) { + var tripUpdateBuilder = new TripUpdateBuilder( + trip.getId().getId(), + SERVICE_DATE, + GtfsRealtime.TripDescriptor.ScheduleRelationship.REPLACEMENT, + TIME_ZONE + ); + tripUpdateBuilder.addStopTime(A.stop.getId().getId(), 0); + tripUpdateBuilder.addStopTime(B.stop.getId().getId(), 300); + tripUpdateBuilder.addStopTime(C.stop.getId().getId(), 600); + tripUpdateBuilder.addStopTime(D.stop.getId().getId(), 900); + return tripUpdateBuilder.build(); + } + private static BikeAccess bikesAllowed(TransitMode m) { return switch (m.ordinal() % 3) { case 0 -> BikeAccess.ALLOWED; diff --git a/application/src/test/java/org/opentripplanner/updater/trip/TripUpdateBuilder.java b/application/src/test/java/org/opentripplanner/updater/trip/TripUpdateBuilder.java index e8218edfc1f..16d1efc5ca4 100644 --- a/application/src/test/java/org/opentripplanner/updater/trip/TripUpdateBuilder.java +++ b/application/src/test/java/org/opentripplanner/updater/trip/TripUpdateBuilder.java @@ -37,10 +37,21 @@ public TripUpdateBuilder( this.midnight = ServiceDateUtils.asStartOfService(serviceDate, zoneId); } - public TripUpdateBuilder addStopTime(String stopId, int minutes) { + public TripUpdateBuilder( + String routeId, + String tripId, + LocalDate serviceDate, + GtfsRealtime.TripDescriptor.ScheduleRelationship scheduleRelationship, + ZoneId zoneId + ) { + this(tripId, serviceDate, scheduleRelationship, zoneId); + tripDescriptorBuilder.setRouteId(routeId); + } + + public TripUpdateBuilder addStopTime(String stopId, int secondsFromMidnight) { return addStopTime( stopId, - minutes, + secondsFromMidnight, NO_VALUE, NO_DELAY, NO_DELAY, @@ -49,10 +60,14 @@ public TripUpdateBuilder addStopTime(String stopId, int minutes) { ); } - public TripUpdateBuilder addStopTime(String stopId, int minutes, DropOffPickupType pickDrop) { + public TripUpdateBuilder addStopTime( + String stopId, + int secondsFromMidnight, + DropOffPickupType pickDrop + ) { return addStopTime( stopId, - minutes, + secondsFromMidnight, NO_VALUE, NO_DELAY, NO_DELAY, @@ -122,7 +137,7 @@ public TripUpdateBuilder addRawStopTime(StopTimeUpdate stopTime) { private TripUpdateBuilder addStopTime( String stopId, - int minutes, + int secondsFromMidnight, int stopSequence, int arrivalDelay, int departureDelay, @@ -153,8 +168,8 @@ private TripUpdateBuilder addStopTime( final GtfsRealtime.TripUpdate.StopTimeEvent.Builder arrivalBuilder = stopTimeUpdateBuilder.getArrivalBuilder(); final GtfsRealtime.TripUpdate.StopTimeEvent.Builder departureBuilder = stopTimeUpdateBuilder.getDepartureBuilder(); - if (minutes > NO_VALUE) { - var epochSeconds = midnight.plusHours(8).plusMinutes(minutes).toEpochSecond(); + if (secondsFromMidnight > NO_VALUE) { + var epochSeconds = midnight.plusSeconds(secondsFromMidnight).toEpochSecond(); arrivalBuilder.setTime(epochSeconds); departureBuilder.setTime(epochSeconds); } diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/patterns.json b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/patterns.json index b23ced4f954..a141220d0e9 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/patterns.json +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/patterns.json @@ -51,6 +51,53 @@ "occupancy" : { "occupancyStatus" : "FEW_SEATS_AVAILABLE" } + }, + { + "gtfsId" : "F:REPLACEMENT_TRIP", + "stoptimes" : [ + { + "stop" : { + "gtfsId" : "F:Stop_0", + "name" : "Stop_0" + }, + "headsign" : "Stop headsign at stop 10", + "scheduledArrival" : 41400, + "scheduledDeparture" : 41400, + "stopPosition" : 10, + "realtimeState" : "SCHEDULED", + "pickupType" : "SCHEDULED", + "dropoffType" : "SCHEDULED" + }, + { + "stop" : { + "gtfsId" : "F:Stop_1", + "name" : "Stop_1" + }, + "headsign" : "Stop headsign at stop 20", + "scheduledArrival" : 41700, + "scheduledDeparture" : 41700, + "stopPosition" : 20, + "realtimeState" : "SCHEDULED", + "pickupType" : "SCHEDULED", + "dropoffType" : "SCHEDULED" + }, + { + "stop" : { + "gtfsId" : "F:Stop_2", + "name" : "Stop_2" + }, + "headsign" : "Stop headsign at stop 30", + "scheduledArrival" : 42000, + "scheduledDeparture" : 42000, + "stopPosition" : 30, + "realtimeState" : "SCHEDULED", + "pickupType" : "SCHEDULED", + "dropoffType" : "SCHEDULED" + } + ], + "occupancy" : { + "occupancyStatus" : "NO_DATA_AVAILABLE" + } } ], "vehiclePositions" : [ diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/realtime-trip.json b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/realtime-trip.json new file mode 100644 index 00000000000..258f7ba1ff3 --- /dev/null +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/realtime-trip.json @@ -0,0 +1,114 @@ +{ + "data": { + "addedTrip": { + "gtfsId": "F:ADDED_TRIP", + "timetabledOrigin": null, + "datedOrigin": { + "realtimeDeparture": 0 + }, + "timetabledDestination": null, + "datedDestination": { + "realtimeArrival": 900 + }, + "stoptimes": null, + "stoptimesForDate": [ + { + "stop": { + "gtfsId": "F:A" + }, + "scheduledDeparture": 0, + "realtimeDeparture": 0 + }, + { + "stop": { + "gtfsId": "F:B" + }, + "scheduledDeparture": 300, + "realtimeDeparture": 300 + }, + { + "stop": { + "gtfsId": "F:C" + }, + "scheduledDeparture": 600, + "realtimeDeparture": 600 + }, + { + "stop": { + "gtfsId": "F:D" + }, + "scheduledDeparture": 900, + "realtimeDeparture": 900 + } + ] + }, + "replacementTrip": { + "gtfsId": "F:REPLACEMENT_TRIP", + "timetabledOrigin": { + "scheduledDeparture": 41400 + }, + "datedOrigin": { + "realtimeDeparture": 0 + }, + "timetabledDestination": { + "scheduledArrival": 42000 + }, + "datedDestination": { + "realtimeArrival": 900 + }, + "stoptimes": [ + { + "stop": { + "gtfsId": "F:Stop_0" + }, + "scheduledDeparture": 41400, + "realtimeDeparture": 41400 + }, + { + "stop": { + "gtfsId": "F:Stop_1" + }, + "scheduledDeparture": 41700, + "realtimeDeparture": 41700 + }, + { + "stop": { + "gtfsId": "F:Stop_2" + }, + "scheduledDeparture": 42000, + "realtimeDeparture": 42000 + } + ], + "stoptimesForDate": [ + { + "stop": { + "gtfsId": "F:A" + }, + "scheduledDeparture": 0, + "realtimeDeparture": 0 + }, + { + "stop": { + "gtfsId": "F:B" + }, + "scheduledDeparture": 300, + "realtimeDeparture": 300 + }, + { + "stop": { + "gtfsId": "F:C" + }, + "scheduledDeparture": 600, + "realtimeDeparture": 600 + }, + { + "stop": { + "gtfsId": "F:D" + }, + "scheduledDeparture": 900, + "realtimeDeparture": 900 + } + ] + } + } +} \ No newline at end of file diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/realtime-trip.graphql b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/realtime-trip.graphql new file mode 100644 index 00000000000..5072649e571 --- /dev/null +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/realtime-trip.graphql @@ -0,0 +1,38 @@ +fragment StoptimeSummary on Stoptime { + stop { + gtfsId + } + scheduledDeparture + realtimeDeparture +} + +fragment TripSummary on Trip { + gtfsId + timetabledOrigin: departureStoptime { + scheduledDeparture + } + datedOrigin: departureStoptime(serviceDate: "20240101") { + realtimeDeparture + } + timetabledDestination: arrivalStoptime { + scheduledArrival + } + datedDestination: arrivalStoptime(serviceDate: "20240101") { + realtimeArrival + } + stoptimes { + ...StoptimeSummary + } + stoptimesForDate(serviceDate: "20240101") { + ...StoptimeSummary + } +} + +query GtfsExampleQuery { + addedTrip: trip(id: "F:ADDED_TRIP") { + ...TripSummary + } + replacementTrip: trip(id: "F:REPLACEMENT_TRIP") { + ...TripSummary + } +} From 782730d5c039f33ffca48cf030cf823fb8bef0de Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Fri, 8 Nov 2024 10:22:05 +0000 Subject: [PATCH 02/16] add Nullable annotation --- .../java/org/opentripplanner/model/TripTimeOnDate.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/model/TripTimeOnDate.java b/application/src/main/java/org/opentripplanner/model/TripTimeOnDate.java index 71aaa734f0e..028e91c0fc2 100644 --- a/application/src/main/java/org/opentripplanner/model/TripTimeOnDate.java +++ b/application/src/main/java/org/opentripplanner/model/TripTimeOnDate.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import javax.annotation.Nullable; import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.StopLocation; @@ -31,7 +32,10 @@ public class TripTimeOnDate { private final int stopIndex; // This is only needed because TripTimes has no reference to TripPattern private final TripPattern tripPattern; + + @Nullable private final LocalDate serviceDate; + private final long midnight; public TripTimeOnDate(TripTimes tripTimes, int stopIndex, TripPattern tripPattern) { @@ -46,8 +50,8 @@ public TripTimeOnDate( TripTimes tripTimes, int stopIndex, TripPattern tripPattern, - LocalDate serviceDate, - Instant midnight + @Nullable LocalDate serviceDate, + @Nullable Instant midnight ) { this.tripTimes = tripTimes; this.stopIndex = stopIndex; From 98c5d1363df24449461c9a8c441a033258eef159 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Fri, 8 Nov 2024 13:22:27 +0000 Subject: [PATCH 03/16] refactor arrival and departure stop time --- .../apis/gtfs/datafetchers/TripImpl.java | 93 +++++++++---------- 1 file changed, 44 insertions(+), 49 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java index 956b35309e2..2266da23f63 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java @@ -13,6 +13,7 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; +import javax.annotation.Nullable; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.LineString; import org.opentripplanner.apis.gtfs.GraphQLRequestContext; @@ -36,7 +37,6 @@ import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.timetable.Direction; import org.opentripplanner.transit.model.timetable.Trip; -import org.opentripplanner.transit.model.timetable.TripTimes; import org.opentripplanner.transit.service.TransitService; import org.opentripplanner.utils.time.ServiceDateUtils; @@ -132,38 +132,23 @@ public DataFetcher> alerts() { @Override public DataFetcher arrivalStoptime() { return environment -> { - try { - TransitService transitService = getTransitService(environment); - TripPattern tripPattern = getTripPattern(environment); - if (tripPattern == null) { - return null; - } - Timetable timetable = tripPattern.getScheduledTimetable(); - - TripTimes triptimes = timetable.getTripTimes(getSource(environment)); - LocalDate serviceDate = null; - Instant midnight = null; - - var args = new GraphQLTypes.GraphQLTripArrivalStoptimeArgs(environment.getArguments()); - if (args.getGraphQLServiceDate() != null) { + LocalDate serviceDate = null; + var args = new GraphQLTypes.GraphQLTripArrivalStoptimeArgs(environment.getArguments()); + if (args.getGraphQLServiceDate() != null) { + try { serviceDate = ServiceDateUtils.parseString(args.getGraphQLServiceDate()); - midnight = - ServiceDateUtils - .asStartOfService(serviceDate, transitService.getTimeZone()) - .toInstant(); + } catch (ParseException e) { + //Invalid date format + return null; } + } - return new TripTimeOnDate( - triptimes, - triptimes.getNumStops() - 1, - tripPattern, - serviceDate, - midnight - ); - } catch (ParseException e) { - //Invalid date format + TripPattern tripPattern = getTripPattern(environment); + if (tripPattern == null) { return null; } + + return getStoptimeAtIndex(environment, serviceDate, tripPattern.numberOfStops() - 1); }; } @@ -180,32 +165,23 @@ public DataFetcher blockId() { @Override public DataFetcher departureStoptime() { return environment -> { - try { - TransitService transitService = getTransitService(environment); - TripPattern tripPattern = getTripPattern(environment); - if (tripPattern == null) { - return null; - } - Timetable timetable = tripPattern.getScheduledTimetable(); - - TripTimes triptimes = timetable.getTripTimes(getSource(environment)); - LocalDate serviceDate = null; - Instant midnight = null; - - var args = new GraphQLTypes.GraphQLTripDepartureStoptimeArgs(environment.getArguments()); - if (args.getGraphQLServiceDate() != null) { + LocalDate serviceDate = null; + var args = new GraphQLTypes.GraphQLTripDepartureStoptimeArgs(environment.getArguments()); + if (args.getGraphQLServiceDate() != null) { + try { serviceDate = ServiceDateUtils.parseString(args.getGraphQLServiceDate()); - midnight = - ServiceDateUtils - .asStartOfService(serviceDate, transitService.getTimeZone()) - .toInstant(); + } catch (ParseException e) { + //Invalid date format + return null; } + } - return new TripTimeOnDate(triptimes, 0, tripPattern, serviceDate, midnight); - } catch (ParseException e) { - //Invalid date format + TripPattern tripPattern = getTripPattern(environment); + if (tripPattern == null) { return null; } + + return getStoptimeAtIndex(environment, serviceDate, 0); }; } @@ -408,6 +384,25 @@ private RealtimeVehicleService getRealtimeVehiclesService(DataFetchingEnvironmen return environment.getContext().realTimeVehicleService(); } + private TripTimeOnDate getStoptimeAtIndex( + DataFetchingEnvironment environment, + @Nullable LocalDate serviceDate, + int stopIndex + ) { + var tripPattern = getTripPattern(environment); + return new TripTimeOnDate( + tripPattern.getScheduledTimetable().getTripTimes(getSource(environment)), + stopIndex, + tripPattern, + serviceDate, + serviceDate == null + ? null + : ServiceDateUtils + .asStartOfService(serviceDate, getTransitService(environment).getTimeZone()) + .toInstant() + ); + } + private Trip getSource(DataFetchingEnvironment environment) { return environment.getSource(); } From 38c3a5a4bf6355684a183e70fa560a8ab2877085 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Fri, 8 Nov 2024 14:24:01 +0000 Subject: [PATCH 04/16] fix #6242 --- .../apis/gtfs/datafetchers/TripImpl.java | 36 ++++++++++++++----- .../opentripplanner/model/TripTimeOnDate.java | 12 +++++++ 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java index 2266da23f63..4c41f256a59 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java @@ -143,7 +143,7 @@ public DataFetcher arrivalStoptime() { } } - TripPattern tripPattern = getTripPattern(environment); + TripPattern tripPattern = getTripPattern(environment, serviceDate); if (tripPattern == null) { return null; } @@ -176,7 +176,7 @@ public DataFetcher departureStoptime() { } } - TripPattern tripPattern = getTripPattern(environment); + TripPattern tripPattern = getTripPattern(environment, serviceDate); if (tripPattern == null) { return null; } @@ -301,7 +301,7 @@ public DataFetcher> stoptimesForDate() { ? ServiceDateUtils.parseString(args.getGraphQLServiceDate()) : LocalDate.now(timeZone); - TripPattern tripPattern = transitService.getPatternForTrip(trip, serviceDate); + TripPattern tripPattern = getTripPattern(environment, serviceDate); // no matching pattern found if (tripPattern == null) { return List.of(); @@ -376,6 +376,15 @@ private TripPattern getTripPattern(DataFetchingEnvironment environment) { return getTransitService(environment).getPatternForTrip(environment.getSource()); } + private TripPattern getTripPattern( + DataFetchingEnvironment environment, + @Nullable LocalDate date + ) { + return date == null + ? getTripPattern(environment) + : getTransitService(environment).getPatternForTrip(environment.getSource(), date); + } + private TransitService getTransitService(DataFetchingEnvironment environment) { return environment.getContext().transitService(); } @@ -389,17 +398,28 @@ private TripTimeOnDate getStoptimeAtIndex( @Nullable LocalDate serviceDate, int stopIndex ) { - var tripPattern = getTripPattern(environment); + var tripPattern = getTripPattern(environment, serviceDate); + var transitService = getTransitService(environment); + var timetable = serviceDate != null + ? transitService.getTimetableForTripPattern(tripPattern, serviceDate) + : tripPattern.getScheduledTimetable(); + if (timetable == null) { + return null; + } + + var tripTimes = timetable.getTripTimes(getSource(environment)); + if (tripTimes == null) { + return null; + } + return new TripTimeOnDate( - tripPattern.getScheduledTimetable().getTripTimes(getSource(environment)), + tripTimes, stopIndex, tripPattern, serviceDate, serviceDate == null ? null - : ServiceDateUtils - .asStartOfService(serviceDate, getTransitService(environment).getTimeZone()) - .toInstant() + : ServiceDateUtils.asStartOfService(serviceDate, transitService.getTimeZone()).toInstant() ); } diff --git a/application/src/main/java/org/opentripplanner/model/TripTimeOnDate.java b/application/src/main/java/org/opentripplanner/model/TripTimeOnDate.java index 028e91c0fc2..ef663d9bd06 100644 --- a/application/src/main/java/org/opentripplanner/model/TripTimeOnDate.java +++ b/application/src/main/java/org/opentripplanner/model/TripTimeOnDate.java @@ -63,9 +63,15 @@ public TripTimeOnDate( /** * Must pass in both Timetable and Trip, because TripTimes do not have a reference to * StopPatterns. + * + * @return null if the trip does not exist in the timetable */ + @Nullable public static List fromTripTimes(Timetable table, Trip trip) { TripTimes times = table.getTripTimes(trip); + if (times == null) { + return null; + } List out = new ArrayList<>(); for (int i = 0; i < times.getNumStops(); ++i) { out.add(new TripTimeOnDate(times, i, table.getPattern())); @@ -78,7 +84,10 @@ public static List fromTripTimes(Timetable table, Trip trip) { * StopPatterns. * * @param serviceDate service day to set, if null none is set + * @return null if the trip does not exist in the timetable */ + + @Nullable public static List fromTripTimes( Timetable table, Trip trip, @@ -86,6 +95,9 @@ public static List fromTripTimes( Instant midnight ) { TripTimes times = table.getTripTimes(trip); + if (times == null) { + return null; + } List out = new ArrayList<>(); for (int i = 0; i < times.getNumStops(); ++i) { out.add(new TripTimeOnDate(times, i, table.getPattern(), serviceDate, midnight)); From 8b4b0fe4dfbe4b331c4d98878b265671929d62ba Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 14 Nov 2024 16:47:06 +0000 Subject: [PATCH 05/16] delete TripTimeOnDateHelper and move the logic to DefaultTransitService It has nothing to do with routing and belongs to the wrong package --- .../timetable/DatedServiceJourneyType.java | 4 +- .../model/timetable/ServiceJourneyType.java | 4 +- .../routing/TripTimeOnDateHelper.java | 53 ------------------- .../service/DefaultTransitService.java | 39 ++++++++++++++ .../transit/service/TransitService.java | 2 + 5 files changed, 43 insertions(+), 59 deletions(-) delete mode 100644 application/src/main/java/org/opentripplanner/routing/TripTimeOnDateHelper.java diff --git a/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyType.java b/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyType.java index 7fcce88c4ee..e4d5c03cc79 100644 --- a/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyType.java +++ b/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyType.java @@ -17,7 +17,6 @@ import org.opentripplanner.apis.transmodel.model.framework.TransmodelDirectives; import org.opentripplanner.apis.transmodel.model.framework.TransmodelScalars; import org.opentripplanner.apis.transmodel.support.GqlUtil; -import org.opentripplanner.routing.TripTimeOnDateHelper; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.timetable.TripOnServiceDate; @@ -150,8 +149,7 @@ public static GraphQLObjectType create( ) .dataFetcher(environment -> { TripOnServiceDate tripOnServiceDate = tripOnServiceDate(environment); - return TripTimeOnDateHelper.getTripTimeOnDates( - GqlUtil.getTransitService(environment), + return GqlUtil.getTransitService(environment).getTripTimeOnDates( tripOnServiceDate.getTrip(), tripOnServiceDate.getServiceDate() ); diff --git a/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java b/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java index e61d0a12edc..753b44c2832 100644 --- a/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java +++ b/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java @@ -22,7 +22,6 @@ import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.framework.geometry.EncodedPolyline; import org.opentripplanner.model.TripTimeOnDate; -import org.opentripplanner.routing.TripTimeOnDateHelper; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.timetable.Trip; @@ -274,8 +273,7 @@ public static GraphQLObjectType create( .ofNullable(environment.getArgument("date")) .map(LocalDate.class::cast) .orElse(LocalDate.now(GqlUtil.getTransitService(environment).getTimeZone())); - return TripTimeOnDateHelper.getTripTimeOnDates( - GqlUtil.getTransitService(environment), + return GqlUtil.getTransitService(environment).getTripTimeOnDates( trip(environment), serviceDate ); diff --git a/application/src/main/java/org/opentripplanner/routing/TripTimeOnDateHelper.java b/application/src/main/java/org/opentripplanner/routing/TripTimeOnDateHelper.java deleted file mode 100644 index f2806d0a1f2..00000000000 --- a/application/src/main/java/org/opentripplanner/routing/TripTimeOnDateHelper.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.opentripplanner.routing; - -import java.time.Instant; -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; -import org.opentripplanner.model.Timetable; -import org.opentripplanner.model.TripTimeOnDate; -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.utils.time.ServiceDateUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class TripTimeOnDateHelper { - - private static final Logger LOG = LoggerFactory.getLogger(TripTimeOnDateHelper.class); - - public static List getTripTimeOnDates( - TransitService transitService, - Trip trip, - LocalDate serviceDate - ) { - TripPattern pattern = transitService.getPatternForTrip(trip, serviceDate); - - Timetable timetable = transitService.getTimetableForTripPattern(pattern, serviceDate); - - // If realtime moved pattern back to original trip, fetch it instead - if (timetable.getTripIndex(trip.getId()) == -1) { - LOG.warn( - "Trip {} not found in realtime pattern. This should not happen, and indicates a bug.", - trip - ); - pattern = transitService.getPatternForTrip(trip); - timetable = transitService.getTimetableForTripPattern(pattern, serviceDate); - } - - // This check is made here to avoid changing TripTimeOnDate.fromTripTimes - TripTimes times = timetable.getTripTimes(trip); - if ( - !transitService.getServiceCodesRunningForDate(serviceDate).contains(times.getServiceCode()) - ) { - return new ArrayList<>(); - } else { - Instant midnight = ServiceDateUtils - .asStartOfService(serviceDate, transitService.getTimeZone()) - .toInstant(); - return TripTimeOnDate.fromTripTimes(timetable, trip, serviceDate, midnight); - } - } -} diff --git a/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java b/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java index 5f7cfa95524..41b68c67dc2 100644 --- a/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java +++ b/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java @@ -8,6 +8,7 @@ import java.time.LocalDate; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -57,8 +58,12 @@ import org.opentripplanner.transit.model.timetable.Trip; import org.opentripplanner.transit.model.timetable.TripIdAndServiceDate; import org.opentripplanner.transit.model.timetable.TripOnServiceDate; +import org.opentripplanner.transit.model.timetable.TripTimes; import org.opentripplanner.updater.GraphUpdaterStatus; import org.opentripplanner.utils.collection.CollectionsView; +import org.opentripplanner.utils.time.ServiceDateUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Default implementation of the Transit Service and Transit Editor Service. @@ -68,6 +73,7 @@ */ public class DefaultTransitService implements TransitEditorService { + private static final Logger LOG = LoggerFactory.getLogger(DefaultTransitService.class); private final TimetableRepository timetableRepository; private final TimetableRepositoryIndex timetableRepositoryIndex; @@ -91,6 +97,39 @@ public DefaultTransitService( this.timetableSnapshot = timetableSnapshotBuffer; } + + public List getTripTimeOnDates( + Trip trip, + LocalDate serviceDate + ) { + TripPattern pattern = getPatternForTrip(trip, serviceDate); + + Timetable timetable = getTimetableForTripPattern(pattern, serviceDate); + + // If realtime moved pattern back to original trip, fetch it instead + if (timetable.getTripIndex(trip.getId()) == -1) { + LOG.warn( + "Trip {} not found in realtime pattern. This should not happen, and indicates a bug.", + trip + ); + pattern = getPatternForTrip(trip); + timetable = getTimetableForTripPattern(pattern, serviceDate); + } + + // This check is made here to avoid changing TripTimeOnDate.fromTripTimes + TripTimes times = timetable.getTripTimes(trip); + if ( + !this.getServiceCodesRunningForDate(serviceDate).contains(times.getServiceCode()) + ) { + return new ArrayList<>(); + } else { + Instant midnight = ServiceDateUtils + .asStartOfService(serviceDate, this.getTimeZone()) + .toInstant(); + return TripTimeOnDate.fromTripTimes(timetable, trip, serviceDate, midnight); + } + } + @Override public Collection getFeedIds() { return this.timetableRepository.getFeedIds(); diff --git a/application/src/main/java/org/opentripplanner/transit/service/TransitService.java b/application/src/main/java/org/opentripplanner/transit/service/TransitService.java index 7be2a29065a..7ecc2277ed6 100644 --- a/application/src/main/java/org/opentripplanner/transit/service/TransitService.java +++ b/application/src/main/java/org/opentripplanner/transit/service/TransitService.java @@ -64,6 +64,8 @@ * copy-on-write and shares a lot of objects with any other TransitLayer instances. */ public interface TransitService { + List getTripTimeOnDates(Trip trip, LocalDate serviceDate); + Collection getFeedIds(); Collection getAgencies(); From 816e9c0810e00315396c9039684aa293a0b7ee09 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 14 Nov 2024 16:50:25 +0000 Subject: [PATCH 06/16] move scheduled trip time fetching logic to TransitService --- .../model/timetable/ServiceJourneyType.java | 12 +++--------- .../transit/service/DefaultTransitService.java | 14 +++++++++----- .../transit/service/TransitService.java | 2 ++ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java b/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java index 753b44c2832..975aa8d3422 100644 --- a/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java +++ b/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java @@ -21,7 +21,6 @@ import org.opentripplanner.apis.transmodel.model.framework.TransmodelScalars; import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.framework.geometry.EncodedPolyline; -import org.opentripplanner.model.TripTimeOnDate; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.timetable.Trip; @@ -239,14 +238,9 @@ public static GraphQLObjectType create( .description( "Returns scheduled passing times only - without real-time-updates, for realtime-data use 'estimatedCalls'" ) - .dataFetcher(env -> { - Trip trip = trip(env); - TripPattern tripPattern = GqlUtil.getTransitService(env).getPatternForTrip(trip); - if (tripPattern == null) { - return List.of(); - } - return TripTimeOnDate.fromTripTimes(tripPattern.getScheduledTimetable(), trip); - }) + .dataFetcher(env -> GqlUtil.getTransitService(env).getScheduledTripTimes( + trip(env) + )) .build() ) .field( diff --git a/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java b/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java index 41b68c67dc2..0a401126b81 100644 --- a/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java +++ b/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java @@ -96,12 +96,16 @@ public DefaultTransitService( this(timetableRepository); this.timetableSnapshot = timetableSnapshotBuffer; } - - public List getTripTimeOnDates( - Trip trip, - LocalDate serviceDate - ) { + public List getScheduledTripTimes(Trip trip) { + TripPattern tripPattern = getPatternForTrip(trip); + if (tripPattern == null) { + return List.of(); + } + return TripTimeOnDate.fromTripTimes(tripPattern.getScheduledTimetable(), trip); + } + + public List getTripTimeOnDates(Trip trip, LocalDate serviceDate) { TripPattern pattern = getPatternForTrip(trip, serviceDate); Timetable timetable = getTimetableForTripPattern(pattern, serviceDate); diff --git a/application/src/main/java/org/opentripplanner/transit/service/TransitService.java b/application/src/main/java/org/opentripplanner/transit/service/TransitService.java index 7ecc2277ed6..b56b2ffc41e 100644 --- a/application/src/main/java/org/opentripplanner/transit/service/TransitService.java +++ b/application/src/main/java/org/opentripplanner/transit/service/TransitService.java @@ -64,6 +64,8 @@ * copy-on-write and shares a lot of objects with any other TransitLayer instances. */ public interface TransitService { + List getScheduledTripTimes(Trip trip); + List getTripTimeOnDates(Trip trip, LocalDate serviceDate); Collection getFeedIds(); From 9df81a3523f1b847bd0b790f2951b9ab0c12f885 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 14 Nov 2024 16:57:48 +0000 Subject: [PATCH 07/16] use trip time logic in TransitService from GTFS GraphQL TripImpl --- .../apis/gtfs/datafetchers/TripImpl.java | 102 +++++------------- 1 file changed, 27 insertions(+), 75 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java index 4c41f256a59..ad984acf46c 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java @@ -4,7 +4,6 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import java.text.ParseException; -import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; import java.util.ArrayList; @@ -24,7 +23,6 @@ import org.opentripplanner.apis.gtfs.mapping.BikesAllowedMapper; import org.opentripplanner.apis.gtfs.model.TripOccupancy; import org.opentripplanner.apis.support.SemanticHash; -import org.opentripplanner.model.Timetable; import org.opentripplanner.model.TripTimeOnDate; import org.opentripplanner.routing.alertpatch.EntitySelector; import org.opentripplanner.routing.alertpatch.TransitAlert; @@ -104,12 +102,12 @@ public DataFetcher> alerts() { .anyMatch(entity -> ( entity instanceof EntitySelector.StopAndRoute stopAndRoute && - stopAndRoute.routeId().equals(getRoute(environment).getId()) + stopAndRoute.routeId().equals(getRoute(environment).getId()) ) || - ( - entity instanceof EntitySelector.StopAndTrip stopAndTrip && - stopAndTrip.tripId().equals(getSource(environment).getId()) - ) + ( + entity instanceof EntitySelector.StopAndTrip stopAndTrip && + stopAndTrip.tripId().equals(getSource(environment).getId()) + ) ) ) .toList() @@ -143,12 +141,12 @@ public DataFetcher arrivalStoptime() { } } - TripPattern tripPattern = getTripPattern(environment, serviceDate); - if (tripPattern == null) { - return null; - } - - return getStoptimeAtIndex(environment, serviceDate, tripPattern.numberOfStops() - 1); + var trip = getSource(environment); + var transitService = getTransitService(environment); + var stopTimes = serviceDate == null + ? transitService.getScheduledTripTimes(trip) + : transitService.getTripTimeOnDates(trip, serviceDate); + return stopTimes.getLast(); }; } @@ -176,12 +174,12 @@ public DataFetcher departureStoptime() { } } - TripPattern tripPattern = getTripPattern(environment, serviceDate); - if (tripPattern == null) { - return null; - } - - return getStoptimeAtIndex(environment, serviceDate, 0); + var trip = getSource(environment); + var transitService = getTransitService(environment); + var stopTimes = serviceDate == null + ? transitService.getScheduledTripTimes(trip) + : transitService.getTripTimeOnDates(trip, serviceDate); + return stopTimes.getFirst(); }; } @@ -276,43 +274,27 @@ public DataFetcher> stops() { @Override public DataFetcher> stoptimes() { - return environment -> { - TripPattern tripPattern = getTripPattern(environment); - if (tripPattern == null) { - return List.of(); - } - return TripTimeOnDate.fromTripTimes( - tripPattern.getScheduledTimetable(), - getSource(environment) - ); - }; + return environment -> getTransitService(environment).getScheduledTripTimes(getSource(environment)); } @Override public DataFetcher> stoptimesForDate() { return environment -> { - try { - TransitService transitService = getTransitService(environment); - Trip trip = getSource(environment); - var args = new GraphQLTypes.GraphQLTripStoptimesForDateArgs(environment.getArguments()); + TransitService transitService = getTransitService(environment); + Trip trip = getSource(environment); + var args = new GraphQLTypes.GraphQLTripStoptimesForDateArgs(environment.getArguments()); - ZoneId timeZone = transitService.getTimeZone(); - LocalDate serviceDate = args.getGraphQLServiceDate() != null + ZoneId timeZone = transitService.getTimeZone(); + LocalDate serviceDate; + try { + serviceDate = args.getGraphQLServiceDate() != null ? ServiceDateUtils.parseString(args.getGraphQLServiceDate()) : LocalDate.now(timeZone); - - TripPattern tripPattern = getTripPattern(environment, serviceDate); - // no matching pattern found - if (tripPattern == null) { - return List.of(); - } - - Instant midnight = ServiceDateUtils.asStartOfService(serviceDate, timeZone).toInstant(); - Timetable timetable = transitService.getTimetableForTripPattern(tripPattern, serviceDate); - return TripTimeOnDate.fromTripTimes(timetable, trip, serviceDate, midnight); } catch (ParseException e) { return null; // Invalid date format } + + return transitService.getTripTimeOnDates(trip, serviceDate); }; } @@ -393,36 +375,6 @@ private RealtimeVehicleService getRealtimeVehiclesService(DataFetchingEnvironmen return environment.getContext().realTimeVehicleService(); } - private TripTimeOnDate getStoptimeAtIndex( - DataFetchingEnvironment environment, - @Nullable LocalDate serviceDate, - int stopIndex - ) { - var tripPattern = getTripPattern(environment, serviceDate); - var transitService = getTransitService(environment); - var timetable = serviceDate != null - ? transitService.getTimetableForTripPattern(tripPattern, serviceDate) - : tripPattern.getScheduledTimetable(); - if (timetable == null) { - return null; - } - - var tripTimes = timetable.getTripTimes(getSource(environment)); - if (tripTimes == null) { - return null; - } - - return new TripTimeOnDate( - tripTimes, - stopIndex, - tripPattern, - serviceDate, - serviceDate == null - ? null - : ServiceDateUtils.asStartOfService(serviceDate, transitService.getTimeZone()).toInstant() - ); - } - private Trip getSource(DataFetchingEnvironment environment) { return environment.getSource(); } From 8cf5e9b902159c3c533469ffc3f936e10d9bae8b Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 14 Nov 2024 16:58:25 +0000 Subject: [PATCH 08/16] reformat code --- .../apis/gtfs/datafetchers/TripImpl.java | 22 ++++++++++--------- .../timetable/DatedServiceJourneyType.java | 7 +++--- .../model/timetable/ServiceJourneyType.java | 11 ++++------ 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java index ad984acf46c..0a65c168346 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java @@ -102,12 +102,12 @@ public DataFetcher> alerts() { .anyMatch(entity -> ( entity instanceof EntitySelector.StopAndRoute stopAndRoute && - stopAndRoute.routeId().equals(getRoute(environment).getId()) + stopAndRoute.routeId().equals(getRoute(environment).getId()) ) || - ( - entity instanceof EntitySelector.StopAndTrip stopAndTrip && - stopAndTrip.tripId().equals(getSource(environment).getId()) - ) + ( + entity instanceof EntitySelector.StopAndTrip stopAndTrip && + stopAndTrip.tripId().equals(getSource(environment).getId()) + ) ) ) .toList() @@ -274,7 +274,8 @@ public DataFetcher> stops() { @Override public DataFetcher> stoptimes() { - return environment -> getTransitService(environment).getScheduledTripTimes(getSource(environment)); + return environment -> + getTransitService(environment).getScheduledTripTimes(getSource(environment)); } @Override @@ -287,13 +288,14 @@ public DataFetcher> stoptimesForDate() { ZoneId timeZone = transitService.getTimeZone(); LocalDate serviceDate; try { - serviceDate = args.getGraphQLServiceDate() != null - ? ServiceDateUtils.parseString(args.getGraphQLServiceDate()) - : LocalDate.now(timeZone); + serviceDate = + args.getGraphQLServiceDate() != null + ? ServiceDateUtils.parseString(args.getGraphQLServiceDate()) + : LocalDate.now(timeZone); } catch (ParseException e) { return null; // Invalid date format } - + return transitService.getTripTimeOnDates(trip, serviceDate); }; } diff --git a/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyType.java b/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyType.java index e4d5c03cc79..2bd9918680d 100644 --- a/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyType.java +++ b/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyType.java @@ -149,10 +149,9 @@ public static GraphQLObjectType create( ) .dataFetcher(environment -> { TripOnServiceDate tripOnServiceDate = tripOnServiceDate(environment); - return GqlUtil.getTransitService(environment).getTripTimeOnDates( - tripOnServiceDate.getTrip(), - tripOnServiceDate.getServiceDate() - ); + return GqlUtil + .getTransitService(environment) + .getTripTimeOnDates(tripOnServiceDate.getTrip(), tripOnServiceDate.getServiceDate()); }) .build() ) diff --git a/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java b/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java index 975aa8d3422..1baa8ff6be9 100644 --- a/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java +++ b/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java @@ -238,9 +238,7 @@ public static GraphQLObjectType create( .description( "Returns scheduled passing times only - without real-time-updates, for realtime-data use 'estimatedCalls'" ) - .dataFetcher(env -> GqlUtil.getTransitService(env).getScheduledTripTimes( - trip(env) - )) + .dataFetcher(env -> GqlUtil.getTransitService(env).getScheduledTripTimes(trip(env))) .build() ) .field( @@ -267,10 +265,9 @@ public static GraphQLObjectType create( .ofNullable(environment.getArgument("date")) .map(LocalDate.class::cast) .orElse(LocalDate.now(GqlUtil.getTransitService(environment).getTimeZone())); - return GqlUtil.getTransitService(environment).getTripTimeOnDates( - trip(environment), - serviceDate - ); + return GqlUtil + .getTransitService(environment) + .getTripTimeOnDates(trip(environment), serviceDate); }) .build() ) From d6da96498a3a29e81946623d3dd2224b10de46e8 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 14 Nov 2024 17:01:57 +0000 Subject: [PATCH 09/16] do not silently return null in case of invalid date better to let error propagate --- .../apis/gtfs/datafetchers/TripImpl.java | 28 ++++--------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java index 0a65c168346..41330ee3039 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java @@ -3,7 +3,6 @@ import graphql.relay.Relay; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; -import java.text.ParseException; import java.time.LocalDate; import java.time.ZoneId; import java.util.ArrayList; @@ -133,12 +132,7 @@ public DataFetcher arrivalStoptime() { LocalDate serviceDate = null; var args = new GraphQLTypes.GraphQLTripArrivalStoptimeArgs(environment.getArguments()); if (args.getGraphQLServiceDate() != null) { - try { - serviceDate = ServiceDateUtils.parseString(args.getGraphQLServiceDate()); - } catch (ParseException e) { - //Invalid date format - return null; - } + serviceDate = ServiceDateUtils.parseString(args.getGraphQLServiceDate()); } var trip = getSource(environment); @@ -166,12 +160,7 @@ public DataFetcher departureStoptime() { LocalDate serviceDate = null; var args = new GraphQLTypes.GraphQLTripDepartureStoptimeArgs(environment.getArguments()); if (args.getGraphQLServiceDate() != null) { - try { - serviceDate = ServiceDateUtils.parseString(args.getGraphQLServiceDate()); - } catch (ParseException e) { - //Invalid date format - return null; - } + serviceDate = ServiceDateUtils.parseString(args.getGraphQLServiceDate()); } var trip = getSource(environment); @@ -286,15 +275,10 @@ public DataFetcher> stoptimesForDate() { var args = new GraphQLTypes.GraphQLTripStoptimesForDateArgs(environment.getArguments()); ZoneId timeZone = transitService.getTimeZone(); - LocalDate serviceDate; - try { - serviceDate = - args.getGraphQLServiceDate() != null - ? ServiceDateUtils.parseString(args.getGraphQLServiceDate()) - : LocalDate.now(timeZone); - } catch (ParseException e) { - return null; // Invalid date format - } + LocalDate serviceDate = + args.getGraphQLServiceDate() != null + ? ServiceDateUtils.parseString(args.getGraphQLServiceDate()) + : LocalDate.now(timeZone); return transitService.getTripTimeOnDates(trip, serviceDate); }; From cd74120c76ceb3c2ecbb5cd4f0e644efab55ca67 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 14 Nov 2024 17:06:45 +0000 Subject: [PATCH 10/16] refactor date parsing --- .../apis/gtfs/datafetchers/TripImpl.java | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java index 41330ee3039..5e1871e57a4 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java @@ -3,6 +3,7 @@ import graphql.relay.Relay; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.text.ParseException; import java.time.LocalDate; import java.time.ZoneId; import java.util.ArrayList; @@ -129,17 +130,11 @@ public DataFetcher> alerts() { @Override public DataFetcher arrivalStoptime() { return environment -> { - LocalDate serviceDate = null; - var args = new GraphQLTypes.GraphQLTripArrivalStoptimeArgs(environment.getArguments()); - if (args.getGraphQLServiceDate() != null) { - serviceDate = ServiceDateUtils.parseString(args.getGraphQLServiceDate()); - } - + var serviceDate = getOptionalServiceDateArgument(environment); var trip = getSource(environment); var transitService = getTransitService(environment); - var stopTimes = serviceDate == null - ? transitService.getScheduledTripTimes(trip) - : transitService.getTripTimeOnDates(trip, serviceDate); + var stopTimes = serviceDate.map(date -> transitService.getTripTimeOnDates(trip, date)) + .orElseGet(() -> transitService.getScheduledTripTimes(trip)); return stopTimes.getLast(); }; } @@ -157,17 +152,11 @@ public DataFetcher blockId() { @Override public DataFetcher departureStoptime() { return environment -> { - LocalDate serviceDate = null; - var args = new GraphQLTypes.GraphQLTripDepartureStoptimeArgs(environment.getArguments()); - if (args.getGraphQLServiceDate() != null) { - serviceDate = ServiceDateUtils.parseString(args.getGraphQLServiceDate()); - } - + var serviceDate = getOptionalServiceDateArgument(environment); var trip = getSource(environment); var transitService = getTransitService(environment); - var stopTimes = serviceDate == null - ? transitService.getScheduledTripTimes(trip) - : transitService.getTripTimeOnDates(trip, serviceDate); + var stopTimes = serviceDate.map(date -> transitService.getTripTimeOnDates(trip, date)) + .orElseGet(() -> transitService.getScheduledTripTimes(trip)); return stopTimes.getFirst(); }; } @@ -361,6 +350,14 @@ private RealtimeVehicleService getRealtimeVehiclesService(DataFetchingEnvironmen return environment.getContext().realTimeVehicleService(); } + private static Optional getOptionalServiceDateArgument(DataFetchingEnvironment environment) throws ParseException { + var args = new GraphQLTypes.GraphQLTripArrivalStoptimeArgs(environment.getArguments()); + if (args.getGraphQLServiceDate() != null) { + return Optional.of(ServiceDateUtils.parseString(args.getGraphQLServiceDate())); + } + return Optional.empty(); + } + private Trip getSource(DataFetchingEnvironment environment) { return environment.getSource(); } From 29db2ef6bbd83c9ccabeaec8b1570e4bc6d4a042 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 14 Nov 2024 17:07:23 +0000 Subject: [PATCH 11/16] reformat code --- .../apis/gtfs/datafetchers/TripImpl.java | 17 ++++++++++------- .../transit/service/DefaultTransitService.java | 8 +++----- .../transit/service/TransitService.java | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java index 5e1871e57a4..0b2eb2077b2 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java @@ -133,7 +133,8 @@ public DataFetcher arrivalStoptime() { var serviceDate = getOptionalServiceDateArgument(environment); var trip = getSource(environment); var transitService = getTransitService(environment); - var stopTimes = serviceDate.map(date -> transitService.getTripTimeOnDates(trip, date)) + var stopTimes = serviceDate + .map(date -> transitService.getTripTimeOnDates(trip, date)) .orElseGet(() -> transitService.getScheduledTripTimes(trip)); return stopTimes.getLast(); }; @@ -155,7 +156,8 @@ public DataFetcher departureStoptime() { var serviceDate = getOptionalServiceDateArgument(environment); var trip = getSource(environment); var transitService = getTransitService(environment); - var stopTimes = serviceDate.map(date -> transitService.getTripTimeOnDates(trip, date)) + var stopTimes = serviceDate + .map(date -> transitService.getTripTimeOnDates(trip, date)) .orElseGet(() -> transitService.getScheduledTripTimes(trip)); return stopTimes.getFirst(); }; @@ -264,10 +266,9 @@ public DataFetcher> stoptimesForDate() { var args = new GraphQLTypes.GraphQLTripStoptimesForDateArgs(environment.getArguments()); ZoneId timeZone = transitService.getTimeZone(); - LocalDate serviceDate = - args.getGraphQLServiceDate() != null - ? ServiceDateUtils.parseString(args.getGraphQLServiceDate()) - : LocalDate.now(timeZone); + LocalDate serviceDate = args.getGraphQLServiceDate() != null + ? ServiceDateUtils.parseString(args.getGraphQLServiceDate()) + : LocalDate.now(timeZone); return transitService.getTripTimeOnDates(trip, serviceDate); }; @@ -350,7 +351,9 @@ private RealtimeVehicleService getRealtimeVehiclesService(DataFetchingEnvironmen return environment.getContext().realTimeVehicleService(); } - private static Optional getOptionalServiceDateArgument(DataFetchingEnvironment environment) throws ParseException { + private static Optional getOptionalServiceDateArgument( + DataFetchingEnvironment environment + ) throws ParseException { var args = new GraphQLTypes.GraphQLTripArrivalStoptimeArgs(environment.getArguments()); if (args.getGraphQLServiceDate() != null) { return Optional.of(ServiceDateUtils.parseString(args.getGraphQLServiceDate())); diff --git a/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java b/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java index 0a401126b81..2ecc29e3e63 100644 --- a/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java +++ b/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java @@ -96,7 +96,7 @@ public DefaultTransitService( this(timetableRepository); this.timetableSnapshot = timetableSnapshotBuffer; } - + public List getScheduledTripTimes(Trip trip) { TripPattern tripPattern = getPatternForTrip(trip); if (tripPattern == null) { @@ -104,7 +104,7 @@ public List getScheduledTripTimes(Trip trip) { } return TripTimeOnDate.fromTripTimes(tripPattern.getScheduledTimetable(), trip); } - + public List getTripTimeOnDates(Trip trip, LocalDate serviceDate) { TripPattern pattern = getPatternForTrip(trip, serviceDate); @@ -122,9 +122,7 @@ public List getTripTimeOnDates(Trip trip, LocalDate serviceDate) // This check is made here to avoid changing TripTimeOnDate.fromTripTimes TripTimes times = timetable.getTripTimes(trip); - if ( - !this.getServiceCodesRunningForDate(serviceDate).contains(times.getServiceCode()) - ) { + if (!this.getServiceCodesRunningForDate(serviceDate).contains(times.getServiceCode())) { return new ArrayList<>(); } else { Instant midnight = ServiceDateUtils diff --git a/application/src/main/java/org/opentripplanner/transit/service/TransitService.java b/application/src/main/java/org/opentripplanner/transit/service/TransitService.java index b56b2ffc41e..d8b7444581c 100644 --- a/application/src/main/java/org/opentripplanner/transit/service/TransitService.java +++ b/application/src/main/java/org/opentripplanner/transit/service/TransitService.java @@ -65,7 +65,7 @@ */ public interface TransitService { List getScheduledTripTimes(Trip trip); - + List getTripTimeOnDates(Trip trip, LocalDate serviceDate); Collection getFeedIds(); From 38dd2aa0f6a3f73651d9176e12a1662501be6437 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 14 Nov 2024 18:09:58 +0000 Subject: [PATCH 12/16] add test for new transit service methods --- .../opentripplanner/model/TripTimeOnDate.java | 19 ++++ .../service/DefaultTransitServiceTest.java | 100 +++++++++++++++--- 2 files changed, 102 insertions(+), 17 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/model/TripTimeOnDate.java b/application/src/main/java/org/opentripplanner/model/TripTimeOnDate.java index ef663d9bd06..d5e59d7322b 100644 --- a/application/src/main/java/org/opentripplanner/model/TripTimeOnDate.java +++ b/application/src/main/java/org/opentripplanner/model/TripTimeOnDate.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Objects; import javax.annotation.Nullable; import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.transit.model.network.TripPattern; @@ -286,4 +287,22 @@ public BookingInfo getPickupBookingInfo() { public BookingInfo getDropOffBookingInfo() { return tripTimes.getDropOffBookingInfo(stopIndex); } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + TripTimeOnDate that = (TripTimeOnDate) o; + return ( + stopIndex == that.stopIndex && + midnight == that.midnight && + Objects.equals(tripTimes, that.tripTimes) && + Objects.equals(tripPattern, that.tripPattern) && + Objects.equals(serviceDate, that.serviceDate) + ); + } + + @Override + public int hashCode() { + return Objects.hash(tripTimes, stopIndex, tripPattern, serviceDate, midnight); + } } diff --git a/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java b/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java index 1c0d2a03a0f..94b522db2d9 100644 --- a/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java +++ b/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java @@ -6,16 +6,21 @@ import static org.opentripplanner.transit.model.basic.TransitMode.RAIL; import static org.opentripplanner.transit.model.basic.TransitMode.TRAM; +import java.time.Instant; import java.time.LocalDate; import java.util.Collection; import java.util.List; import java.util.Set; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.model.RealTimeTripUpdate; import org.opentripplanner.model.TimetableSnapshot; +import org.opentripplanner.model.TripTimeOnDate; +import org.opentripplanner.model.calendar.CalendarServiceData; import org.opentripplanner.transit.model._data.TimetableRepositoryForTest; import org.opentripplanner.transit.model.framework.Deduplicator; +import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.network.StopPattern; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.RegularStop; @@ -23,32 +28,64 @@ import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.timetable.RealTimeTripTimes; import org.opentripplanner.transit.model.timetable.ScheduledTripTimes; +import org.opentripplanner.transit.model.timetable.Trip; +import org.opentripplanner.utils.time.ServiceDateUtils; class DefaultTransitServiceTest { private static final TimetableRepositoryForTest TEST_MODEL = TimetableRepositoryForTest.of(); - static TransitService service; - static Station STATION = TEST_MODEL.station("C").build(); - static RegularStop STOP_A = TEST_MODEL + private static TransitService service; + private static final Station STATION = TEST_MODEL.station("C").build(); + private static final RegularStop STOP_A = TEST_MODEL .stop("A") .withVehicleType(TRAM) .withParentStation(STATION) .build(); - static RegularStop STOP_B = TEST_MODEL.stop("B").withParentStation(STATION).build(); - static TripPattern RAIL_PATTERN = TEST_MODEL.pattern(RAIL).build(); - static TripPattern FERRY_PATTERN = TEST_MODEL.pattern(FERRY).build(); - static TripPattern BUS_PATTERN = TEST_MODEL.pattern(BUS).build(); + private static final RegularStop STOP_B = TEST_MODEL.stop("B").withParentStation(STATION).build(); - static StopPattern REAL_TIME_STOP_PATTERN = TimetableRepositoryForTest.stopPattern( + private static final FeedScopedId SERVICE_ID = new FeedScopedId("FEED", "SERVICE"); + private static final int SERVICE_CODE = 0; + private static final Trip TRIP = TimetableRepositoryForTest + .trip("REAL_TIME_TRIP") + .withServiceId(SERVICE_ID) + .build(); + private static final ScheduledTripTimes SCHEDULED_TRIP_TIMES = ScheduledTripTimes + .of() + .withTrip(TRIP) + .withArrivalTimes(new int[] { 0, 1 }) + .withDepartureTimes(new int[] { 0, 1 }) + .withServiceCode(SERVICE_CODE) + .build(); + + private static final TripPattern RAIL_PATTERN = TEST_MODEL + .pattern(RAIL) + .withScheduledTimeTableBuilder(builder -> builder.addTripTimes(SCHEDULED_TRIP_TIMES)) + .build(); + private static final TripPattern FERRY_PATTERN = TEST_MODEL.pattern(FERRY).build(); + private static final TripPattern BUS_PATTERN = TEST_MODEL.pattern(BUS).build(); + + private static final StopPattern REAL_TIME_STOP_PATTERN = TimetableRepositoryForTest.stopPattern( STOP_A, STOP_B ); - static TripPattern REAL_TIME_PATTERN = TEST_MODEL + private static final TripPattern REAL_TIME_PATTERN = TEST_MODEL .pattern(BUS) .withStopPattern(REAL_TIME_STOP_PATTERN) .withCreatedByRealtimeUpdater(true) .build(); + private static final int DELAY = 120; + private static final RealTimeTripTimes REALTIME_TRIP_TIMES = SCHEDULED_TRIP_TIMES.copyScheduledTimes(); + + static { + for (var i = 0; i < REALTIME_TRIP_TIMES.getNumStops(); ++i) { + REALTIME_TRIP_TIMES.updateArrivalDelay(i, DefaultTransitServiceTest.DELAY); + REALTIME_TRIP_TIMES.updateDepartureDelay(i, DefaultTransitServiceTest.DELAY); + } + } + + private static final LocalDate SERVICE_DATE = LocalDate.of(2024, 1, 1); + private static final LocalDate NO_SERVICE_DATE = LocalDate.of(2000, 1, 1); @BeforeAll static void setup() { @@ -60,20 +97,18 @@ static void setup() { .build(); var timetableRepository = new TimetableRepository(siteRepository, new Deduplicator()); + var calendar = new CalendarServiceData(); + calendar.putServiceDatesForServiceId(SERVICE_ID, List.of(SERVICE_DATE)); + var serviceCodes = timetableRepository.getServiceCodes(); + serviceCodes.put(SERVICE_ID, SERVICE_CODE); + timetableRepository.updateCalendarServiceData(true, calendar, DataImportIssueStore.NOOP); timetableRepository.addTripPattern(RAIL_PATTERN.getId(), RAIL_PATTERN); timetableRepository.index(); timetableRepository.initTimetableSnapshotProvider(() -> { TimetableSnapshot timetableSnapshot = new TimetableSnapshot(); - RealTimeTripTimes tripTimes = RealTimeTripTimes.of( - ScheduledTripTimes - .of() - .withTrip(TimetableRepositoryForTest.trip("REAL_TIME_TRIP").build()) - .withDepartureTimes(new int[] { 0, 1 }) - .build() - ); timetableSnapshot.update( - new RealTimeTripUpdate(REAL_TIME_PATTERN, tripTimes, LocalDate.now()) + new RealTimeTripUpdate(REAL_TIME_PATTERN, REALTIME_TRIP_TIMES, SERVICE_DATE) ); return timetableSnapshot.commit(); @@ -121,4 +156,35 @@ void getPatternForStopsWithRealTime() { Collection patternsForStop = service.getPatternsForStop(STOP_B, true); assertEquals(Set.of(FERRY_PATTERN, RAIL_PATTERN, REAL_TIME_PATTERN), patternsForStop); } + + @Test + void getScheduledTripTimes() { + assertEquals( + List.of( + new TripTimeOnDate(SCHEDULED_TRIP_TIMES, 0, RAIL_PATTERN), + new TripTimeOnDate(SCHEDULED_TRIP_TIMES, 1, RAIL_PATTERN) + ), + service.getScheduledTripTimes(TRIP) + ); + } + + @Test + void getRealtimeTripTimes() { + Instant midnight = ServiceDateUtils + .asStartOfService(SERVICE_DATE, service.getTimeZone()) + .toInstant(); + + assertEquals( + List.of( + new TripTimeOnDate(REALTIME_TRIP_TIMES, 0, REAL_TIME_PATTERN, SERVICE_DATE, midnight), + new TripTimeOnDate(REALTIME_TRIP_TIMES, 1, REAL_TIME_PATTERN, SERVICE_DATE, midnight) + ), + service.getTripTimeOnDates(TRIP, SERVICE_DATE) + ); + } + + @Test + void getTripTimesOnNoServiceDay() { + assertEquals(List.of(), service.getTripTimeOnDates(TRIP, NO_SERVICE_DATE)); + } } From d3d283fc5d7ae3250ddc76fd29a5c232c42ca32d Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 14 Nov 2024 18:30:09 +0000 Subject: [PATCH 13/16] use optional for trip time on dates it can be empty if the trip doesn't run at all --- .../apis/gtfs/datafetchers/TripImpl.java | 8 +-- .../timetable/DatedServiceJourneyType.java | 3 +- .../model/timetable/ServiceJourneyType.java | 3 +- .../service/DefaultTransitService.java | 17 +++--- .../transit/service/TransitService.java | 10 +++- .../service/DefaultTransitServiceTest.java | 58 ++++++++++++++++--- 6 files changed, 75 insertions(+), 24 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java index 0b2eb2077b2..243ce6d1897 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripImpl.java @@ -136,7 +136,7 @@ public DataFetcher arrivalStoptime() { var stopTimes = serviceDate .map(date -> transitService.getTripTimeOnDates(trip, date)) .orElseGet(() -> transitService.getScheduledTripTimes(trip)); - return stopTimes.getLast(); + return stopTimes.map(List::getLast).orElse(null); }; } @@ -159,7 +159,7 @@ public DataFetcher departureStoptime() { var stopTimes = serviceDate .map(date -> transitService.getTripTimeOnDates(trip, date)) .orElseGet(() -> transitService.getScheduledTripTimes(trip)); - return stopTimes.getFirst(); + return stopTimes.map(List::getFirst).orElse(null); }; } @@ -255,7 +255,7 @@ public DataFetcher> stops() { @Override public DataFetcher> stoptimes() { return environment -> - getTransitService(environment).getScheduledTripTimes(getSource(environment)); + getTransitService(environment).getScheduledTripTimes(getSource(environment)).orElse(null); } @Override @@ -270,7 +270,7 @@ public DataFetcher> stoptimesForDate() { ? ServiceDateUtils.parseString(args.getGraphQLServiceDate()) : LocalDate.now(timeZone); - return transitService.getTripTimeOnDates(trip, serviceDate); + return transitService.getTripTimeOnDates(trip, serviceDate).orElse(null); }; } diff --git a/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyType.java b/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyType.java index 2bd9918680d..93458f01771 100644 --- a/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyType.java +++ b/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyType.java @@ -151,7 +151,8 @@ public static GraphQLObjectType create( TripOnServiceDate tripOnServiceDate = tripOnServiceDate(environment); return GqlUtil .getTransitService(environment) - .getTripTimeOnDates(tripOnServiceDate.getTrip(), tripOnServiceDate.getServiceDate()); + .getTripTimeOnDates(tripOnServiceDate.getTrip(), tripOnServiceDate.getServiceDate()) + .orElse(null); }) .build() ) diff --git a/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java b/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java index 1baa8ff6be9..2aeea5dbfba 100644 --- a/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java +++ b/application/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java @@ -267,7 +267,8 @@ public static GraphQLObjectType create( .orElse(LocalDate.now(GqlUtil.getTransitService(environment).getTimeZone())); return GqlUtil .getTransitService(environment) - .getTripTimeOnDates(trip(environment), serviceDate); + .getTripTimeOnDates(trip(environment), serviceDate) + .orElse(null); }) .build() ) diff --git a/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java b/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java index 2ecc29e3e63..0f2a0350f5e 100644 --- a/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java +++ b/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java @@ -8,7 +8,6 @@ import java.time.LocalDate; import java.time.ZoneId; import java.time.ZonedDateTime; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -97,15 +96,17 @@ public DefaultTransitService( this.timetableSnapshot = timetableSnapshotBuffer; } - public List getScheduledTripTimes(Trip trip) { + public Optional> getScheduledTripTimes(Trip trip) { TripPattern tripPattern = getPatternForTrip(trip); if (tripPattern == null) { - return List.of(); + return Optional.empty(); } - return TripTimeOnDate.fromTripTimes(tripPattern.getScheduledTimetable(), trip); + return Optional.ofNullable( + TripTimeOnDate.fromTripTimes(tripPattern.getScheduledTimetable(), trip) + ); } - public List getTripTimeOnDates(Trip trip, LocalDate serviceDate) { + public Optional> getTripTimeOnDates(Trip trip, LocalDate serviceDate) { TripPattern pattern = getPatternForTrip(trip, serviceDate); Timetable timetable = getTimetableForTripPattern(pattern, serviceDate); @@ -123,12 +124,14 @@ public List getTripTimeOnDates(Trip trip, LocalDate serviceDate) // This check is made here to avoid changing TripTimeOnDate.fromTripTimes TripTimes times = timetable.getTripTimes(trip); if (!this.getServiceCodesRunningForDate(serviceDate).contains(times.getServiceCode())) { - return new ArrayList<>(); + return Optional.empty(); } else { Instant midnight = ServiceDateUtils .asStartOfService(serviceDate, this.getTimeZone()) .toInstant(); - return TripTimeOnDate.fromTripTimes(timetable, trip, serviceDate, midnight); + return Optional.ofNullable( + TripTimeOnDate.fromTripTimes(timetable, trip, serviceDate, midnight) + ); } } diff --git a/application/src/main/java/org/opentripplanner/transit/service/TransitService.java b/application/src/main/java/org/opentripplanner/transit/service/TransitService.java index d8b7444581c..292fb59c786 100644 --- a/application/src/main/java/org/opentripplanner/transit/service/TransitService.java +++ b/application/src/main/java/org/opentripplanner/transit/service/TransitService.java @@ -64,9 +64,15 @@ * copy-on-write and shares a lot of objects with any other TransitLayer instances. */ public interface TransitService { - List getScheduledTripTimes(Trip trip); + /** + * @return empty if the trip doesn't exist in the timetable (e.g. real-time added) + */ + Optional> getScheduledTripTimes(Trip trip); - List getTripTimeOnDates(Trip trip, LocalDate serviceDate); + /** + * @return empty if the trip doesn't run on the date specified + */ + Optional> getTripTimeOnDates(Trip trip, LocalDate serviceDate); Collection getFeedIds(); diff --git a/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java b/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java index 94b522db2d9..9b84ab1ee22 100644 --- a/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java +++ b/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java @@ -10,6 +10,7 @@ import java.time.LocalDate; import java.util.Collection; import java.util.List; +import java.util.Optional; import java.util.Set; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -46,8 +47,9 @@ class DefaultTransitServiceTest { private static final FeedScopedId SERVICE_ID = new FeedScopedId("FEED", "SERVICE"); private static final int SERVICE_CODE = 0; - private static final Trip TRIP = TimetableRepositoryForTest - .trip("REAL_TIME_TRIP") + private static final Trip TRIP = TimetableRepositoryForTest.trip("REAL_TIME_TRIP").build(); + private static final Trip ADDED_TRIP = TimetableRepositoryForTest + .trip("REAL_TIME_ADDED_TRIP") .withServiceId(SERVICE_ID) .build(); private static final ScheduledTripTimes SCHEDULED_TRIP_TIMES = ScheduledTripTimes @@ -76,6 +78,15 @@ class DefaultTransitServiceTest { .build(); private static final int DELAY = 120; private static final RealTimeTripTimes REALTIME_TRIP_TIMES = SCHEDULED_TRIP_TIMES.copyScheduledTimes(); + private static final RealTimeTripTimes ADDED_TRIP_TIMES = RealTimeTripTimes.of( + ScheduledTripTimes + .of() + .withTrip(ADDED_TRIP) + .withArrivalTimes(new int[] { 10, 11 }) + .withDepartureTimes(new int[] { 10, 11 }) + .withServiceCode(SERVICE_CODE) + .build() + ); static { for (var i = 0; i < REALTIME_TRIP_TIMES.getNumStops(); ++i) { @@ -110,6 +121,9 @@ static void setup() { timetableSnapshot.update( new RealTimeTripUpdate(REAL_TIME_PATTERN, REALTIME_TRIP_TIMES, SERVICE_DATE) ); + timetableSnapshot.update( + new RealTimeTripUpdate(REAL_TIME_PATTERN, ADDED_TRIP_TIMES, SERVICE_DATE) + ); return timetableSnapshot.commit(); }); @@ -160,9 +174,11 @@ void getPatternForStopsWithRealTime() { @Test void getScheduledTripTimes() { assertEquals( - List.of( - new TripTimeOnDate(SCHEDULED_TRIP_TIMES, 0, RAIL_PATTERN), - new TripTimeOnDate(SCHEDULED_TRIP_TIMES, 1, RAIL_PATTERN) + Optional.of( + List.of( + new TripTimeOnDate(SCHEDULED_TRIP_TIMES, 0, RAIL_PATTERN), + new TripTimeOnDate(SCHEDULED_TRIP_TIMES, 1, RAIL_PATTERN) + ) ), service.getScheduledTripTimes(TRIP) ); @@ -175,9 +191,11 @@ void getRealtimeTripTimes() { .toInstant(); assertEquals( - List.of( - new TripTimeOnDate(REALTIME_TRIP_TIMES, 0, REAL_TIME_PATTERN, SERVICE_DATE, midnight), - new TripTimeOnDate(REALTIME_TRIP_TIMES, 1, REAL_TIME_PATTERN, SERVICE_DATE, midnight) + Optional.of( + List.of( + new TripTimeOnDate(REALTIME_TRIP_TIMES, 0, REAL_TIME_PATTERN, SERVICE_DATE, midnight), + new TripTimeOnDate(REALTIME_TRIP_TIMES, 1, REAL_TIME_PATTERN, SERVICE_DATE, midnight) + ) ), service.getTripTimeOnDates(TRIP, SERVICE_DATE) ); @@ -185,6 +203,28 @@ void getRealtimeTripTimes() { @Test void getTripTimesOnNoServiceDay() { - assertEquals(List.of(), service.getTripTimeOnDates(TRIP, NO_SERVICE_DATE)); + assertEquals(Optional.empty(), service.getTripTimeOnDates(TRIP, NO_SERVICE_DATE)); + } + + @Test + void getScheduledTripTimesForAddedTrip() { + assertEquals(Optional.empty(), service.getScheduledTripTimes(ADDED_TRIP)); + } + + @Test + void getRealtimeTripTimesForAddedTrip() { + Instant midnight = ServiceDateUtils + .asStartOfService(SERVICE_DATE, service.getTimeZone()) + .toInstant(); + + assertEquals( + Optional.of( + List.of( + new TripTimeOnDate(ADDED_TRIP_TIMES, 0, REAL_TIME_PATTERN, SERVICE_DATE, midnight), + new TripTimeOnDate(ADDED_TRIP_TIMES, 1, REAL_TIME_PATTERN, SERVICE_DATE, midnight) + ) + ), + service.getTripTimeOnDates(ADDED_TRIP, SERVICE_DATE) + ); } } From 7ad5e63afa2ac2d889bb1c45841495bc9dd02366 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Tue, 26 Nov 2024 16:37:54 +0000 Subject: [PATCH 14/16] update test for latest dev --- .../org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java index 1d35cabb4d5..43eb6d18454 100644 --- a/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java +++ b/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java @@ -206,7 +206,7 @@ static void setup() { .addTripTimes( TripTimesFactory.tripTimes( tripToBeReplaced, - TEST_MODEL.stopTimesEvery5Minutes(3, tripToBeReplaced, T11_30), + TEST_MODEL.stopTimesEvery5Minutes(3, tripToBeReplaced, "11:30"), DEDUPLICATOR ) ) From bdc6c0aae037c048ec67bfaf684cca8620abe96c Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Wed, 27 Nov 2024 14:19:22 +0000 Subject: [PATCH 15/16] stub the real time information in GraphQL intergration test --- .../apis/gtfs/GraphQLIntegrationTest.java | 123 ++++++++---------- 1 file changed, 54 insertions(+), 69 deletions(-) diff --git a/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java index 43eb6d18454..468bc3a077d 100644 --- a/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java +++ b/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java @@ -16,7 +16,6 @@ import static org.opentripplanner.transit.model.basic.TransitMode.FERRY; import static org.opentripplanner.transit.model.timetable.OccupancyStatus.FEW_SEATS_AVAILABLE; -import com.google.transit.realtime.GtfsRealtime; import jakarta.ws.rs.core.Response; import java.io.IOException; import java.nio.file.Files; @@ -27,10 +26,12 @@ import java.time.OffsetDateTime; import java.time.ZoneId; import java.time.temporal.ChronoUnit; +import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.Locale; +import java.util.Optional; import java.util.Set; import java.util.stream.Stream; import org.glassfish.jersey.message.internal.OutboundJaxrsResponse; @@ -45,8 +46,8 @@ import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.framework.model.Grams; -import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.model.FeedInfo; +import org.opentripplanner.model.TripTimeOnDate; import org.opentripplanner.model.calendar.CalendarServiceData; import org.opentripplanner.model.fare.FareMedium; import org.opentripplanner.model.fare.FareProduct; @@ -65,10 +66,6 @@ import org.opentripplanner.routing.alertpatch.EntitySelector; import org.opentripplanner.routing.alertpatch.TimePeriod; import org.opentripplanner.routing.alertpatch.TransitAlert; -import org.opentripplanner.routing.algorithm.raptoradapter.transit.TransitLayer; -import org.opentripplanner.routing.algorithm.raptoradapter.transit.TransitTuningParameters; -import org.opentripplanner.routing.algorithm.raptoradapter.transit.mappers.TransitLayerMapper; -import org.opentripplanner.routing.algorithm.raptoradapter.transit.mappers.TransitLayerUpdater; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.graphfinder.GraphFinder; @@ -106,12 +103,6 @@ import org.opentripplanner.transit.service.TimetableRepository; import org.opentripplanner.transit.service.TransitEditorService; import org.opentripplanner.transit.service.TransitService; -import org.opentripplanner.updater.GtfsRealtimeFuzzyTripMatcher; -import org.opentripplanner.updater.TimetableSnapshotSourceParameters; -import org.opentripplanner.updater.trip.BackwardsDelayPropagationType; -import org.opentripplanner.updater.trip.TimetableSnapshotSource; -import org.opentripplanner.updater.trip.TripUpdateBuilder; -import org.opentripplanner.updater.trip.UpdateIncrementality; import org.opentripplanner.utils.collection.ListUtils; class GraphQLIntegrationTest { @@ -226,12 +217,8 @@ static void setup() { .build(); timetableRepository.addAgency(agency); - timetableRepository.initTimeZone(TIME_ZONE); - var serviceCodes = timetableRepository.getServiceCodes(); - serviceCodes.put(serviceId, serviceCodes.size()); - timetableRepository.updateCalendarServiceData(true, calendar, DataImportIssueStore.NOOP); + timetableRepository.initTimeZone(ZoneIds.BERLIN); timetableRepository.index(); - var routes = Arrays .stream(TransitMode.values()) .sorted(Comparator.comparing(Enum::name)) @@ -252,6 +239,11 @@ static void setup() { timetableRepository ); + private final Trip addedTrip = Trip + .of(new FeedScopedId(FEED_ID, ADDED_TRIP_ID)) + .withRoute(busRoute) + .build(); + @Override public List getModesOfStopLocation(StopLocation stop) { return List.of(BUS, FERRY); @@ -266,31 +258,53 @@ public TransitAlertService getTransitAlertService() { public Set getRoutesForStop(StopLocation stop) { return Set.of(ROUTE); } - }; - routes.forEach(transitService::addRoutes); - timetableRepository.setTransitLayer( - TransitLayerMapper.map(TransitTuningParameters.FOR_TEST, timetableRepository) - ); - timetableRepository.setRealtimeTransitLayer( - new TransitLayer(timetableRepository.getTransitLayer()) - ); - var transitLayerUpdater = new TransitLayerUpdater(transitService); - timetableRepository.setTransitLayerUpdater(transitLayerUpdater); + @Override + public Trip getTripForId(FeedScopedId id) { + if (addedTrip.getId().equals(id)) { + return addedTrip; + } - var timetableSnapshotProvider = new TimetableSnapshotSource( - TimetableSnapshotSourceParameters.DEFAULT, - timetableRepository, - () -> SERVICE_DATE - ); - timetableSnapshotProvider.applyTripUpdates( - new GtfsRealtimeFuzzyTripMatcher(transitService), - BackwardsDelayPropagationType.REQUIRED_NO_DATA, - UpdateIncrementality.FULL_DATASET, - List.of(getAddedTrip(busRoute), getReplacementTrip(tripToBeReplaced)), - FEED_ID - ); - timetableSnapshotProvider.flushBuffer(); + return super.getTripForId(id); + } + + @Override + public Optional> getTripTimeOnDates(Trip trip, LocalDate serviceDate) { + if (serviceDate.equals(SERVICE_DATE)) { + if ( + addedTrip.equals(trip) || + trip.getId().equals(new FeedScopedId(FEED_ID, REPLACEMENT_TRIP_ID)) + ) { + var stopCount = 4; + var tripTimes = TripTimesFactory.tripTimes( + trip, + TEST_MODEL.stopTimesEvery5Minutes(4, trip, "00:00"), + new Deduplicator() + ); + var tripPattern = TripPattern + .of(new FeedScopedId(FEED_ID, "ADDED_TRIP_PATTERN")) + .withRoute(trip.getRoute()) + .withStopPattern( + TimetableRepositoryForTest.stopPattern( + (RegularStop) A.stop, + (RegularStop) B.stop, + (RegularStop) C.stop, + (RegularStop) D.stop + ) + ) + .build(); + var result = new ArrayList(stopCount); + for (var i = 0; i < stopCount; ++i) { + result.add(new TripTimeOnDate(tripTimes, i, tripPattern)); + } + return Optional.of(result); + } + } + + return super.getTripTimeOnDates(trip, serviceDate); + } + }; + routes.forEach(transitService::addRoutes); var step1 = walkStep("street") .withRelativeDirection(RelativeDirection.DEPART) @@ -389,35 +403,6 @@ public Set getRoutesForStop(StopLocation stop) { ); } - private static GtfsRealtime.TripUpdate getAddedTrip(Route route) { - var tripUpdateBuilder = new TripUpdateBuilder( - route.getId().getId(), - ADDED_TRIP_ID, - SERVICE_DATE, - GtfsRealtime.TripDescriptor.ScheduleRelationship.ADDED, - TIME_ZONE - ); - tripUpdateBuilder.addStopTime(A.stop.getId().getId(), 0); - tripUpdateBuilder.addStopTime(B.stop.getId().getId(), 300); - tripUpdateBuilder.addStopTime(C.stop.getId().getId(), 600); - tripUpdateBuilder.addStopTime(D.stop.getId().getId(), 900); - return tripUpdateBuilder.build(); - } - - private static GtfsRealtime.TripUpdate getReplacementTrip(Trip trip) { - var tripUpdateBuilder = new TripUpdateBuilder( - trip.getId().getId(), - SERVICE_DATE, - GtfsRealtime.TripDescriptor.ScheduleRelationship.REPLACEMENT, - TIME_ZONE - ); - tripUpdateBuilder.addStopTime(A.stop.getId().getId(), 0); - tripUpdateBuilder.addStopTime(B.stop.getId().getId(), 300); - tripUpdateBuilder.addStopTime(C.stop.getId().getId(), 600); - tripUpdateBuilder.addStopTime(D.stop.getId().getId(), 900); - return tripUpdateBuilder.build(); - } - private static BikeAccess bikesAllowed(TransitMode m) { return switch (m.ordinal() % 3) { case 0 -> BikeAccess.ALLOWED; From 4b501298f940d602b5943b76a4b84ad9451a999d Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Wed, 27 Nov 2024 14:56:52 +0000 Subject: [PATCH 16/16] format JSON files --- .../apis/gtfs/expectations/patterns.json | 74 +++++++++---------- .../apis/gtfs/expectations/realtime-trip.json | 2 +- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/patterns.json b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/patterns.json index 3896fb1bbef..8612663e4cc 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/patterns.json +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/patterns.json @@ -56,53 +56,53 @@ } }, { - "gtfsId" : "F:REPLACEMENT_TRIP", - "stoptimes" : [ + "gtfsId": "F:REPLACEMENT_TRIP", + "stoptimes": [ { - "stop" : { - "gtfsId" : "F:Stop_0", - "name" : "Stop_0" + "stop": { + "gtfsId": "F:Stop_0", + "name": "Stop_0" }, - "headsign" : "Stop headsign at stop 10", - "scheduledArrival" : 41400, - "scheduledDeparture" : 41400, - "stopPosition" : 10, - "stopPositionInPattern" : 0, - "realtimeState" : "SCHEDULED", - "pickupType" : "SCHEDULED", - "dropoffType" : "SCHEDULED" + "headsign": "Stop headsign at stop 10", + "scheduledArrival": 41400, + "scheduledDeparture": 41400, + "stopPosition": 10, + "stopPositionInPattern": 0, + "realtimeState": "SCHEDULED", + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED" }, { - "stop" : { - "gtfsId" : "F:Stop_1", - "name" : "Stop_1" + "stop": { + "gtfsId": "F:Stop_1", + "name": "Stop_1" }, - "headsign" : "Stop headsign at stop 20", - "scheduledArrival" : 41700, - "scheduledDeparture" : 41700, - "stopPosition" : 20, - "stopPositionInPattern" : 1, - "realtimeState" : "SCHEDULED", - "pickupType" : "SCHEDULED", - "dropoffType" : "SCHEDULED" + "headsign": "Stop headsign at stop 20", + "scheduledArrival": 41700, + "scheduledDeparture": 41700, + "stopPosition": 20, + "stopPositionInPattern": 1, + "realtimeState": "SCHEDULED", + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED" }, { - "stop" : { - "gtfsId" : "F:Stop_2", - "name" : "Stop_2" + "stop": { + "gtfsId": "F:Stop_2", + "name": "Stop_2" }, - "headsign" : "Stop headsign at stop 30", - "scheduledArrival" : 42000, - "scheduledDeparture" : 42000, - "stopPosition" : 30, - "stopPositionInPattern" : 2, - "realtimeState" : "SCHEDULED", - "pickupType" : "SCHEDULED", - "dropoffType" : "SCHEDULED" + "headsign": "Stop headsign at stop 30", + "scheduledArrival": 42000, + "scheduledDeparture": 42000, + "stopPosition": 30, + "stopPositionInPattern": 2, + "realtimeState": "SCHEDULED", + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED" } ], - "occupancy" : { - "occupancyStatus" : "NO_DATA_AVAILABLE" + "occupancy": { + "occupancyStatus": "NO_DATA_AVAILABLE" } } ], diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/realtime-trip.json b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/realtime-trip.json index 258f7ba1ff3..7faf0a13d6b 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/realtime-trip.json +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/realtime-trip.json @@ -111,4 +111,4 @@ ] } } -} \ No newline at end of file +}