/** * This method downloads the latest vehicle data, processes each vehicle in turn, and create a * GTFS-realtime feed of trip updates and vehicle positions as a result. */ private void refreshVehicles() throws IOException, JSONException { /** We download the vehicle details as an array of JSON objects. */ JSONArray vehicleArray = downloadVehicleDetails(); /** * The FeedMessage.Builder is what we will use to build up our GTFS-realtime feeds. We create a * feed for both trip updates and vehicle positions. */ FeedMessage.Builder tripUpdates = GtfsRealtimeLibrary.createFeedMessageBuilder(); FeedMessage.Builder vehiclePositions = GtfsRealtimeLibrary.createFeedMessageBuilder(); /** We iterate over every JSON vehicle object. */ for (int i = 0; i < vehicleArray.length(); ++i) { JSONObject obj = vehicleArray.getJSONObject(i); String trainNumber = obj.getString("trainno"); String route = obj.getString("dest"); String stopId = obj.getString("nextstop"); double lat = obj.getDouble("lat"); double lon = obj.getDouble("lon"); int delay = obj.getInt("late"); /** * We construct a TripDescriptor and VehicleDescriptor, which will be used in both trip * updates and vehicle positions to identify the trip and vehicle. Ideally, we would have a * trip id to use for the trip descriptor, but the SEPTA api doesn't include it, so we settle * for a route id instead. */ TripDescriptor.Builder tripDescriptor = TripDescriptor.newBuilder(); tripDescriptor.setRouteId(route); VehicleDescriptor.Builder vehicleDescriptor = VehicleDescriptor.newBuilder(); vehicleDescriptor.setId(trainNumber); /** * To construct our TripUpdate, we create a stop-time arrival event for the next stop for the * vehicle, with the specified arrival delay. We add the stop-time update to a TripUpdate * builder, along with the trip and vehicle descriptors. */ StopTimeEvent.Builder arrival = StopTimeEvent.newBuilder(); arrival.setDelay(delay * 60); StopTimeUpdate.Builder stopTimeUpdate = StopTimeUpdate.newBuilder(); stopTimeUpdate.setArrival(arrival); stopTimeUpdate.setStopId(stopId); TripUpdate.Builder tripUpdate = TripUpdate.newBuilder(); tripUpdate.addStopTimeUpdate(stopTimeUpdate); tripUpdate.setTrip(tripDescriptor); tripUpdate.setVehicle(vehicleDescriptor); /** * Create a new feed entity to wrap the trip update and add it to the GTFS-realtime trip * updates feed. */ FeedEntity.Builder tripUpdateEntity = FeedEntity.newBuilder(); tripUpdateEntity.setId(trainNumber); tripUpdateEntity.setTripUpdate(tripUpdate); tripUpdates.addEntity(tripUpdateEntity); /** * To construct our VehiclePosition, we create a position for the vehicle. We add the position * to a VehiclePosition builder, along with the trip and vehicle descriptors. */ Position.Builder position = Position.newBuilder(); position.setLatitude((float) lat); position.setLongitude((float) lon); VehiclePosition.Builder vehiclePosition = VehiclePosition.newBuilder(); vehiclePosition.setPosition(position); vehiclePosition.setTrip(tripDescriptor); vehiclePosition.setVehicle(vehicleDescriptor); /** * Create a new feed entity to wrap the vehicle position and add it to the GTFS-realtime * vehicle positions feed. */ FeedEntity.Builder vehiclePositionEntity = FeedEntity.newBuilder(); vehiclePositionEntity.setId(trainNumber); vehiclePositionEntity.setVehicle(vehiclePosition); vehiclePositions.addEntity(vehiclePositionEntity); } /** Build out the final GTFS-realtime feed messagse and save them. */ _gtfsRealtimeProvider.setTripUpdates(tripUpdates.build()); _gtfsRealtimeProvider.setVehiclePositions(vehiclePositions.build()); _log.info("vehicles extracted: " + tripUpdates.getEntityCount()); }
@Test public void testUpdate() { TripUpdate tripUpdate; TripUpdate.Builder tripUpdateBuilder; TripDescriptor.Builder tripDescriptorBuilder; StopTimeUpdate.Builder stopTimeUpdateBuilder; StopTimeEvent.Builder stopTimeEventBuilder; int trip_1_1_index = timetable.getTripIndex(new AgencyAndId("agency", "1.1")); Vertex stop_a = graph.getVertex("agency_A"); Vertex stop_c = graph.getVertex("agency_C"); RoutingRequest options = new RoutingRequest(); ShortestPathTree spt; GraphPath path; // non-existing trip tripDescriptorBuilder = TripDescriptor.newBuilder(); tripDescriptorBuilder.setTripId("b"); tripDescriptorBuilder.setScheduleRelationship(TripDescriptor.ScheduleRelationship.CANCELED); tripUpdateBuilder = TripUpdate.newBuilder(); tripUpdateBuilder.setTrip(tripDescriptorBuilder); tripUpdate = tripUpdateBuilder.build(); assertFalse(timetable.update(tripUpdate, "a", timeZone, serviceDate)); // update trip with bad data tripDescriptorBuilder = TripDescriptor.newBuilder(); tripDescriptorBuilder.setTripId("1.1"); tripDescriptorBuilder.setScheduleRelationship(TripDescriptor.ScheduleRelationship.SCHEDULED); tripUpdateBuilder = TripUpdate.newBuilder(); tripUpdateBuilder.setTrip(tripDescriptorBuilder); stopTimeUpdateBuilder = tripUpdateBuilder.addStopTimeUpdateBuilder(0); stopTimeUpdateBuilder.setStopSequence(0); stopTimeUpdateBuilder.setScheduleRelationship(StopTimeUpdate.ScheduleRelationship.SKIPPED); tripUpdate = tripUpdateBuilder.build(); assertFalse(timetable.update(tripUpdate, "agency", timeZone, serviceDate)); // update trip with non-increasing data tripDescriptorBuilder = TripDescriptor.newBuilder(); tripDescriptorBuilder.setTripId("1.1"); tripDescriptorBuilder.setScheduleRelationship(TripDescriptor.ScheduleRelationship.SCHEDULED); tripUpdateBuilder = TripUpdate.newBuilder(); tripUpdateBuilder.setTrip(tripDescriptorBuilder); stopTimeUpdateBuilder = tripUpdateBuilder.addStopTimeUpdateBuilder(0); stopTimeUpdateBuilder.setStopSequence(2); stopTimeUpdateBuilder.setScheduleRelationship(StopTimeUpdate.ScheduleRelationship.SCHEDULED); stopTimeEventBuilder = stopTimeUpdateBuilder.getArrivalBuilder(); stopTimeEventBuilder.setTime( TestUtils.dateInSeconds("America/New_York", 2009, AUGUST, 7, 0, 10, 1)); stopTimeEventBuilder = stopTimeUpdateBuilder.getDepartureBuilder(); stopTimeEventBuilder.setTime( TestUtils.dateInSeconds("America/New_York", 2009, AUGUST, 7, 0, 10, 0)); tripUpdate = tripUpdateBuilder.build(); assertFalse(timetable.update(tripUpdate, "agency", timeZone, serviceDate)); // --- long startTime = TestUtils.dateInSeconds("America/New_York", 2009, AUGUST, 7, 0, 0, 0); long endTime; options.dateTime = startTime; // --- options.setRoutingContext(graph, stop_a, stop_c); spt = aStar.getShortestPathTree(options); path = spt.getPath(stop_c, false); assertNotNull(path); endTime = startTime + 20 * 60; assertEquals(endTime, path.getEndTime()); // update trip tripDescriptorBuilder = TripDescriptor.newBuilder(); tripDescriptorBuilder.setTripId("1.1"); tripDescriptorBuilder.setScheduleRelationship(TripDescriptor.ScheduleRelationship.SCHEDULED); tripUpdateBuilder = TripUpdate.newBuilder(); tripUpdateBuilder.setTrip(tripDescriptorBuilder); stopTimeUpdateBuilder = tripUpdateBuilder.addStopTimeUpdateBuilder(0); stopTimeUpdateBuilder.setStopSequence(1); stopTimeUpdateBuilder.setScheduleRelationship(StopTimeUpdate.ScheduleRelationship.SCHEDULED); stopTimeEventBuilder = stopTimeUpdateBuilder.getArrivalBuilder(); stopTimeEventBuilder.setTime( TestUtils.dateInSeconds("America/New_York", 2009, AUGUST, 7, 0, 2, 0)); stopTimeEventBuilder = stopTimeUpdateBuilder.getDepartureBuilder(); stopTimeEventBuilder.setTime( TestUtils.dateInSeconds("America/New_York", 2009, AUGUST, 7, 0, 2, 0)); tripUpdate = tripUpdateBuilder.build(); assertEquals(20 * 60, timetable.getTripTimes(trip_1_1_index).getArrivalTime(2)); assertTrue(timetable.update(tripUpdate, "agency", timeZone, serviceDate)); assertEquals(20 * 60 + 120, timetable.getTripTimes(trip_1_1_index).getArrivalTime(2)); // --- options.setRoutingContext(graph, stop_a, stop_c); spt = aStar.getShortestPathTree(options); path = spt.getPath(stop_c, false); assertNotNull(path); endTime = startTime + 20 * 60 + 120; assertEquals(endTime, path.getEndTime()); // cancel trip tripDescriptorBuilder = TripDescriptor.newBuilder(); tripDescriptorBuilder.setTripId("1.1"); tripDescriptorBuilder.setScheduleRelationship(TripDescriptor.ScheduleRelationship.CANCELED); tripUpdateBuilder = TripUpdate.newBuilder(); tripUpdateBuilder.setTrip(tripDescriptorBuilder); tripUpdate = tripUpdateBuilder.build(); assertTrue(timetable.update(tripUpdate, "agency", timeZone, serviceDate)); TripTimes tripTimes = timetable.getTripTimes(trip_1_1_index); for (int i = 0; i < tripTimes.getNumStops(); i++) { assertEquals(TripTimes.UNAVAILABLE, tripTimes.getDepartureTime(i)); assertEquals(TripTimes.UNAVAILABLE, tripTimes.getArrivalTime(i)); } // --- options.setRoutingContext(graph, stop_a, stop_c); spt = aStar.getShortestPathTree(options); path = spt.getPath(stop_c, false); assertNotNull(path); endTime = startTime + 40 * 60; assertEquals(endTime, path.getEndTime()); // update trip arrival time incorrectly tripDescriptorBuilder = TripDescriptor.newBuilder(); tripDescriptorBuilder.setTripId("1.1"); tripDescriptorBuilder.setScheduleRelationship(TripDescriptor.ScheduleRelationship.SCHEDULED); tripUpdateBuilder = TripUpdate.newBuilder(); tripUpdateBuilder.setTrip(tripDescriptorBuilder); stopTimeUpdateBuilder = tripUpdateBuilder.addStopTimeUpdateBuilder(0); stopTimeUpdateBuilder.setStopSequence(1); stopTimeUpdateBuilder.setScheduleRelationship(StopTimeUpdate.ScheduleRelationship.SCHEDULED); stopTimeEventBuilder = stopTimeUpdateBuilder.getArrivalBuilder(); stopTimeEventBuilder.setDelay(0); tripUpdate = tripUpdateBuilder.build(); assertTrue(timetable.update(tripUpdate, "agency", timeZone, serviceDate)); // update trip arrival time only tripDescriptorBuilder = TripDescriptor.newBuilder(); tripDescriptorBuilder.setTripId("1.1"); tripDescriptorBuilder.setScheduleRelationship(TripDescriptor.ScheduleRelationship.SCHEDULED); tripUpdateBuilder = TripUpdate.newBuilder(); tripUpdateBuilder.setTrip(tripDescriptorBuilder); stopTimeUpdateBuilder = tripUpdateBuilder.addStopTimeUpdateBuilder(0); stopTimeUpdateBuilder.setStopSequence(2); stopTimeUpdateBuilder.setScheduleRelationship(StopTimeUpdate.ScheduleRelationship.SCHEDULED); stopTimeEventBuilder = stopTimeUpdateBuilder.getArrivalBuilder(); stopTimeEventBuilder.setDelay(1); tripUpdate = tripUpdateBuilder.build(); assertTrue(timetable.update(tripUpdate, "agency", timeZone, serviceDate)); // update trip departure time only tripDescriptorBuilder = TripDescriptor.newBuilder(); tripDescriptorBuilder.setTripId("1.1"); tripDescriptorBuilder.setScheduleRelationship(TripDescriptor.ScheduleRelationship.SCHEDULED); tripUpdateBuilder = TripUpdate.newBuilder(); tripUpdateBuilder.setTrip(tripDescriptorBuilder); stopTimeUpdateBuilder = tripUpdateBuilder.addStopTimeUpdateBuilder(0); stopTimeUpdateBuilder.setStopSequence(2); stopTimeUpdateBuilder.setScheduleRelationship(StopTimeUpdate.ScheduleRelationship.SCHEDULED); stopTimeEventBuilder = stopTimeUpdateBuilder.getDepartureBuilder(); stopTimeEventBuilder.setDelay(-1); tripUpdate = tripUpdateBuilder.build(); assertTrue(timetable.update(tripUpdate, "agency", timeZone, serviceDate)); // update trip using stop id tripDescriptorBuilder = TripDescriptor.newBuilder(); tripDescriptorBuilder.setTripId("1.1"); tripDescriptorBuilder.setScheduleRelationship(TripDescriptor.ScheduleRelationship.SCHEDULED); tripUpdateBuilder = TripUpdate.newBuilder(); tripUpdateBuilder.setTrip(tripDescriptorBuilder); stopTimeUpdateBuilder = tripUpdateBuilder.addStopTimeUpdateBuilder(0); stopTimeUpdateBuilder.setStopId("B"); stopTimeUpdateBuilder.setScheduleRelationship(StopTimeUpdate.ScheduleRelationship.SCHEDULED); stopTimeEventBuilder = stopTimeUpdateBuilder.getDepartureBuilder(); stopTimeEventBuilder.setDelay(-1); tripUpdate = tripUpdateBuilder.build(); assertTrue(timetable.update(tripUpdate, "agency", timeZone, serviceDate)); // update trip arrival time at first stop and make departure time incoherent at second stop tripDescriptorBuilder = TripDescriptor.newBuilder(); tripDescriptorBuilder.setTripId("1.1"); tripDescriptorBuilder.setScheduleRelationship(TripDescriptor.ScheduleRelationship.SCHEDULED); tripUpdateBuilder = TripUpdate.newBuilder(); tripUpdateBuilder.setTrip(tripDescriptorBuilder); stopTimeUpdateBuilder = tripUpdateBuilder.addStopTimeUpdateBuilder(0); stopTimeUpdateBuilder.setStopSequence(1); stopTimeUpdateBuilder.setScheduleRelationship(StopTimeUpdate.ScheduleRelationship.SCHEDULED); stopTimeEventBuilder = stopTimeUpdateBuilder.getArrivalBuilder(); stopTimeEventBuilder.setDelay(0); stopTimeUpdateBuilder = tripUpdateBuilder.addStopTimeUpdateBuilder(1); stopTimeUpdateBuilder.setStopSequence(2); stopTimeUpdateBuilder.setScheduleRelationship(StopTimeUpdate.ScheduleRelationship.SCHEDULED); stopTimeEventBuilder = stopTimeUpdateBuilder.getDepartureBuilder(); stopTimeEventBuilder.setDelay(-1); tripUpdate = tripUpdateBuilder.build(); assertFalse(timetable.update(tripUpdate, "agency", timeZone, serviceDate)); }