Search in sources :

Example 1 with OccurrenceModel

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;
}
Also used : ArrayList(java.util.ArrayList) OccurrenceModel(edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel) GtfsRealtime(com.google.transit.realtime.GtfsRealtime) ErrorListHelperModel(edu.usf.cutr.gtfsrtvalidator.lib.model.helper.ErrorListHelperModel) MessageLogModel(edu.usf.cutr.gtfsrtvalidator.lib.model.MessageLogModel) HashSet(java.util.HashSet)

Example 2 with OccurrenceModel

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;
}
Also used : ArrayList(java.util.ArrayList) OccurrenceModel(edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel) GtfsRealtime(com.google.transit.realtime.GtfsRealtime) ErrorListHelperModel(edu.usf.cutr.gtfsrtvalidator.lib.model.helper.ErrorListHelperModel) MessageLogModel(edu.usf.cutr.gtfsrtvalidator.lib.model.MessageLogModel)

Example 3 with OccurrenceModel

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;
}
Also used : Trip(org.onebusaway.gtfs.model.Trip) ArrayList(java.util.ArrayList) OccurrenceModel(edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel) GtfsRealtime(com.google.transit.realtime.GtfsRealtime) ErrorListHelperModel(edu.usf.cutr.gtfsrtvalidator.lib.model.helper.ErrorListHelperModel) MessageLogModel(edu.usf.cutr.gtfsrtvalidator.lib.model.MessageLogModel)

Example 4 with OccurrenceModel

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;
}
Also used : Stop(org.onebusaway.gtfs.model.Stop) ArrayList(java.util.ArrayList) OccurrenceModel(edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel) ErrorListHelperModel(edu.usf.cutr.gtfsrtvalidator.lib.model.helper.ErrorListHelperModel) ArrayList(java.util.ArrayList) List(java.util.List) StopTime(org.onebusaway.gtfs.model.StopTime) GtfsRealtime(com.google.transit.realtime.GtfsRealtime) MessageLogModel(edu.usf.cutr.gtfsrtvalidator.lib.model.MessageLogModel)

Example 5 with OccurrenceModel

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;
}
Also used : ArrayList(java.util.ArrayList) OccurrenceModel(edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel) GtfsRealtime(com.google.transit.realtime.GtfsRealtime) ErrorListHelperModel(edu.usf.cutr.gtfsrtvalidator.lib.model.helper.ErrorListHelperModel) MessageLogModel(edu.usf.cutr.gtfsrtvalidator.lib.model.MessageLogModel)

Aggregations

OccurrenceModel (edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel)16 MessageLogModel (edu.usf.cutr.gtfsrtvalidator.lib.model.MessageLogModel)14 ErrorListHelperModel (edu.usf.cutr.gtfsrtvalidator.lib.model.helper.ErrorListHelperModel)14 GtfsRealtime (com.google.transit.realtime.GtfsRealtime)9 ArrayList (java.util.ArrayList)8 ValidationRule (edu.usf.cutr.gtfsrtvalidator.lib.model.ValidationRule)4 Test (org.junit.Test)4 Stop (org.onebusaway.gtfs.model.Stop)2 StopTime (org.onebusaway.gtfs.model.StopTime)2 HashSet (java.util.HashSet)1 List (java.util.List)1 Session (org.hibernate.Session)1 Frequency (org.onebusaway.gtfs.model.Frequency)1 Trip (org.onebusaway.gtfs.model.Trip)1