/** * 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()); }
private void recordTripUpdate(TripUpdate tripUpdate, DataCopier tuCopier, DataCopier stCopier) throws SQLException { PreparedStatement stmt = null; int updateId = getUpdateId(); DataCopierRow tuRow = null; if (tuCopier != null) { tuRow = new DataCopierRow(); } else { stmt = mStatements.get(STTRIPUPDATE); } if (tuRow == null) { stmt.setInt(1, updateId); } else { tuRow.add(updateId); } if (tripUpdate.hasTimestamp()) { if (tuRow == null) { stmt.setLong(2, tripUpdate.getTimestamp()); } else { tuRow.add(tripUpdate.getTimestamp()); } } else { if (tuRow == null) { stmt.setNull(2, Types.INTEGER); } else { tuRow.addNull(); } } if (tripUpdate.hasTrip()) { TripDescriptor trip = tripUpdate.getTrip(); if (trip.hasScheduleRelationship()) { if (tuRow == null) { stmt.setInt(3, trip.getScheduleRelationship().getNumber()); } else { tuRow.add(trip.getScheduleRelationship().getNumber()); } } else { if (tuRow == null) { stmt.setNull(3, Types.INTEGER); } else { tuRow.addNull(); } } if (trip.hasStartDate()) { if (tuRow == null) { stmt.setString(4, trip.getStartDate()); } else { tuRow.add(trip.getStartDate()); } } else { if (tuRow == null) { stmt.setNull(4, Types.VARCHAR); } else { tuRow.addNull(); } } if (trip.hasStartTime()) { if (tuRow == null) { stmt.setString(5, trip.getStartTime()); } else { tuRow.add(trip.getStartTime()); } } else { if (tuRow == null) { stmt.setNull(5, Types.VARCHAR); } else { tuRow.addNull(); } } if (trip.hasTripId()) { if (tuRow == null) { stmt.setString(6, trip.getTripId()); } else { tuRow.add(trip.getTripId()); } } else { if (tuRow == null) { stmt.setNull(6, Types.VARCHAR); } else { tuRow.addNull(); } } if (trip.hasRouteId()) { if (tuRow == null) { stmt.setString(7, trip.getRouteId()); } else { tuRow.add(trip.getRouteId()); } } else { if (tuRow == null) { stmt.setNull(7, Types.VARCHAR); } else { tuRow.addNull(); } } } else { if (tuRow == null) { stmt.setNull(3, Types.INTEGER); stmt.setNull(4, Types.VARCHAR); stmt.setNull(5, Types.VARCHAR); stmt.setNull(6, Types.VARCHAR); stmt.setNull(7, Types.VARCHAR); } else { tuRow.addNull(5); } } if (tripUpdate.hasVehicle()) { VehicleDescriptor vd = tripUpdate.getVehicle(); if (vd.hasId()) { if (tuRow == null) { stmt.setString(8, vd.getId()); } else { tuRow.add(vd.getId()); } } else { if (tuRow == null) { stmt.setNull(8, Types.INTEGER); } else { tuRow.addNull(); } } if (vd.hasLabel()) { if (tuRow == null) { stmt.setString(9, vd.getLabel()); } else { tuRow.add(vd.getLabel()); } } else { if (tuRow == null) { stmt.setNull(9, Types.VARCHAR); } else { tuRow.addNull(); } } if (vd.hasLicensePlate()) { if (tuRow == null) { stmt.setString(10, vd.getLicensePlate()); } else { tuRow.add(vd.getLicensePlate()); } } else { if (tuRow == null) { stmt.setNull(10, Types.VARCHAR); } else { tuRow.addNull(); } } } else { if (tuRow == null) { stmt.setNull(8, Types.INTEGER); stmt.setNull(9, Types.VARCHAR); stmt.setNull(10, Types.VARCHAR); } else { tuRow.addNull(3); } } Date recorded = new Date(); if (tuRow == null) { stmt.setInt(11, (int) (recorded.getTime() / 1000)); } else { tuRow.add((int) (recorded.getTime() / 1000)); } if (tuCopier == null) { stmt.addBatch(); } else { tuCopier.add(tuRow); } if (stCopier == null) { stmt = mStatements.get(STTRIPUPDATE_STOPTIMEUPDATES); } else { stmt = null; } for (StopTimeUpdate stu : tripUpdate.getStopTimeUpdateList()) { DataCopierRow stRow = null; if (stmt == null) { stRow = new DataCopierRow(); } if (stRow == null) { stmt.setInt(1, updateId); } else { stRow.add(updateId); } if (stu.hasArrival()) { StopTimeEvent ste = stu.getArrival(); if (ste.hasTime()) { if (stRow == null) { stmt.setLong(2, ste.getTime()); } else { stRow.add(ste.getTime()); } } else { if (stRow == null) { stmt.setNull(2, Types.INTEGER); } else { stRow.addNull(); } } if (ste.hasUncertainty()) { if (stRow == null) { stmt.setInt(3, ste.getUncertainty()); } else { stRow.add(ste.getUncertainty()); } } else { if (stRow == null) { stmt.setNull(3, Types.INTEGER); } else { stRow.addNull(); } } if (ste.hasDelay()) { if (stRow == null) { stmt.setInt(4, ste.getDelay()); } else { stRow.add(ste.getDelay()); } } else { if (stRow == null) { stmt.setNull(4, Types.INTEGER); } else { stRow.addNull(); } } } else { if (stRow == null) { stmt.setNull(2, Types.INTEGER); stmt.setNull(3, Types.INTEGER); stmt.setNull(4, Types.INTEGER); } else { stRow.addNull(3); } } if (stu.hasDeparture()) { StopTimeEvent ste = stu.getDeparture(); if (ste.hasTime()) { if (stRow == null) { stmt.setLong(5, ste.getTime()); } else { stRow.add(ste.getTime()); } } else { if (stRow == null) { stmt.setNull(5, Types.INTEGER); } else { stRow.addNull(); } } if (ste.hasUncertainty()) { if (stRow == null) { stmt.setInt(6, ste.getUncertainty()); } else { stRow.add(ste.getUncertainty()); } } else { if (stRow == null) { stmt.setNull(6, Types.INTEGER); } else { stRow.addNull(); } } if (ste.hasDelay()) { if (stRow == null) { stmt.setInt(7, ste.getDelay()); } else { stRow.add(ste.getDelay()); } } else { if (stRow == null) { stmt.setNull(7, Types.INTEGER); } else { stRow.addNull(); } } } else { if (stRow == null) { stmt.setNull(5, Types.INTEGER); stmt.setNull(6, Types.INTEGER); stmt.setNull(7, Types.INTEGER); } else { stRow.addNull(3); } } int srInt = stu.hasScheduleRelationship() ? stu.getScheduleRelationship().getNumber() : com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate .ScheduleRelationship.SCHEDULED_VALUE; if (stRow == null) { stmt.setInt(8, srInt); } else { stRow.add(srInt); } if (stu.hasStopId()) { if (stRow == null) { stmt.setString(9, stu.getStopId()); } else { stRow.add(stu.getStopId()); } } else { if (stRow == null) { stmt.setNull(9, Types.VARCHAR); } else { stRow.addNull(); } } int ssInt = stu.hasStopSequence() ? stu.getStopSequence() : -1; if (stRow == null) { stmt.setInt(10, ssInt); } else { stRow.add(ssInt); } if (stmt == null) { stCopier.add(stRow); } else { stmt.addBatch(); } } }
@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)); }