
org.opentripplanner.updater.alert.gtfs.AlertsUpdateHandler Maven / Gradle / Ivy
The newest version!
package org.opentripplanner.updater.alert.gtfs;
import static org.opentripplanner.updater.alert.gtfs.mapping.GtfsRealtimeCauseMapper.getAlertCauseForGtfsRtCause;
import static org.opentripplanner.updater.alert.gtfs.mapping.GtfsRealtimeEffectMapper.getAlertEffectForGtfsRtEffect;
import static org.opentripplanner.updater.alert.gtfs.mapping.GtfsRealtimeSeverityMapper.getAlertSeverityForGtfsRtSeverity;
import com.google.transit.realtime.GtfsRealtime;
import com.google.transit.realtime.GtfsRealtime.FeedEntity;
import com.google.transit.realtime.GtfsRealtime.FeedMessage;
import com.google.transit.realtime.GtfsRealtime.TimeRange;
import com.google.transit.realtime.GtfsRealtime.TripDescriptor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.opentripplanner.framework.i18n.I18NString;
import org.opentripplanner.framework.i18n.TranslatedString;
import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore;
import org.opentripplanner.gtfs.mapping.DirectionMapper;
import org.opentripplanner.routing.alertpatch.EntitySelector;
import org.opentripplanner.routing.alertpatch.TimePeriod;
import org.opentripplanner.routing.alertpatch.TransitAlert;
import org.opentripplanner.routing.alertpatch.TransitAlertBuilder;
import org.opentripplanner.routing.services.TransitAlertService;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.updater.trip.gtfs.GtfsRealtimeFuzzyTripMatcher;
/**
* This updater only includes GTFS-Realtime Service Alert feeds.
*
* @author novalis
*/
public class AlertsUpdateHandler {
private static final int MISSING_INT_FIELD_VALUE = -1;
private String feedId;
private TransitAlertService transitAlertService;
/** How long before the posted start of an event it should be displayed to users */
private long earlyStart;
/** Set only if we should attempt to match the trip_id from other data in TripDescriptor */
private final boolean fuzzyTripMatching;
// TODO: replace this with a runtime solution
private final DirectionMapper directionMapper = new DirectionMapper(DataImportIssueStore.NOOP);
public AlertsUpdateHandler(boolean fuzzyTripMatching) {
this.fuzzyTripMatching = fuzzyTripMatching;
}
public void update(FeedMessage message, GtfsRealtimeFuzzyTripMatcher fuzzyTripMatcher) {
Collection alerts = new ArrayList<>();
for (FeedEntity entity : message.getEntityList()) {
if (!entity.hasAlert()) {
continue;
}
GtfsRealtime.Alert alert = entity.getAlert();
String id = entity.getId();
alerts.add(mapAlert(id, alert, fuzzyTripMatcher));
}
transitAlertService.setAlerts(alerts);
}
public void setFeedId(String feedId) {
if (feedId != null) this.feedId = feedId.intern();
}
public void setTransitAlertService(TransitAlertService transitAlertService) {
this.transitAlertService = transitAlertService;
}
public void setEarlyStart(long earlyStart) {
this.earlyStart = earlyStart;
}
private TransitAlert mapAlert(
String id,
GtfsRealtime.Alert alert,
GtfsRealtimeFuzzyTripMatcher fuzzyTripMatcher
) {
TransitAlertBuilder alertBuilder = TransitAlert.of(new FeedScopedId(feedId, id))
.withDescriptionText(deBuffer(alert.getDescriptionText()))
.withHeaderText(deBuffer(alert.getHeaderText()))
.withUrl(deBuffer(alert.getUrl()))
.withSeverity(getAlertSeverityForGtfsRtSeverity(alert.getSeverityLevel()))
.withCause(getAlertCauseForGtfsRtCause(alert.getCause()))
.withEffect(getAlertEffectForGtfsRtEffect(alert.getEffect()));
ArrayList periods = new ArrayList<>();
if (alert.getActivePeriodCount() > 0) {
for (TimeRange activePeriod : alert.getActivePeriodList()) {
final long realStart = activePeriod.hasStart() ? activePeriod.getStart() : 0;
final long start = activePeriod.hasStart() ? realStart - earlyStart : 0;
final long end = activePeriod.hasEnd() ? activePeriod.getEnd() : TimePeriod.OPEN_ENDED;
periods.add(new TimePeriod(start, end));
}
} else {
// Per the GTFS-rt spec, if an alert has no TimeRanges, than it should always be shown.
periods.add(new TimePeriod(0, TimePeriod.OPEN_ENDED));
}
alertBuilder.addTimePeriods(periods);
for (GtfsRealtime.EntitySelector informed : alert.getInformedEntityList()) {
if (fuzzyTripMatching && informed.hasTrip()) {
TripDescriptor trip = fuzzyTripMatcher.match(feedId, informed.getTrip());
informed = informed.toBuilder().setTrip(trip).build();
}
String routeId = null;
if (informed.hasRouteId()) {
routeId = informed.getRouteId();
}
int directionId = MISSING_INT_FIELD_VALUE;
if (informed.hasDirectionId()) {
directionId = informed.getDirectionId();
}
String tripId = null;
if (informed.hasTrip() && informed.getTrip().hasTripId()) {
tripId = informed.getTrip().getTripId();
}
String stopId = null;
if (informed.hasStopId()) {
stopId = informed.getStopId();
}
String agencyId = null;
if (informed.hasAgencyId()) {
agencyId = informed.getAgencyId().intern();
}
int routeType = MISSING_INT_FIELD_VALUE;
if (informed.hasRouteType()) {
routeType = informed.getRouteType();
}
if (tripId != null) {
if (stopId != null) {
alertBuilder.addEntity(
new EntitySelector.StopAndTrip(
new FeedScopedId(feedId, stopId),
new FeedScopedId(feedId, tripId)
)
);
} else {
alertBuilder.addEntity(new EntitySelector.Trip(new FeedScopedId(feedId, tripId)));
}
} else if (routeId != null) {
if (stopId != null) {
alertBuilder.addEntity(
new EntitySelector.StopAndRoute(
new FeedScopedId(feedId, stopId),
new FeedScopedId(feedId, routeId)
)
);
} else if (directionId != MISSING_INT_FIELD_VALUE) {
alertBuilder.addEntity(
new EntitySelector.DirectionAndRoute(
new FeedScopedId(feedId, routeId),
directionMapper.map(directionId)
)
);
} else {
alertBuilder.addEntity(new EntitySelector.Route(new FeedScopedId(feedId, routeId)));
}
} else if (stopId != null) {
alertBuilder.addEntity(new EntitySelector.Stop(new FeedScopedId(feedId, stopId)));
} else if (agencyId != null) {
FeedScopedId feedScopedAgencyId = new FeedScopedId(feedId, agencyId);
if (routeType != MISSING_INT_FIELD_VALUE) {
alertBuilder.addEntity(
new EntitySelector.RouteTypeAndAgency(feedScopedAgencyId, routeType)
);
} else {
alertBuilder.addEntity(new EntitySelector.Agency(feedScopedAgencyId));
}
} else if (routeType != MISSING_INT_FIELD_VALUE) {
alertBuilder.addEntity(new EntitySelector.RouteType(feedId, routeType));
} else {
String description = "Entity selector: " + informed;
alertBuilder.addEntity(new EntitySelector.Unknown(description));
}
}
if (!alertBuilder.hasEntities()) {
alertBuilder.addEntity(new EntitySelector.Unknown("Alert had no entities"));
}
return alertBuilder.build();
}
/**
* Convert a GTFS-RT Protobuf TranslatedString to an TranslatedString.
*
* @return An OTP TranslatedString containing the same information as the input GTFS-RT Protobuf
* TranslatedString.
*/
private I18NString deBuffer(GtfsRealtime.TranslatedString input) {
Map translations = new HashMap<>();
for (GtfsRealtime.TranslatedString.Translation translation : input.getTranslationList()) {
String language = translation.getLanguage();
String string = translation.getText();
translations.put(language, string);
}
return translations.isEmpty() ? null : TranslatedString.getI18NString(translations, true, true);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy