public Optional<GtfsReader.TripWithStopTimes> getTripUpdate(GTFSFeed staticFeed, GtfsRealtime.TripDescriptor tripDescriptor, Label.Transition boardEdge, Instant boardTime) { logger.trace("getTripUpdate {}", tripDescriptor); if (!isThisRealtimeUpdateAboutThisLineRun(boardEdge.edge.edgeIteratorState, boardTime)) { return Optional.empty(); } else { GtfsRealtime.TripDescriptor normalizedTripDescriptor = normalize(tripDescriptor); return feedMessages.values().stream().flatMap(feedMessage -> feedMessage.getEntityList().stream() .filter(e -> e.hasTripUpdate()) .map(e -> e.getTripUpdate()) .filter(tu -> normalize(tu.getTrip()).equals(normalizedTripDescriptor)) .map(tu -> toTripWithStopTimes(staticFeed, tu))) .findFirst(); } }
public static GtfsReader.TripWithStopTimes toTripWithStopTimes(GTFSFeed feed, GtfsRealtime.TripUpdate tripUpdate) { ZoneId timezone = ZoneId.of(feed.agency.values().stream().findFirst().get().agency_timezone); logger.trace("{}", tripUpdate.getTrip()); final List<StopTime> stopTimes = new ArrayList<>(); Set<Integer> cancelledArrivals = new HashSet<>(); Set<Integer> cancelledDepartures = new HashSet<>(); Trip originalTrip = feed.trips.get(tripUpdate.getTrip().getTripId()); Trip trip = new Trip(); if (originalTrip != null) { trip.route_id = originalTrip.route_id; } else { trip.trip_id = tripUpdate.getTrip().getTripId(); trip.route_id = tripUpdate.getTrip().getRouteId(); Iterable<StopTime> interpolatedStopTimesForTrip; try { interpolatedStopTimesForTrip = feed.getInterpolatedStopTimesForTrip(tripUpdate.getTrip().getTripId()); } catch (GTFSFeed.FirstAndLastStopsDoNotHaveTimes firstAndLastStopsDoNotHaveTimes) { throw new RuntimeException(firstAndLastStopsDoNotHaveTimes); int nextStopSequence = stopTimes.isEmpty() ? 1 : stopTimes.get(stopTimes.size()-1).stop_sequence+1; for (int i=nextStopSequence; i<stopTimeUpdate.getStopSequence(); i++) { StopTime previousOriginalStopTime = feed.stop_times.get(new Fun.Tuple2(tripUpdate.getTrip().getTripId(), i)); if (previousOriginalStopTime == null) { continue; // This can and does happen. Stop sequence numbers can be left out. final StopTime originalStopTime = feed.stop_times.get(new Fun.Tuple2(tripUpdate.getTrip().getTripId(), stopTimeUpdate.getStopSequence())); if (originalStopTime != null) { StopTime updatedStopTime = originalStopTime.clone();
final TripDescriptor tripDescriptor = tripUpdate.getTrip(); if (!tripDescriptor.hasTripId()) { LOG.warn("No trip id found for ADDED trip, skipping.");
/** * Returns vehicle and trip IDs text (vehicle_id X trip_id = Y) for the given entity if the entity is a VehiclePosition, or the trip ID text (trip_id = Y) for the given entity if the entity is a TripUpdate * * @param entity Either the VehiclePosition or TripUpdate for which to generate the ID text * @return vehicle and trip IDs text (vehicle_id X trip_id = Y) for the given entity if the entity is a VehiclePosition, or the trip ID text (trip_id = Y) for the given entity if the entity is a TripUpdate */ public static String getVehicleAndTripIdText(Object entity) { if (!(entity instanceof GtfsRealtime.VehiclePosition || entity instanceof GtfsRealtime.TripUpdate)) { throw new IllegalArgumentException("entity must be instance of VehiclePosition or TripUpdate"); } String ids = null; if (entity instanceof GtfsRealtime.VehiclePosition) { GtfsRealtime.VehiclePosition vp = (GtfsRealtime.VehiclePosition) entity; ids = "vehicle_id " + vp.getVehicle().getId() + " trip_id " + vp.getTrip().getTripId(); } else if (entity instanceof GtfsRealtime.TripUpdate) { GtfsRealtime.TripUpdate tu = (GtfsRealtime.TripUpdate) entity; ids = "trip_id " + tu.getTrip().getTripId(); } return ids; }
/** * Returns vehicle and route IDs text (vehicle_id X route_id = Y) for the given entity if the entity is a VehiclePosition, or the route ID text (route_id = Y) for the given entity if the entity is a TripUpdate * * @param entity Either the VehiclePosition or TripUpdate for which to generate the ID text * @return vehicle and route IDs text (vehicle_id X route_id = Y) for the given entity if the entity is a VehiclePosition, or the route ID text (route_id = Y) for the given entity if the entity is a TripUpdate */ public static String getVehicleAndRouteId(Object entity) { if (!(entity instanceof GtfsRealtime.VehiclePosition || entity instanceof GtfsRealtime.TripUpdate)) { throw new IllegalArgumentException("entity must be instance of VehiclePosition or TripUpdate"); } String ids = null; if (entity instanceof GtfsRealtime.VehiclePosition) { GtfsRealtime.VehiclePosition vp = (GtfsRealtime.VehiclePosition) entity; ids = "vehicle_id " + vp.getVehicle().getId() + " route_id " + vp.getTrip().getRouteId(); } else if (entity instanceof GtfsRealtime.TripUpdate) { GtfsRealtime.TripUpdate tu = (GtfsRealtime.TripUpdate) entity; ids = "route_id " + tu.getTrip().getRouteId(); } return ids; }
/** * Checks E041 "trip doesn't have any stop_time_updates", and adds any errors to the provided error list. * * @param entity entity that the trip_update is from * @param tripUpdate the trip_update to examine * @param errors the list to add the errors to */ private void checkE041(GtfsRealtime.FeedEntity entity, GtfsRealtime.TripUpdate tripUpdate, List<OccurrenceModel> errors) { if (tripUpdate.getStopTimeUpdateCount() < 1) { if (tripUpdate.hasTrip() && tripUpdate.getTrip().hasScheduleRelationship() && tripUpdate.getTrip().getScheduleRelationship().equals(GtfsRealtime.TripDescriptor.ScheduleRelationship.CANCELED)) { // No errors - the trip was canceled, so it doesn't need any stop_time_updates - return return; } RuleUtils.addOccurrence(ValidationRules.E041, GtfsUtils.getTripId(entity, tripUpdate), errors, _log); } }
/** * Returns the trip_id for the given TripUpdate if one exists, if not the entity ID is returned in the format * "trip_id 1234" or "entity ID 4321". * * @param entity the entity that the TripUpdate belongs to * @param tripUpdate the tripUpdate to get the ID for * @return the trip_id for the given TripUpdate if one exists, if not the entity ID is returned in the format "trip_id 1234" or "entity ID 4321". */ public static String getTripId(GtfsRealtime.FeedEntity entity, GtfsRealtime.TripUpdate tripUpdate) { if (!tripUpdate.hasTrip()) { return "entity ID " + entity.getId(); } return getTripId(entity, tripUpdate.getTrip()); }
/** * Checks rule W009 - "schedule_relationship not populated", and adds any warnings that are found to the provided warning list * * @param entity entity which contains the specified trip.stop_time_update * @param stopTimeUpdate stop_time_update to examine to see if it has a schedule_relationship * @param warnings list to add any warnings for W009 to */ private void checkW009(GtfsRealtime.FeedEntity entity, GtfsRealtime.TripUpdate.StopTimeUpdate stopTimeUpdate, List<OccurrenceModel> warnings) { if (stopTimeUpdate != null && !stopTimeUpdate.hasScheduleRelationship()) { RuleUtils.addOccurrence(W009, GtfsUtils.getTripId(entity, entity.getTripUpdate().getTrip()) + " " + GtfsUtils.getStopTimeUpdateId(stopTimeUpdate) + " (and potentially more for this trip)", warnings, _log); } } }
/** * Returns true if this tripUpdate has a trip_id, false if it does not * * @param tripUpdate to examine * @return true if this tripUpdate has a trip_id, false if it does not */ private boolean hasTripId(GtfsRealtime.TripUpdate tripUpdate) { return tripUpdate.hasTrip() && tripUpdate.getTrip().hasTripId(); }
.filter(GtfsRealtime.FeedEntity::hasTripUpdate) .map(GtfsRealtime.FeedEntity::getTripUpdate) .filter(tripUpdate -> tripUpdate.getTrip().getScheduleRelationship() == GtfsRealtime.TripDescriptor.ScheduleRelationship.SCHEDULED) .forEach(tripUpdate -> { Collection<Frequency> frequencies = feed.getFrequencies(tripUpdate.getTrip().getTripId()); int timeOffset = (tripUpdate.getTrip().hasStartTime() && !frequencies.isEmpty()) ? LocalTime.parse(tripUpdate.getTrip().getStartTime()).toSecondOfDay() : 0; String key = GtfsStorage.tripKey(tripUpdate.getTrip(), !frequencies.isEmpty()); final int[] boardEdges = staticGtfs.getBoardEdgesForTrip().get(key); final int[] leaveEdges = staticGtfs.getAlightEdgesForTrip().get(key); if (boardEdges == null || leaveEdges == null) { logger.warn("Trip not found: {}", tripUpdate.getTrip()); return; final StopTime originalStopTime = feed.stop_times.get(new Fun.Tuple2(tripUpdate.getTrip().getTripId(), stopTime.stop_sequence)); int arrivalDelay = stopTime.arrival_time - originalStopTime.arrival_time; delaysForAlightEdges.put(leaveEdges[stopTime.stop_sequence], arrivalDelay * 1000); int boardEdge = boardEdges[stopTime.stop_sequence]; int departureNode = graphHopperStorage.getEdgeIteratorState(boardEdge, Integer.MIN_VALUE).getAdjNode(); int delayedBoardEdge = gtfsReader.addDelayedBoardEdge(timezone, tripUpdate.getTrip(), stopTime.stop_sequence, stopTime.departure_time + timeOffset, departureNode, validOnDay); delaysForBoardEdges.put(delayedBoardEdge, departureDelay * 1000); .filter(GtfsRealtime.FeedEntity::hasTripUpdate) .map(GtfsRealtime.FeedEntity::getTripUpdate) .filter(tripUpdate -> tripUpdate.getTrip().getScheduleRelationship() == GtfsRealtime.TripDescriptor.ScheduleRelationship.ADDED) .forEach(tripUpdate -> { Trip trip = new Trip(); trip.trip_id = tripUpdate.getTrip().getTripId(); trip.route_id = tripUpdate.getTrip().getRouteId();
TripDescriptor tripDescriptor = tripUpdate.getTrip(); if (!tripDescriptor.hasTripId()) { LOG.error("TripDescriptor object has no TripId field");
final TripDescriptor tripDescriptor = tripUpdate.getTrip(); if (!tripDescriptor.hasTripId()) { LOG.warn("No trip id found for MODIFIED trip, skipping.");
final String tripId = tripUpdate.getTrip().getTripId(); cancelPreviouslyAddedTrip(feedId, tripId, serviceDate); if (tripUpdate.getTrip().hasRouteId()) { route = getRouteForRouteId(feedId, tripUpdate.getTrip().getRouteId()); if (tripUpdate.getTrip().hasRouteId()) { route.setId(new FeedScopedId(feedId, tripUpdate.getTrip().getRouteId())); } else { route.setId(new FeedScopedId(feedId, tripId)); trip.setId(new FeedScopedId(feedId, tripUpdate.getTrip().getTripId())); trip.setRoute(route);
public Builder mergeFrom(com.google.transit.realtime.GtfsRealtime.TripUpdate other) { if (other == com.google.transit.realtime.GtfsRealtime.TripUpdate.getDefaultInstance()) return this; if (other.hasTrip()) { mergeTrip(other.getTrip());
public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized != -1) return isInitialized == 1; if (!hasTrip()) { memoizedIsInitialized = 0; return false; } if (!getTrip().isInitialized()) { memoizedIsInitialized = 0; return false; } if (hasVehicle()) { if (!getVehicle().isInitialized()) { memoizedIsInitialized = 0; return false; } } for (int i = 0; i < getStopTimeUpdateCount(); i++) { if (!getStopTimeUpdate(i).isInitialized()) { memoizedIsInitialized = 0; return false; } } if (!extensionsAreInitialized()) { memoizedIsInitialized = 0; return false; } memoizedIsInitialized = 1; return true; }
/** * Handle GTFS-RT TripUpdate message containing a MODIFIED trip. * * @param graph graph to update * @param trip trip that is modified * @param tripUpdate GTFS-RT TripUpdate message * @param stops the stops of each StopTimeUpdate in the TripUpdate message * @param feedId * @param serviceDate service date for modified trip * @return true iff successful */ private boolean handleModifiedTrip(final Graph graph, final Trip trip, final TripUpdate tripUpdate, final List<Stop> stops, final String feedId, final ServiceDate serviceDate) { // Preconditions Preconditions.checkNotNull(stops); Preconditions.checkArgument(tripUpdate.getStopTimeUpdateCount() == stops.size(), "number of stop should match the number of stop time updates"); // Cancel scheduled trip final String tripId = tripUpdate.getTrip().getTripId(); cancelScheduledTrip(feedId, tripId, serviceDate); // Check whether trip id has been used for previously ADDED/MODIFIED trip message and cancel // previously created trip cancelPreviouslyAddedTrip(feedId, tripId, serviceDate); // Add new trip final boolean success = addTripToGraphAndBuffer(feedId, graph, trip, tripUpdate, stops, serviceDate, RealTimeState.MODIFIED); return success; }
private boolean handleScheduledTrip(final TripUpdate tripUpdate, final String feedId, final ServiceDate serviceDate) { final TripDescriptor tripDescriptor = tripUpdate.getTrip(); // This does not include Agency ID or feed ID, trips are feed-unique and we currently assume a single static feed. final String tripId = tripDescriptor.getTripId(); final TripPattern pattern = getPatternForTripId(feedId, tripId); if (pattern == null) { LOG.warn("No pattern found for tripId {}, skipping TripUpdate.", tripId); return false; } if (tripUpdate.getStopTimeUpdateCount() < 1) { LOG.warn("TripUpdate contains no updates, skipping."); return false; } // Apply update on the *scheduled* time table and set the updated trip times in the buffer final TripTimes updatedTripTimes = pattern.scheduledTimetable.createUpdatedTripTimes(tripUpdate, timeZone, serviceDate); if (updatedTripTimes == null) { return false; } // Make sure that updated trip times have the correct real time state updatedTripTimes.setRealTimeState(RealTimeState.UPDATED); final boolean success = buffer.update(feedId, pattern, updatedTripTimes, serviceDate); return success; }
private boolean handleCanceledTrip(final TripUpdate tripUpdate, final String feedId, final ServiceDate serviceDate) { boolean success = false; if (tripUpdate.getTrip().hasTripId()) { // Try to cancel scheduled trip final String tripId = tripUpdate.getTrip().getTripId(); final boolean cancelScheduledSuccess = cancelScheduledTrip(feedId, tripId, serviceDate); // Try to cancel previously added trip final boolean cancelPreviouslyAddedSuccess = cancelPreviouslyAddedTrip(feedId, tripId, serviceDate); if (cancelScheduledSuccess || cancelPreviouslyAddedSuccess) { success = true; } else { LOG.warn("No pattern found for tripId {}, skipping TripUpdate.", tripId); } } else { LOG.warn("No trip id in CANCELED trip update, skipping TripUpdate."); } return success; }