use of edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel in project gtfs-realtime-validator by CUTR-at-USF.
the class VehicleValidator method validate.
@Override
public List<ErrorListHelperModel> validate(long currentTimeMillis, GtfsDaoImpl gtfsData, GtfsMetadata gtfsMetadata, GtfsRealtime.FeedMessage feedMessage, GtfsRealtime.FeedMessage previousFeedMessage, GtfsRealtime.FeedMessage combinedFeedMessage) {
List<GtfsRealtime.FeedEntity> entityList = feedMessage.getEntityList();
List<OccurrenceModel> e026List = new ArrayList<>();
List<OccurrenceModel> e027List = new ArrayList<>();
List<OccurrenceModel> e028List = new ArrayList<>();
List<OccurrenceModel> e029List = new ArrayList<>();
List<OccurrenceModel> w002List = new ArrayList<>();
List<OccurrenceModel> w004List = new ArrayList<>();
List<OccurrenceModel> e052List = new ArrayList<>();
HashSet<String> vehicleIds = new HashSet<>(entityList.size());
for (GtfsRealtime.FeedEntity entity : entityList) {
if (entity.hasTripUpdate()) {
GtfsRealtime.TripUpdate tripUpdate = entity.getTripUpdate();
if (StringUtils.isEmpty(tripUpdate.getVehicle().getId())) {
// W002 - vehicle_id not populated
RuleUtils.addOccurrence(W002, getTripId(entity, tripUpdate), w002List, _log);
}
}
if (entity.hasVehicle()) {
GtfsRealtime.VehiclePosition v = entity.getVehicle();
if (StringUtils.isEmpty(v.getVehicle().getId())) {
// W002 - vehicle_id not populated
RuleUtils.addOccurrence(W002, "entity ID " + entity.getId(), w002List, _log);
} else {
if (vehicleIds.contains(v.getVehicle().getId())) {
// E052 - vehicle.id is not unique
RuleUtils.addOccurrence(E052, "entity ID " + entity.getId() + " has vehicle.id " + v.getVehicle().getId(), e052List, _log);
} else {
vehicleIds.add(v.getVehicle().getId());
}
}
if (v.hasPosition() && v.getPosition().hasSpeed()) {
if (v.getPosition().getSpeed() > MAX_REALISTIC_SPEED_METERS_PER_SECOND || v.getPosition().getSpeed() < 0f) {
// W004 - vehicle speed is unrealistic
String prefix = getVehicleId(entity, v) + " speed of " + v.getPosition().getSpeed() + " m/s (" + String.format("%.2f", GtfsUtils.toMilesPerHour(v.getPosition().getSpeed())) + " mph)";
RuleUtils.addOccurrence(W004, prefix, w004List, _log);
}
}
if (v.hasPosition()) {
GtfsRealtime.Position position = v.getPosition();
String id = getVehicleId(entity, v);
if (!position.hasLatitude() || !position.hasLongitude()) {
// E026 - Invalid vehicle position - missing lat/long
RuleUtils.addOccurrence(E026, id + " position is missing lat/long", e026List, _log);
} else if (!GtfsUtils.isPositionValid(position)) {
// E026 - Invalid vehicle position - invalid lat/long
RuleUtils.addOccurrence(E026, id + " has latitude/longitude of (" + position.getLatitude() + "," + position.getLongitude() + ")", e026List, _log);
} else {
// Position is valid - check E028, if it lies within the agency bounds, using shapes.txt if it exists
boolean insideBounds = checkE028(entity, gtfsMetadata, e028List);
if (insideBounds) {
// Position is within agency bounds - check E029, if it lies within the trip bounds using shapes.txt
checkE029(entityList, entity, gtfsMetadata, e029List);
}
}
if (!GtfsUtils.isBearingValid(position)) {
// E027 - Invalid vehicle bearing
RuleUtils.addOccurrence(E027, id + " has bearing of " + position.getBearing(), e027List, _log);
}
}
}
}
List<ErrorListHelperModel> errors = new ArrayList<>();
if (!e026List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E026), e026List));
}
if (!e027List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E027), e027List));
}
if (!e028List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E028), e028List));
}
if (!e029List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E029), e029List));
}
if (!w002List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(W002), w002List));
}
if (!w004List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(W004), w004List));
}
if (!e052List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E052), e052List));
}
return errors;
}
use of edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel in project gtfs-realtime-validator by CUTR-at-USF.
the class StopValidator method validate.
@Override
public List<ErrorListHelperModel> validate(long currentTimeMillis, GtfsDaoImpl gtfsData, GtfsMetadata gtfsMetadata, GtfsRealtime.FeedMessage feedMessage, GtfsRealtime.FeedMessage previousFeedMessage, GtfsRealtime.FeedMessage combinedFeedMessage) {
List<OccurrenceModel> e011List = new ArrayList<>();
List<OccurrenceModel> e015List = new ArrayList<>();
List<GtfsRealtime.FeedEntity> allEntities = feedMessage.getEntityList();
// Checks all of the RT feeds entities and checks if matching stop_ids are available in the GTFS feed
for (GtfsRealtime.FeedEntity entity : allEntities) {
String entityId = entity.getId();
if (entity.hasTripUpdate()) {
GtfsRealtime.TripUpdate tripUpdate = entity.getTripUpdate();
List<GtfsRealtime.TripUpdate.StopTimeUpdate> stopTimeUpdateList = tripUpdate.getStopTimeUpdateList();
for (GtfsRealtime.TripUpdate.StopTimeUpdate stopTimeUpdate : stopTimeUpdateList) {
if (stopTimeUpdate.hasStopId()) {
String prefix = "trip_id " + tripUpdate.getTrip().getTripId() + " stop_id " + stopTimeUpdate.getStopId();
if (!gtfsMetadata.getStopIds().contains(stopTimeUpdate.getStopId())) {
// E011 - All stop_ids referenced in GTFS-rt feed must appear in the GTFS feed
RuleUtils.addOccurrence(E011, prefix, e011List, _log);
}
Integer locationType = gtfsMetadata.getStopToLocationTypeMap().get(stopTimeUpdate.getStopId());
if (locationType != null && locationType != 0) {
// E015 - All stop_ids referenced in GTFS-rt feeds must have the location_type = 0
RuleUtils.addOccurrence(E015, prefix, e015List, _log);
}
}
}
}
if (entity.hasVehicle()) {
GtfsRealtime.VehiclePosition v = entity.getVehicle();
if (v.hasStopId()) {
if (!gtfsMetadata.getStopIds().contains(v.getStopId())) {
// E011 - All stop_ids referenced in GTFS-rt feed must appear in the GTFS feed
String prefix = (v.hasVehicle() && v.getVehicle().hasId() ? "vehicle_id " + v.getVehicle().getId() + " " : "") + "stop_id " + v.getStopId();
RuleUtils.addOccurrence(E011, prefix, e011List, _log);
}
Integer locationType = gtfsMetadata.getStopToLocationTypeMap().get(v.getStopId());
if (locationType != null && locationType != 0) {
// E015 - All stop_ids referenced in GTFS-rt feeds must have the location_type = 0
String prefix = (v.hasVehicle() && v.getVehicle().hasId() ? "vehicle_id " + v.getVehicle().getId() + " " : "") + "stop_id " + v.getStopId();
RuleUtils.addOccurrence(E015, prefix, e015List, _log);
}
}
}
if (entity.hasAlert()) {
List<GtfsRealtime.EntitySelector> informedEntityList = entity.getAlert().getInformedEntityList();
for (GtfsRealtime.EntitySelector entitySelector : informedEntityList) {
if (entitySelector.hasStopId()) {
String prefix = "alert entity ID " + entityId + " stop_id " + entitySelector.getStopId();
if (!gtfsMetadata.getStopIds().contains(entitySelector.getStopId())) {
// E011 - All stop_ids referenced in GTFS-rt feed must appear in the GTFS feed
RuleUtils.addOccurrence(E011, prefix, e011List, _log);
}
Integer locationType = gtfsMetadata.getStopToLocationTypeMap().get(entitySelector.getStopId());
if (locationType != null && locationType != 0) {
// E015 - All stop_ids referenced in GTFS-rt feeds must have the location_type = 0
RuleUtils.addOccurrence(E015, prefix, e015List, _log);
}
}
}
}
}
List<ErrorListHelperModel> errors = new ArrayList<>();
if (!e011List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E011), e011List));
}
if (!e015List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E015), e015List));
}
return errors;
}
use of edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel in project gtfs-realtime-validator by CUTR-at-USF.
the class TripDescriptorValidator method validate.
@Override
public List<ErrorListHelperModel> validate(long currentTimeMillis, GtfsDaoImpl gtfsData, GtfsMetadata gtfsMetadata, GtfsRealtime.FeedMessage feedMessage, GtfsRealtime.FeedMessage previousFeedMessage, GtfsRealtime.FeedMessage combinedFeedMessage) {
List<OccurrenceModel> errorListE003 = new ArrayList<>();
List<OccurrenceModel> errorListE004 = new ArrayList<>();
List<OccurrenceModel> errorListE016 = new ArrayList<>();
List<OccurrenceModel> errorListE020 = new ArrayList<>();
List<OccurrenceModel> errorListE021 = new ArrayList<>();
List<OccurrenceModel> errorListE023 = new ArrayList<>();
List<OccurrenceModel> errorListE024 = new ArrayList<>();
List<OccurrenceModel> errorListE030 = new ArrayList<>();
List<OccurrenceModel> errorListE031 = new ArrayList<>();
List<OccurrenceModel> errorListE032 = new ArrayList<>();
List<OccurrenceModel> errorListE033 = new ArrayList<>();
List<OccurrenceModel> errorListE034 = new ArrayList<>();
List<OccurrenceModel> errorListE035 = new ArrayList<>();
List<OccurrenceModel> errorListW006 = new ArrayList<>();
List<OccurrenceModel> errorListW009 = new ArrayList<>();
// Check the route_id values against the values from the GTFS feed
for (GtfsRealtime.FeedEntity entity : feedMessage.getEntityList()) {
if (entity.hasTripUpdate()) {
GtfsRealtime.TripUpdate tripUpdate = entity.getTripUpdate();
if (!tripUpdate.getTrip().hasTripId()) {
checkW006(entity, tripUpdate.getTrip(), errorListW006);
} else {
String tripId = tripUpdate.getTrip().getTripId();
Trip trip = gtfsMetadata.getTrips().get(tripId);
if (trip == null) {
if (!GtfsUtils.isAddedTrip(tripUpdate.getTrip())) {
// Trip isn't in GTFS data and isn't an ADDED trip - E003
RuleUtils.addOccurrence(E003, GtfsUtils.getTripId(entity, tripUpdate), errorListE003, _log);
}
} else {
if (GtfsUtils.isAddedTrip(tripUpdate.getTrip())) {
// Trip is in GTFS data and is an ADDED trip - E016
RuleUtils.addOccurrence(E016, GtfsUtils.getTripId(entity, tripUpdate), errorListE016, _log);
}
if (tripUpdate.getTrip().hasStartTime()) {
checkE023(tripUpdate, tripUpdate.getTrip(), gtfsMetadata, errorListE023);
}
}
}
if (tripUpdate.getTrip().hasStartTime()) {
checkE020(tripUpdate, tripUpdate.getTrip(), errorListE020);
}
checkE021(tripUpdate, tripUpdate.getTrip(), errorListE021);
checkE004(tripUpdate, tripUpdate.getTrip(), gtfsMetadata, errorListE004);
checkE024(tripUpdate, tripUpdate.getTrip(), gtfsMetadata, errorListE024);
checkE035(entity, tripUpdate.getTrip(), gtfsMetadata, errorListE035);
boolean foundW009 = false;
List<GtfsRealtime.TripUpdate.StopTimeUpdate> stopTimeUpdateList = tripUpdate.getStopTimeUpdateList();
for (GtfsRealtime.TripUpdate.StopTimeUpdate stopTimeUpdate : stopTimeUpdateList) {
// Only flag one occurrence of W009 for stop_time_update per trip to avoid flooding the database
if (!foundW009) {
checkW009(entity, stopTimeUpdate, errorListW009);
if (!errorListW009.isEmpty()) {
foundW009 = true;
}
}
}
if (tripUpdate.hasTrip()) {
checkW009(entity, tripUpdate.getTrip(), errorListW009);
}
}
if (entity.hasVehicle() && entity.getVehicle().hasTrip()) {
GtfsRealtime.TripDescriptor trip = entity.getVehicle().getTrip();
if (!trip.hasTripId()) {
checkW006(entity, trip, errorListW006);
} else {
String tripId = trip.getTripId();
if (!StringUtils.isEmpty(tripId)) {
Trip gtfsTrip = gtfsMetadata.getTrips().get(tripId);
if (gtfsTrip == null) {
if (!GtfsUtils.isAddedTrip(trip)) {
// E003 - Trip isn't in GTFS data and isn't an ADDED trip
RuleUtils.addOccurrence(E003, "vehicle_id " + entity.getVehicle().getVehicle().getId() + " trip_id " + tripId, errorListE003, _log);
}
} else {
if (GtfsUtils.isAddedTrip(trip)) {
// E016 - Trip is in GTFS data and is an ADDED trip
RuleUtils.addOccurrence(E016, "vehicle_id " + entity.getVehicle().getVehicle().getId() + " trip_id " + tripId, errorListE016, _log);
}
if (trip.hasStartTime()) {
checkE023(entity.getVehicle(), trip, gtfsMetadata, errorListE023);
}
}
}
}
if (trip.hasStartTime()) {
checkE020(entity.getVehicle(), trip, errorListE020);
}
checkE004(entity.getVehicle(), trip, gtfsMetadata, errorListE004);
checkE021(entity.getVehicle(), trip, errorListE021);
checkE024(entity.getVehicle(), trip, gtfsMetadata, errorListE024);
checkE035(entity, trip, gtfsMetadata, errorListE035);
checkW009(entity, trip, errorListW009);
}
if (entity.hasAlert()) {
GtfsRealtime.Alert alert = entity.getAlert();
List<GtfsRealtime.EntitySelector> entitySelectors = alert.getInformedEntityList();
if (entitySelectors != null && entitySelectors.size() > 0) {
for (GtfsRealtime.EntitySelector entitySelector : entitySelectors) {
checkE033(entity, entitySelector, errorListE033);
checkE034(entity, entitySelector, gtfsMetadata, errorListE034);
checkE035(entity, entitySelector.getTrip(), gtfsMetadata, errorListE035);
if (entitySelector.hasRouteId() && entitySelector.hasTrip()) {
checkE030(entity, entitySelector, gtfsMetadata, errorListE030);
checkE031(entity, entitySelector, errorListE031);
}
if (entitySelector.hasTrip()) {
checkW006(entity, entitySelector.getTrip(), errorListW006);
checkW009(entity, entitySelector.getTrip(), errorListW009);
}
}
} else {
// E032 - Alert does not have an informed_entity
RuleUtils.addOccurrence(E032, "alert ID " + entity.getId() + " does not have an informed_entity", errorListE032, _log);
}
}
}
List<ErrorListHelperModel> errors = new ArrayList<>();
if (!errorListE003.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E003), errorListE003));
}
if (!errorListE004.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E004), errorListE004));
}
if (!errorListE016.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E016), errorListE016));
}
if (!errorListE020.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E020), errorListE020));
}
if (!errorListE021.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E021), errorListE021));
}
if (!errorListE023.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E023), errorListE023));
}
if (!errorListE024.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E024), errorListE024));
}
if (!errorListE030.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E030), errorListE030));
}
if (!errorListE031.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E031), errorListE031));
}
if (!errorListE032.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E032), errorListE032));
}
if (!errorListE033.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E033), errorListE033));
}
if (!errorListE034.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E034), errorListE034));
}
if (!errorListE035.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E035), errorListE035));
}
if (!errorListW006.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(W006), errorListW006));
}
if (!errorListW009.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(W009), errorListW009));
}
return errors;
}
use of edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel in project gtfs-realtime-validator by CUTR-at-USF.
the class StopTimeUpdateValidator method validate.
@Override
public List<ErrorListHelperModel> validate(long currentTimeMillis, GtfsDaoImpl gtfsData, GtfsMetadata gtfsMetadata, GtfsRealtime.FeedMessage feedMessage, GtfsRealtime.FeedMessage previousFeedMessage, GtfsRealtime.FeedMessage combinedFeedMessage) {
List<GtfsRealtime.FeedEntity> entityList = feedMessage.getEntityList();
List<OccurrenceModel> e002List = new ArrayList<>();
List<OccurrenceModel> e009List = new ArrayList<>();
List<OccurrenceModel> e036List = new ArrayList<>();
List<OccurrenceModel> e037List = new ArrayList<>();
List<OccurrenceModel> e040List = new ArrayList<>();
List<OccurrenceModel> e041List = new ArrayList<>();
List<OccurrenceModel> e042List = new ArrayList<>();
List<OccurrenceModel> e043List = new ArrayList<>();
List<OccurrenceModel> e044List = new ArrayList<>();
List<OccurrenceModel> e045List = new ArrayList<>();
List<OccurrenceModel> e046List = new ArrayList<>();
List<OccurrenceModel> e051List = new ArrayList<>();
for (GtfsRealtime.FeedEntity entity : entityList) {
if (entity.hasTripUpdate()) {
GtfsRealtime.TripUpdate tripUpdate = entity.getTripUpdate();
checkE041(entity, tripUpdate, e041List);
List<StopTime> gtfsStopTimes = null;
int gtfsStopTimeIndex = 0;
String tripId = null;
if (tripUpdate.hasTrip() && tripUpdate.getTrip().hasTripId()) {
tripId = tripUpdate.getTrip().getTripId();
gtfsStopTimes = gtfsMetadata.getTripStopTimes().get(tripId);
}
List<GtfsRealtime.TripUpdate.StopTimeUpdate> rtStopTimeUpdateList = tripUpdate.getStopTimeUpdateList();
List<Integer> rtStopSequenceList = new ArrayList<>();
List<String> rtStopIdList = new ArrayList<>();
Integer previousRtStopSequence = null;
String previousRtStopId = null;
boolean foundE009error = false;
boolean addedStopSequenceFromStopId = false;
Map<String, List<String>> tripWithMultiStop = gtfsMetadata.getTripsWithMultiStops();
boolean unknownRtStopSequence = false;
for (GtfsRealtime.TripUpdate.StopTimeUpdate stopTimeUpdate : rtStopTimeUpdateList) {
if (!foundE009error && tripId != null && tripWithMultiStop.containsKey(tripId) && !stopTimeUpdate.hasStopSequence()) {
// E009 - GTFS-rt stop_sequence isn't provided for trip that visits same stop_id more than once
List<String> stopIds = tripWithMultiStop.get(tripId);
RuleUtils.addOccurrence(ValidationRules.E009, "trip_id " + tripId + " visits stop_id " + stopIds.toString(), e009List, _log);
// Only log error once for this trip
foundE009error = true;
}
if (previousRtStopSequence != null) {
checkE036(entity, previousRtStopSequence, stopTimeUpdate, e036List);
}
if (previousRtStopId != null) {
checkE037(entity, previousRtStopId, stopTimeUpdate, e037List);
}
previousRtStopSequence = stopTimeUpdate.getStopSequence();
previousRtStopId = stopTimeUpdate.getStopId();
if (stopTimeUpdate.hasStopSequence()) {
rtStopSequenceList.add(stopTimeUpdate.getStopSequence());
}
if (stopTimeUpdate.hasStopId()) {
rtStopIdList.add(stopTimeUpdate.getStopId());
}
if (gtfsStopTimes != null) {
// Loop through GTFS stop_time.txt to try and find a matching GTFS stop
while (gtfsStopTimeIndex < gtfsStopTimes.size()) {
int gtfsStopSequence = gtfsStopTimes.get(gtfsStopTimeIndex).getStopSequence();
Stop gtfsStop = gtfsStopTimes.get(gtfsStopTimeIndex).getStop();
boolean foundStopSequence = false;
boolean foundStopId = false;
if (stopTimeUpdate.hasStopSequence()) {
if (gtfsStopSequence == stopTimeUpdate.getStopSequence()) {
// Found a matching stop_sequence from GTFS stop_times.txt
checkE045(entity, tripUpdate, stopTimeUpdate, gtfsStopSequence, gtfsStop, e045List);
checkE046(entity, tripUpdate, stopTimeUpdate, gtfsStopTimes.get(gtfsStopTimeIndex), e046List);
foundStopSequence = true;
}
}
if (stopTimeUpdate.hasStopId()) {
if (gtfsStop.getId().getId().equals(stopTimeUpdate.getStopId())) {
/**
* Found a matching stop_id - note that there could be loops in routes, so unlike
* stop_sequence this isn't a definitive match between this stopTimeUpdate and a GTFS stop_times.txt entry
*/
foundStopId = true;
}
}
gtfsStopTimeIndex++;
if (foundStopSequence) {
// We caught up with the stop_sequence in GTFS data - stop so we can pick up from here in next WHILE loop
break;
} else {
if (stopTimeUpdate.hasStopSequence() && gtfsStopTimeIndex == gtfsStopTimes.size()) {
// For E051 - we've reached the last GTFS stop_times.txt record for the GTFS-rt stop_time_update and haven't found stop_sequence (#261)
unknownRtStopSequence = true;
}
if (!stopTimeUpdate.hasStopSequence() && foundStopId) {
// For E002 - in the case when stop_sequence is missing from the GTFS-rt feed, add the GTFS stop_sequence (See #159)
if (!stopTimeUpdate.hasStopSequence()) {
rtStopSequenceList.add(gtfsStopSequence);
addedStopSequenceFromStopId = true;
}
// E046 hasn't been checked yet if a stop_sequence doesn't exist - check now
checkE046(entity, tripUpdate, stopTimeUpdate, gtfsStopTimes.get(gtfsStopTimeIndex - 1), e046List);
// Note that for routes with loops, we could potentially be stopping prematurely
break;
}
}
}
}
checkE040(entity, tripUpdate, stopTimeUpdate, e040List);
checkE042(entity, tripUpdate, stopTimeUpdate, e042List);
checkE043(entity, tripUpdate, stopTimeUpdate, e043List);
checkE044(entity, tripUpdate, stopTimeUpdate, e044List);
if (unknownRtStopSequence) {
// E051 - GTFS-rt stop_sequence not found in GTFS data
RuleUtils.addOccurrence(ValidationRules.E051, "GTFS-rt " + GtfsUtils.getTripId(entity, tripUpdate) + " contains stop_sequence " + stopTimeUpdate.getStopSequence(), e051List, _log);
// the remaining stop_time_updates for this GTFS-rt trip will be validated.
break;
}
}
boolean sorted = Ordering.natural().isStrictlyOrdered(rtStopSequenceList);
if (!sorted) {
// E002 - stop_time_updates for a given trip_id must be sorted by increasing stop_sequence
String id = GtfsUtils.getTripId(entity, tripUpdate);
RuleUtils.addOccurrence(ValidationRules.E002, id + " stop_sequence " + rtStopSequenceList.toString(), e002List, _log);
} else if (addedStopSequenceFromStopId) {
// TripUpdate was missing at least one stop_sequence
if (rtStopSequenceList.size() < rtStopTimeUpdateList.size()) {
// We didn't find all of the stop_time_updates in GTFS using stop_id, so stop_time_updates are
// out of sequence
// E002 - stop_time_updates for a given trip_id must be sorted by increasing stop_sequence
String id = GtfsUtils.getTripId(entity, tripUpdate);
RuleUtils.addOccurrence(ValidationRules.E002, id + " stop_sequence for stop_ids " + rtStopIdList.toString(), e002List, _log);
}
}
}
}
List<ErrorListHelperModel> errors = new ArrayList<>();
if (!e002List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(ValidationRules.E002), e002List));
}
if (!e009List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(ValidationRules.E009), e009List));
}
if (!e036List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(ValidationRules.E036), e036List));
}
if (!e037List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(ValidationRules.E037), e037List));
}
if (!e040List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(ValidationRules.E040), e040List));
}
if (!e041List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(ValidationRules.E041), e041List));
}
if (!e042List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(ValidationRules.E042), e042List));
}
if (!e043List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(ValidationRules.E043), e043List));
}
if (!e044List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(ValidationRules.E044), e044List));
}
if (!e045List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(ValidationRules.E045), e045List));
}
if (!e046List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(ValidationRules.E046), e046List));
}
if (!e051List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(ValidationRules.E051), e051List));
}
return errors;
}
use of edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel in project gtfs-realtime-validator by CUTR-at-USF.
the class TimestampValidator method validate.
@Override
public List<ErrorListHelperModel> validate(long currentTimeMillis, GtfsDaoImpl gtfsData, GtfsMetadata gtfsMetadata, GtfsRealtime.FeedMessage feedMessage, GtfsRealtime.FeedMessage previousFeedMessage, GtfsRealtime.FeedMessage combinedFeedMessage) {
if (feedMessage.equals(previousFeedMessage)) {
throw new IllegalArgumentException("feedMessage and previousFeedMessage must not be the same");
}
List<OccurrenceModel> w001List = new ArrayList<>();
List<OccurrenceModel> w007List = new ArrayList<>();
List<OccurrenceModel> w008List = new ArrayList<>();
List<OccurrenceModel> e001List = new ArrayList<>();
List<OccurrenceModel> e012List = new ArrayList<>();
List<OccurrenceModel> e017List = new ArrayList<>();
List<OccurrenceModel> e018List = new ArrayList<>();
List<OccurrenceModel> e022List = new ArrayList<>();
List<OccurrenceModel> e025List = new ArrayList<>();
List<OccurrenceModel> e048List = new ArrayList<>();
List<OccurrenceModel> e050List = new ArrayList<>();
String currentTimeText = TimestampUtils.posixToClock(TimeUnit.MILLISECONDS.toSeconds(currentTimeMillis), gtfsMetadata.getTimeZone());
/**
* Validate FeedHeader timestamp
*/
long headerTimestamp = feedMessage.getHeader().getTimestamp();
if (headerTimestamp == 0) {
boolean isV2orHigher = true;
try {
isV2orHigher = GtfsUtils.isV2orHigher(feedMessage.getHeader());
} catch (Exception e) {
_log.error("Error checking header version for E048/W001, logging as E048: " + e);
}
if (isV2orHigher) {
// E048 - header timestamp not populated
RuleUtils.addOccurrence(E048, "", e048List, _log);
} else {
// W001 - Timestamp not populated
RuleUtils.addOccurrence(W001, "header", w001List, _log);
}
} else {
if (!isPosix(headerTimestamp)) {
// E001 - Not in POSIX time
RuleUtils.addOccurrence(E001, "header.timestamp", e001List, _log);
} else {
long ageMillis = getAge(currentTimeMillis, headerTimestamp);
long ageMinutes = TimeUnit.MILLISECONDS.toMinutes(ageMillis);
long ageSeconds = TimeUnit.MILLISECONDS.toSeconds(ageMillis);
if (ageMillis > TimeUnit.SECONDS.toMillis(MAX_AGE_SECONDS)) {
// W008 - Header timestamp is older than 65 seconds
RuleUtils.addOccurrence(W008, "header.timestamp is " + ageMinutes + " min " + ageSeconds % 60 + " sec", w008List, _log);
}
if (TimestampUtils.isInFuture(currentTimeMillis, headerTimestamp, IN_FUTURE_TOLERANCE_SECONDS)) {
// E050 - timestamp is in the future
String headerTimestampText = TimestampUtils.posixToClock(headerTimestamp, gtfsMetadata.getTimeZone());
RuleUtils.addOccurrence(E050, "header.timestamp " + headerTimestampText + " (" + headerTimestamp + ") is " + Math.abs(ageMinutes) + " min " + Math.abs(ageSeconds) % 60 + " sec greater than " + currentTimeText + " (" + currentTimeMillis + ")", e050List, _log);
}
}
if (previousFeedMessage != null && previousFeedMessage.getHeader().getTimestamp() != 0) {
long previousTimestamp = previousFeedMessage.getHeader().getTimestamp();
long interval = headerTimestamp - previousTimestamp;
if (headerTimestamp == previousTimestamp) {
// E017 - GTFS-rt content changed but has the same timestamp
RuleUtils.addOccurrence(E017, "header.timestamp of " + headerTimestamp, e017List, _log);
} else if (headerTimestamp < previousTimestamp) {
// E018 - GTFS-rt header timestamp decreased between two sequential iterations
String prefix = "header.timestamp of " + headerTimestamp + " is less than the header.timestamp of " + previousFeedMessage.getHeader().getTimestamp();
RuleUtils.addOccurrence(E018, prefix, e018List, _log);
} else if (interval > MINIMUM_REFRESH_INTERVAL_SECONDS) {
// W007 - Refresh interval is more than 35 seconds
RuleUtils.addOccurrence(W007, interval + " second interval between consecutive header.timestamps", w007List, _log);
}
}
}
for (GtfsRealtime.FeedEntity entity : feedMessage.getEntityList()) {
if (entity.hasTripUpdate()) {
GtfsRealtime.TripUpdate tripUpdate = entity.getTripUpdate();
long tripUpdateTimestamp = tripUpdate.getTimestamp();
/**
* Validate TripUpdate timestamps
*/
String id = GtfsUtils.getTripId(entity, tripUpdate);
if (tripUpdateTimestamp == 0) {
// W001 - Timestamp not populated
RuleUtils.addOccurrence(W001, id, w001List, _log);
} else {
if (headerTimestamp != 0 && tripUpdateTimestamp > headerTimestamp) {
// E012 - Header timestamp should be greater than or equal to all other timestamps
RuleUtils.addOccurrence(E012, id + " timestamp " + tripUpdateTimestamp, e012List, _log);
}
if (!isPosix(tripUpdateTimestamp)) {
// E001 - Not in POSIX time
RuleUtils.addOccurrence(E001, id + " timestamp " + tripUpdateTimestamp, e001List, _log);
} else {
if (TimestampUtils.isInFuture(currentTimeMillis, tripUpdateTimestamp, IN_FUTURE_TOLERANCE_SECONDS)) {
// E050 - timestamp is in the future
long ageMillis = getAge(currentTimeMillis, tripUpdateTimestamp);
long ageMinutes = Math.abs(TimeUnit.MILLISECONDS.toMinutes(ageMillis));
long ageSeconds = Math.abs(TimeUnit.MILLISECONDS.toSeconds(ageMillis));
String tripUpdateTimestampText = TimestampUtils.posixToClock(tripUpdateTimestamp, gtfsMetadata.getTimeZone());
RuleUtils.addOccurrence(E050, id + " timestamp " + tripUpdateTimestampText + " (" + tripUpdateTimestamp + ") is " + ageMinutes + " min " + ageSeconds % 60 + " sec greater than " + currentTimeText + " (" + currentTimeMillis + ")", e050List, _log);
}
}
}
/**
* Validate TripUpdate StopTimeUpdate times
*/
List<GtfsRealtime.TripUpdate.StopTimeUpdate> stopTimeUpdates = tripUpdate.getStopTimeUpdateList();
if (stopTimeUpdates != null) {
Long previousArrivalTime = null;
String previousArrivalTimeText = null;
Long previousDepartureTime = null;
String previousDepartureTimeText = null;
for (GtfsRealtime.TripUpdate.StopTimeUpdate stopTimeUpdate : stopTimeUpdates) {
String stopDescription = stopTimeUpdate.hasStopSequence() ? " stop_sequence " + stopTimeUpdate.getStopSequence() : " stop_id " + stopTimeUpdate.getStopId();
Long arrivalTime = null;
String arrivalTimeText;
Long departureTime = null;
String departureTimeText;
if (stopTimeUpdate.hasArrival()) {
if (stopTimeUpdate.getArrival().hasTime()) {
arrivalTime = stopTimeUpdate.getArrival().getTime();
arrivalTimeText = TimestampUtils.posixToClock(arrivalTime, gtfsMetadata.getTimeZone());
if (!isPosix(arrivalTime)) {
// E001 - Not in POSIX time
RuleUtils.addOccurrence(E001, id + stopDescription + " arrival_time " + arrivalTime, e001List, _log);
}
if (previousArrivalTime != null && arrivalTime < previousArrivalTime) {
// E022 - this stop arrival time is < previous stop arrival time
String prefix = id + stopDescription + " arrival_time " + arrivalTimeText + " (" + arrivalTime + ") is less than previous stop arrival_time " + previousArrivalTimeText + " (" + previousArrivalTime + ")";
RuleUtils.addOccurrence(E022, prefix, e022List, _log);
}
if (previousArrivalTime != null && Objects.equals(arrivalTime, previousArrivalTime)) {
// E022 - this stop arrival time is == previous stop arrival time
String prefix = id + stopDescription + " arrival_time " + arrivalTimeText + " (" + arrivalTime + ") is equal to previous stop arrival_time " + previousArrivalTimeText + " (" + previousArrivalTime + ")";
RuleUtils.addOccurrence(E022, prefix, e022List, _log);
}
if (previousDepartureTime != null && arrivalTime < previousDepartureTime) {
// E022 - this stop arrival time is < previous stop departure time
String prefix = id + stopDescription + " arrival_time " + arrivalTimeText + " (" + arrivalTime + ") is less than previous stop departure_time " + previousDepartureTimeText + " (" + previousDepartureTime + ")";
RuleUtils.addOccurrence(E022, prefix, e022List, _log);
}
if (previousDepartureTime != null && Objects.equals(arrivalTime, previousDepartureTime)) {
// E022 - this stop arrival time is == previous stop departure time
String prefix = id + stopDescription + " arrival_time " + arrivalTimeText + " (" + arrivalTime + ") is equal to previous stop departure_time " + previousDepartureTimeText + " (" + previousDepartureTime + ")";
RuleUtils.addOccurrence(E022, prefix, e022List, _log);
}
}
}
if (stopTimeUpdate.hasDeparture()) {
if (stopTimeUpdate.getDeparture().hasTime()) {
departureTime = stopTimeUpdate.getDeparture().getTime();
departureTimeText = TimestampUtils.posixToClock(departureTime, gtfsMetadata.getTimeZone());
if (!isPosix(departureTime)) {
// E001 - Not in POSIX time
RuleUtils.addOccurrence(E001, id + stopDescription + " departure_time " + departureTime, e001List, _log);
}
if (previousDepartureTime != null && departureTime < previousDepartureTime) {
// E022 - this stop departure time is < previous stop departure time
String prefix = id + stopDescription + " departure_time " + departureTimeText + " (" + departureTime + ") is less than previous stop departure_time " + previousDepartureTimeText + " (" + previousDepartureTime + ")";
RuleUtils.addOccurrence(E022, prefix, e022List, _log);
}
if (previousDepartureTime != null && Objects.equals(departureTime, previousDepartureTime)) {
// E022 - this stop departure time is == previous stop departure time
String prefix = id + stopDescription + " departure_time " + departureTimeText + " (" + departureTime + ") is equal to previous stop departure_time " + previousDepartureTimeText + " (" + previousDepartureTime + ")";
RuleUtils.addOccurrence(E022, prefix, e022List, _log);
}
if (previousArrivalTime != null && departureTime < previousArrivalTime) {
// E022 - this stop departure time is < previous stop arrival time
String prefix = id + stopDescription + " departure_time " + departureTimeText + " (" + departureTime + ") is less than previous stop arrival_time " + previousArrivalTimeText + " (" + previousArrivalTime + ")";
RuleUtils.addOccurrence(E022, prefix, e022List, _log);
}
if (previousArrivalTime != null && Objects.equals(departureTime, previousArrivalTime)) {
// E022 - this stop departure time is == previous stop arrival time
String prefix = id + stopDescription + " departure_time " + departureTimeText + " (" + departureTime + ") is equal to previous stop arrival_time " + previousArrivalTimeText + " (" + previousArrivalTime + ")";
RuleUtils.addOccurrence(E022, prefix, e022List, _log);
}
if (stopTimeUpdate.getArrival().hasTime() && departureTime < stopTimeUpdate.getArrival().getTime()) {
// E025 - stop_time_update departure time is before arrival time
String prefix = id + stopDescription + " departure_time " + departureTimeText + " (" + departureTime + ") is less than the same stop arrival_time " + TimestampUtils.posixToClock(stopTimeUpdate.getArrival().getTime(), gtfsMetadata.getTimeZone()) + " (" + stopTimeUpdate.getArrival().getTime() + ")";
RuleUtils.addOccurrence(E025, prefix, e025List, _log);
}
}
}
if (arrivalTime != null) {
previousArrivalTime = arrivalTime;
previousArrivalTimeText = TimestampUtils.posixToClock(previousArrivalTime, gtfsMetadata.getTimeZone());
}
if (departureTime != null) {
previousDepartureTime = departureTime;
previousDepartureTimeText = TimestampUtils.posixToClock(previousDepartureTime, gtfsMetadata.getTimeZone());
}
}
}
}
if (entity.hasVehicle()) {
GtfsRealtime.VehiclePosition vehiclePosition = entity.getVehicle();
long vehicleTimestamp = vehiclePosition.getTimestamp();
if (vehicleTimestamp == 0) {
// W001 - Timestamp not populated
RuleUtils.addOccurrence(W001, "vehicle_id " + vehiclePosition.getVehicle().getId(), w001List, _log);
} else {
String prefix = "vehicle_id " + vehiclePosition.getVehicle().getId() + " timestamp " + vehicleTimestamp;
if (headerTimestamp != 0 && vehicleTimestamp > headerTimestamp) {
// E012 - Header timestamp should be greater than or equal to all other timestamps
RuleUtils.addOccurrence(E012, prefix, e012List, _log);
}
if (!isPosix(vehicleTimestamp)) {
// E001 - Not in POSIX time
RuleUtils.addOccurrence(E001, prefix, e001List, _log);
} else {
if (TimestampUtils.isInFuture(currentTimeMillis, vehicleTimestamp, IN_FUTURE_TOLERANCE_SECONDS)) {
// E050 - timestamp is in the future
long ageMillis = getAge(currentTimeMillis, vehicleTimestamp);
long ageMinutes = Math.abs(TimeUnit.MILLISECONDS.toMinutes(ageMillis));
long ageSeconds = Math.abs(TimeUnit.MILLISECONDS.toSeconds(ageMillis));
String vehicleTimestampText = TimestampUtils.posixToClock(vehicleTimestamp, gtfsMetadata.getTimeZone());
RuleUtils.addOccurrence(E050, "vehicle_id " + vehiclePosition.getVehicle().getId() + " timestamp " + vehicleTimestampText + " (" + vehicleTimestamp + ") is " + ageMinutes + " min " + ageSeconds % 60 + " sec greater than " + currentTimeText + " (" + currentTimeMillis + ")", e050List, _log);
}
}
}
}
if (entity.hasAlert()) {
checkAlertE001(entity, e001List);
}
}
List<ErrorListHelperModel> errors = new ArrayList<>();
if (!w001List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(W001), w001List));
}
if (!w007List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(W007), w007List));
}
if (!w008List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(W008), w008List));
}
if (!e001List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E001), e001List));
}
if (!e012List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E012), e012List));
}
if (!e017List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E017), e017List));
}
if (!e018List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E018), e018List));
}
if (!e022List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E022), e022List));
}
if (!e025List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E025), e025List));
}
if (!e048List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E048), e048List));
}
if (!e050List.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E050), e050List));
}
return errors;
}
Aggregations