/* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.opentripplanner.updater.alerts; import java.io.InputStream; import com.fasterxml.jackson.databind.JsonNode; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.impl.AlertPatchServiceImpl; import org.opentripplanner.routing.services.AlertPatchService; import org.opentripplanner.updater.GraphUpdaterManager; import org.opentripplanner.updater.GraphWriterRunnable; import org.opentripplanner.updater.GtfsRealtimeFuzzyTripMatcher; import org.opentripplanner.updater.PollingGraphUpdater; import org.opentripplanner.util.HttpUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.transit.realtime.GtfsRealtime.FeedMessage; /** * GTFS-RT alerts updater * * Usage example ('myalert' name is an example) in file 'Graph.properties': * * <pre> * myalert.type = real-time-alerts * myalert.frequencySec = 60 * myalert.url = http://host.tld/path * myalert.earlyStartSec = 3600 * myalert.feedId = TA * </pre> */ public class GtfsRealtimeAlertsUpdater extends PollingGraphUpdater { private static final Logger LOG = LoggerFactory.getLogger(GtfsRealtimeAlertsUpdater.class); private GraphUpdaterManager updaterManager; private Long lastTimestamp = Long.MIN_VALUE; private String url; private String feedId; private GtfsRealtimeFuzzyTripMatcher fuzzyTripMatcher; private AlertPatchService alertPatchService; private long earlyStart; private AlertsUpdateHandler updateHandler = null; @Override public void setGraphUpdaterManager(GraphUpdaterManager updaterManager) { this.updaterManager = updaterManager; } @Override protected void configurePolling(Graph graph, JsonNode config) throws Exception { // TODO: add options to choose different patch services AlertPatchService alertPatchService = new AlertPatchServiceImpl(graph); this.alertPatchService = alertPatchService; String url = config.path("url").asText(); if (url == null) { throw new IllegalArgumentException("Missing mandatory 'url' parameter"); } this.url = url; this.earlyStart = config.path("earlyStartSec").asInt(0); this.feedId = config.path("feedId").asText(); if (config.path("fuzzyTripMatching").asBoolean(false)) { this.fuzzyTripMatcher = new GtfsRealtimeFuzzyTripMatcher(graph.index); } LOG.info("Creating real-time alert updater running every {} seconds : {}", frequencySec, url); } @Override public void setup() { if (updateHandler == null) { updateHandler = new AlertsUpdateHandler(); } updateHandler.setEarlyStart(earlyStart); updateHandler.setFeedId(feedId); updateHandler.setAlertPatchService(alertPatchService); updateHandler.setFuzzyTripMatcher(fuzzyTripMatcher); } @Override protected void runPolling() { try { InputStream data = HttpUtils.getData(url); if (data == null) { throw new RuntimeException("Failed to get data from url " + url); } final FeedMessage feed = FeedMessage.PARSER.parseFrom(data); long feedTimestamp = feed.getHeader().getTimestamp(); if (feedTimestamp <= lastTimestamp) { LOG.info("Ignoring feed with an old timestamp."); return; } // Handle update in graph writer runnable updaterManager.execute(new GraphWriterRunnable() { @Override public void run(Graph graph) { updateHandler.update(feed); } }); lastTimestamp = feedTimestamp; } catch (Exception e) { LOG.error("Error reading gtfs-realtime feed from " + url, e); } } @Override public void teardown() { } public String toString() { return "GtfsRealtimeUpdater(" + url + ")"; } }