use of com.google.transit.realtime.GtfsRealtime.TripDescriptor in project onebusaway-application-modules by camsys.
the class TripUpdateConvertor method readFeedEntity.
@Override
public TripUpdateModel readFeedEntity(FeedEntity entity, long timestamp) {
if (entity.hasTripUpdate()) {
TripUpdateModel tu = new TripUpdateModel();
TripDescriptor t = entity.getTripUpdate().getTrip();
if (entity.getTripUpdate().hasTimestamp()) {
timestamp = entity.getTripUpdate().getTimestamp() * 1000;
}
tu.setTimestamp(new Date(timestamp));
if (entity.getTripUpdate().hasDelay()) {
tu.setDelay(entity.getTripUpdate().getDelay());
}
if (t.hasTripId())
tu.setTripId(t.getTripId());
if (t.hasRouteId()) {
tu.setRouteId(t.getRouteId());
}
if (t.hasStartDate() && t.hasStartTime()) {
tu.setTripStart(GtfsRealtimeConversionLibrary.parseDate(t.getStartDate(), t.getStartTime()));
}
tu.setScheduleRelationship(findRelationship(t));
VehicleDescriptor vehicle = entity.getTripUpdate().getVehicle();
if (vehicle != null) {
tu.setVehicleId(vehicle.getId());
tu.setVehicleLabel(vehicle.getLabel());
tu.setVehicleLicensePlate(vehicle.getLicensePlate());
}
for (StopTimeUpdate stu : entity.getTripUpdate().getStopTimeUpdateList()) {
StopTimeUpdateModel stopTimeUpdate = readStopTimeUpdate(stu, tu.getScheduleRelationship());
if (stopTimeUpdate != null) {
stopTimeUpdate.setTripUpdateModel(tu);
tu.addStopTimeUpdateModel(stopTimeUpdate);
}
}
return tu;
}
return null;
}
use of com.google.transit.realtime.GtfsRealtime.TripDescriptor in project onebusaway-application-modules by camsys.
the class VehiclePositionConvertor method readFeedEntity.
@Override
public VehiclePositionModel readFeedEntity(FeedEntity entity, long timestamp) {
if (entity == null)
return null;
VehiclePositionModel vpm = new VehiclePositionModel();
if (entity.hasVehicle()) {
if (entity.getVehicle().hasTimestamp()) {
timestamp = entity.getVehicle().getTimestamp() * 1000;
}
if (entity.getVehicle().hasTrip()) {
TripDescriptor td = entity.getVehicle().getTrip();
if (td.hasTripId()) {
vpm.setTripId(td.getTripId());
}
if (td.hasRouteId()) {
vpm.setRouteId(td.getRouteId());
}
if (td.hasStartDate() && td.hasStartTime()) {
vpm.setTripStart(GtfsRealtimeConversionLibrary.parseDate(td.getStartDate(), td.getStartTime()));
}
}
if (entity.getVehicle().hasVehicle()) {
VehicleDescriptor vd = entity.getVehicle().getVehicle();
if (vd.hasId()) {
vpm.setVehicleId(vd.getId());
}
if (vd.hasLabel()) {
vpm.setVehicleLabel(vd.getLabel());
}
if (vd.hasLicensePlate()) {
vpm.setVehicleLicensePlate(vd.getLicensePlate());
}
}
if (entity.getVehicle().hasPosition()) {
Position p = entity.getVehicle().getPosition();
vpm.setLat(p.getLatitude());
vpm.setLon(p.getLongitude());
if (p.hasBearing()) {
vpm.setBearing(p.getBearing());
}
if (p.hasSpeed()) {
vpm.setSpeed(p.getSpeed());
}
}
if (entity.getVehicle().hasTrip()) {
if (vpm.getTripId() == null) {
if (entity.getVehicle().getTrip().hasTripId()) {
vpm.setTripId(entity.getVehicle().getTrip().getTripId());
}
}
if (vpm.getRouteId() == null) {
if (entity.getVehicle().getTrip().hasRouteId()) {
vpm.setRouteId(entity.getVehicle().getTrip().getRouteId());
}
}
}
}
if (entity.getVehicle().hasStopId()) {
vpm.setStopId(entity.getVehicle().getStopId());
}
vpm.setTimestamp(new Date(timestamp));
return vpm;
}
use of com.google.transit.realtime.GtfsRealtime.TripDescriptor in project OpenTripPlanner by opentripplanner.
the class Timetable method createUpdatedTripTimes.
/**
* Apply the TripUpdate to the appropriate TripTimes from this Timetable. The existing TripTimes
* must not be modified directly because they may be shared with the underlying
* scheduledTimetable, or other updated Timetables. The {@link TimetableSnapshot} performs the
* protective copying of this Timetable. It is not done in this update method to avoid
* repeatedly cloning the same Timetable when several updates are applied to it at once. We
* assume here that all trips in a timetable are from the same feed, which should always be the
* case.
*
* @param tripUpdate GTFS-RT trip update
* @param timeZone time zone of trip update
* @param updateServiceDate service date of trip update
* @return new copy of updated TripTimes after TripUpdate has been applied on TripTimes of trip
* with the id specified in the trip descriptor of the TripUpdate; null if something
* went wrong
*/
public TripTimes createUpdatedTripTimes(TripUpdate tripUpdate, TimeZone timeZone, ServiceDate updateServiceDate) {
if (tripUpdate == null) {
LOG.error("A null TripUpdate pointer was passed to the Timetable class update method.");
return null;
}
// However, we want to apply trip updates on top of *scheduled* times
if (!tripUpdate.hasTrip()) {
LOG.error("TripUpdate object has no TripDescriptor field.");
return null;
}
TripDescriptor tripDescriptor = tripUpdate.getTrip();
if (!tripDescriptor.hasTripId()) {
LOG.error("TripDescriptor object has no TripId field");
return null;
}
String tripId = tripDescriptor.getTripId();
int tripIndex = getTripIndex(tripId);
if (tripIndex == -1) {
LOG.info("tripId {} not found in pattern.", tripId);
return null;
} else {
LOG.trace("tripId {} found at index {} in timetable.", tripId, tripIndex);
}
TripTimes newTimes = new TripTimes(getTripTimes(tripIndex));
if (tripDescriptor.hasScheduleRelationship() && tripDescriptor.getScheduleRelationship() == TripDescriptor.ScheduleRelationship.CANCELED) {
newTimes.cancel();
} else {
// The GTFS-RT reference specifies that StopTimeUpdates are sorted by stop_sequence.
Iterator<StopTimeUpdate> updates = tripUpdate.getStopTimeUpdateList().iterator();
if (!updates.hasNext()) {
LOG.warn("Won't apply zero-length trip update to trip {}.", tripId);
return null;
}
StopTimeUpdate update = updates.next();
int numStops = newTimes.getNumStops();
Integer delay = null;
for (int i = 0; i < numStops; i++) {
boolean match = false;
if (update != null) {
if (update.hasStopSequence()) {
match = update.getStopSequence() == newTimes.getStopSequence(i);
} else if (update.hasStopId()) {
match = pattern.getStop(i).getId().getId().equals(update.getStopId());
}
}
if (match) {
StopTimeUpdate.ScheduleRelationship scheduleRelationship = update.hasScheduleRelationship() ? update.getScheduleRelationship() : StopTimeUpdate.ScheduleRelationship.SCHEDULED;
if (scheduleRelationship == StopTimeUpdate.ScheduleRelationship.SKIPPED) {
LOG.warn("Partially canceled trips are unsupported by this method." + " Skipping TripUpdate.");
return null;
} else if (scheduleRelationship == StopTimeUpdate.ScheduleRelationship.NO_DATA) {
newTimes.updateArrivalDelay(i, 0);
newTimes.updateDepartureDelay(i, 0);
delay = 0;
} else {
long today = updateServiceDate.getAsDate(timeZone).getTime() / 1000;
if (update.hasArrival()) {
StopTimeEvent arrival = update.getArrival();
if (arrival.hasDelay()) {
delay = arrival.getDelay();
if (arrival.hasTime()) {
newTimes.updateArrivalTime(i, (int) (arrival.getTime() - today));
} else {
newTimes.updateArrivalDelay(i, delay);
}
} else if (arrival.hasTime()) {
newTimes.updateArrivalTime(i, (int) (arrival.getTime() - today));
delay = newTimes.getArrivalDelay(i);
} else {
LOG.error("Arrival time at index {} is erroneous.", i);
return null;
}
} else {
if (delay == null) {
newTimes.updateArrivalTime(i, TripTimes.UNAVAILABLE);
} else {
newTimes.updateArrivalDelay(i, delay);
}
}
if (update.hasDeparture()) {
StopTimeEvent departure = update.getDeparture();
if (departure.hasDelay()) {
delay = departure.getDelay();
if (departure.hasTime()) {
newTimes.updateDepartureTime(i, (int) (departure.getTime() - today));
} else {
newTimes.updateDepartureDelay(i, delay);
}
} else if (departure.hasTime()) {
newTimes.updateDepartureTime(i, (int) (departure.getTime() - today));
delay = newTimes.getDepartureDelay(i);
} else {
LOG.error("Departure time at index {} is erroneous.", i);
return null;
}
} else {
if (delay == null) {
newTimes.updateDepartureTime(i, TripTimes.UNAVAILABLE);
} else {
newTimes.updateDepartureDelay(i, delay);
}
}
}
if (updates.hasNext()) {
update = updates.next();
} else {
update = null;
}
} else {
if (delay == null) {
newTimes.updateArrivalTime(i, TripTimes.UNAVAILABLE);
newTimes.updateDepartureTime(i, TripTimes.UNAVAILABLE);
} else {
newTimes.updateArrivalDelay(i, delay);
newTimes.updateDepartureDelay(i, delay);
}
}
}
if (update != null) {
LOG.error("Part of a TripUpdate object could not be applied successfully to trip {}.", tripId);
return null;
}
}
if (!newTimes.timesIncreasing()) {
LOG.error("TripTimes are non-increasing after applying GTFS-RT delay propagation to trip {}.", tripId);
return null;
}
LOG.debug("A valid TripUpdate object was applied to trip {} using the Timetable class update method.", tripId);
return newTimes;
}
use of com.google.transit.realtime.GtfsRealtime.TripDescriptor in project OpenTripPlanner by opentripplanner.
the class TimetableSnapshotSource method validateAndHandleModifiedTrip.
/**
* Validate and handle GTFS-RT TripUpdate message containing a MODIFIED trip.
*
* @param graph graph to update
* @param tripUpdate GTFS-RT TripUpdate message
* @param feedId
* @param serviceDate
* @return true iff successful
*/
private boolean validateAndHandleModifiedTrip(final Graph graph, final TripUpdate tripUpdate, final String feedId, final ServiceDate serviceDate) {
// Preconditions
Preconditions.checkNotNull(graph);
Preconditions.checkNotNull(tripUpdate);
Preconditions.checkNotNull(serviceDate);
//
// Validate modified trip
//
// Check whether trip id of MODIFIED trip is available
final TripDescriptor tripDescriptor = tripUpdate.getTrip();
if (!tripDescriptor.hasTripId()) {
LOG.warn("No trip id found for MODIFIED trip, skipping.");
return false;
}
// Check whether trip id already exists in graph
String tripId = tripDescriptor.getTripId();
Trip trip = getTripForTripId(feedId, tripId);
if (trip == null) {
// TODO: should we support this and consider it an ADDED trip?
LOG.warn("Graph does not contain trip id of MODIFIED trip, skipping.");
return false;
}
// Check whether a start date exists
if (!tripDescriptor.hasStartDate()) {
// TODO: should we support this and apply update to all days?
LOG.warn("MODIFIED trip doesn't have a start date in TripDescriptor, skipping.");
return false;
} else {
// Check whether service date is served by trip
final Set<AgencyAndId> serviceIds = graph.getCalendarService().getServiceIdsOnDate(serviceDate);
if (!serviceIds.contains(trip.getServiceId())) {
// TODO: should we support this and change service id of trip?
LOG.warn("MODIFIED trip has a service date that is not served by trip, skipping.");
return false;
}
}
// Check whether at least two stop updates exist
if (tripUpdate.getStopTimeUpdateCount() < 2) {
LOG.warn("MODIFIED trip has less then two stops, skipping.");
return false;
}
// Check whether all stop times are available and all stops exist
List<Stop> stops = checkNewStopTimeUpdatesAndFindStops(feedId, tripUpdate);
if (stops == null) {
return false;
}
//
// Handle modified trip
//
final boolean success = handleModifiedTrip(graph, trip, tripUpdate, stops, feedId, serviceDate);
return success;
}
use of com.google.transit.realtime.GtfsRealtime.TripDescriptor in project OpenTripPlanner by opentripplanner.
the class TimetableSnapshotSource method applyTripUpdates.
/**
* Method to apply a trip update list to the most recent version of the timetable snapshot. A
* GTFS-RT feed is always applied against a single static feed (indicated by feedId).
*<<<<<<< HEAD
*
*=======
*
* However, multi-feed support is not completed and we currently assume there is only one static
* feed when matching IDs.
*
*>>>>>>> 7296be8ffd532a13afb0bec263a9f436ab787022
* @param graph graph to update (needed for adding/changing stop patterns)
* @param fullDataset true iff the list with updates represent all updates that are active right
* now, i.e. all previous updates should be disregarded
* @param updates GTFS-RT TripUpdate's that should be applied atomically
* @param feedId
*/
public void applyTripUpdates(final Graph graph, final boolean fullDataset, final List<TripUpdate> updates, final String feedId) {
if (updates == null) {
LOG.warn("updates is null");
return;
}
// Acquire lock on buffer
bufferLock.lock();
try {
if (fullDataset) {
// Remove all updates from the buffer
buffer.clear(feedId);
}
LOG.debug("message contains {} trip updates", updates.size());
int uIndex = 0;
for (TripUpdate tripUpdate : updates) {
if (fuzzyTripMatcher != null && tripUpdate.hasTrip()) {
final TripDescriptor trip = fuzzyTripMatcher.match(feedId, tripUpdate.getTrip());
tripUpdate = tripUpdate.toBuilder().setTrip(trip).build();
}
if (!tripUpdate.hasTrip()) {
LOG.warn("Missing TripDescriptor in gtfs-rt trip update: \n{}", tripUpdate);
continue;
}
ServiceDate serviceDate = new ServiceDate();
final TripDescriptor tripDescriptor = tripUpdate.getTrip();
if (tripDescriptor.hasStartDate()) {
try {
serviceDate = ServiceDate.parseString(tripDescriptor.getStartDate());
} catch (final ParseException e) {
LOG.warn("Failed to parse start date in gtfs-rt trip update: \n{}", tripUpdate);
continue;
}
} else {
// TODO: figure out the correct service date. For the special case that a trip
// starts for example at 40:00, yesterday would probably be a better guess.
}
uIndex += 1;
LOG.debug("trip update #{} ({} updates) :", uIndex, tripUpdate.getStopTimeUpdateCount());
LOG.trace("{}", tripUpdate);
// Determine what kind of trip update this is
boolean applied = false;
final TripDescriptor.ScheduleRelationship tripScheduleRelationship = determineTripScheduleRelationship(tripUpdate);
switch(tripScheduleRelationship) {
case SCHEDULED:
applied = handleScheduledTrip(tripUpdate, feedId, serviceDate);
break;
case ADDED:
applied = validateAndHandleAddedTrip(graph, tripUpdate, feedId, serviceDate);
break;
case UNSCHEDULED:
applied = handleUnscheduledTrip(tripUpdate, feedId, serviceDate);
break;
case CANCELED:
applied = handleCanceledTrip(tripUpdate, feedId, serviceDate);
break;
case MODIFIED:
applied = validateAndHandleModifiedTrip(graph, tripUpdate, feedId, serviceDate);
break;
}
if (applied) {
appliedBlockCount++;
} else {
LOG.warn("Failed to apply TripUpdate.");
LOG.trace(" Contents: {}", tripUpdate);
}
if (appliedBlockCount % logFrequency == 0) {
LOG.info("Applied {} trip updates.", appliedBlockCount);
}
}
LOG.debug("end of update message");
// Make sure that the public (locking) getTimetableSnapshot function is not called.
if (purgeExpiredData) {
final boolean modified = purgeExpiredData();
getTimetableSnapshot(modified);
} else {
getTimetableSnapshot(false);
}
} finally {
// Always release lock
bufferLock.unlock();
}
}
Aggregations