
org.opentripplanner.routing.impl.TransitAlertServiceImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of otp Show documentation
Show all versions of otp Show documentation
The OpenTripPlanner multimodal journey planning system
The newest version!
package org.opentripplanner.routing.impl;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import java.time.LocalDate;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.opentripplanner.routing.alertpatch.EntityKey;
import org.opentripplanner.routing.alertpatch.EntitySelector;
import org.opentripplanner.routing.alertpatch.StopCondition;
import org.opentripplanner.routing.alertpatch.TransitAlert;
import org.opentripplanner.routing.services.TransitAlertService;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.transit.model.timetable.Direction;
import org.opentripplanner.transit.service.TransitModel;
/**
* This is the primary implementation of TransitAlertService, which actually retains its own set
* of TransitAlerts and indexes them for fast lookup by which transit entity is affected.
* The only other implementation exists just to combine several instances of this primary
* implementation into one.
* TODO RT_AB: investigate why each updater has its own service instead of taking turns
* sequentially writing to a single service. Original design was for all data and indexes to be
* associated with the Graph or transit model (i.e. the object graph of instances of the transit
* model) and for updaters to submit write tasks that would patch the current version in a
* sequential way, e.g. "add these 10 alerts", "remove these 5 alerts", etc.
*
* When an alert is added with more than one transit entity, e.g. a Stop and a Trip, both conditions
* must be met for the alert to be displayed. This is the case in both the Norwegian interpretation
* of SIRI, and the GTFS-RT alerts specification.
*/
public class TransitAlertServiceImpl implements TransitAlertService {
private final TransitModel transitModel;
private Multimap alerts = HashMultimap.create();
public TransitAlertServiceImpl(TransitModel transitModel) {
this.transitModel = transitModel;
}
@Override
public void setAlerts(Collection alerts) {
// FIXME RT_AB: this is patched live by updaters while in use (being read) by other threads
// performing trip planning. The single-action assignment helps a bit, but the map can be
// swapped out while the delegating service is in the middle of multiple calls that read from
// it. The consistent approach would be to duplicate the entire service, update it
// copy-on-write, and swap in the entire service after the update.
Multimap newAlerts = HashMultimap.create();
for (TransitAlert alert : alerts) {
for (EntitySelector entity : alert.entities()) {
newAlerts.put(entity.key(), alert);
}
}
this.alerts = newAlerts;
}
@Override
public Collection getAllAlerts() {
return new HashSet<>(alerts.values());
}
@Override
public TransitAlert getAlertById(FeedScopedId id) {
return alerts
.values()
.stream()
.filter(transitAlert -> transitAlert.getId().equals(id))
.findAny()
.orElse(null);
}
@Override
public Collection getStopAlerts(
FeedScopedId stopId,
Set stopConditions
) {
Set result = new HashSet<>();
EntitySelector.Stop entitySelector = new EntitySelector.Stop(stopId, stopConditions);
for (TransitAlert alert : alerts.get(entitySelector.key())) {
if (alert.entities().stream().anyMatch(selector -> selector.matches(entitySelector))) {
result.add(alert);
}
}
if (result.isEmpty()) {
// Search for alerts on parent-stop
if (transitModel != null) {
var quay = transitModel.getStopModel().getRegularStop(stopId);
if (quay != null) {
// TODO - SIRI: Add alerts from parent- and multimodal-stops
/*
if ( quay.isPartOfStation()) {
// Add alerts for parent-station
result.addAll(patchesByStop.getOrDefault(quay.getParentStationFeedScopedId(), Collections.emptySet()));
}
if (quay.getMultiModalStation() != null) {
// Add alerts for multimodal-station
result.addAll(patchesByStop.getOrDefault(new FeedScopedId(stop.getAgencyId(), quay.getMultiModalStation()), Collections.emptySet()));
}
*/
}
}
}
return result;
}
@Override
public Collection getRouteAlerts(FeedScopedId route) {
return alerts.get(new EntityKey.Route(route));
}
@Override
public Collection getTripAlerts(FeedScopedId trip, LocalDate serviceDate) {
Set result = new HashSet<>();
EntitySelector.Trip entitySelector = new EntitySelector.Trip(trip, serviceDate);
for (TransitAlert alert : alerts.get(entitySelector.key())) {
if (alert.entities().stream().anyMatch(selector -> selector.matches(entitySelector))) {
result.add(alert);
}
}
return result;
}
@Override
public Collection getAgencyAlerts(FeedScopedId agency) {
return alerts.get(new EntityKey.Agency(agency));
}
@Override
public Collection getStopAndRouteAlerts(
FeedScopedId stop,
FeedScopedId route,
Set stopConditions
) {
Set result = new HashSet<>();
EntitySelector.StopAndRoute entitySelector = new EntitySelector.StopAndRoute(
stop,
route,
stopConditions
);
for (TransitAlert alert : alerts.get(entitySelector.key())) {
if (alert.entities().stream().anyMatch(selector -> selector.matches(entitySelector))) {
result.add(alert);
}
}
return result;
}
@Override
public Collection getStopAndTripAlerts(
FeedScopedId stop,
FeedScopedId trip,
LocalDate serviceDate,
Set stopConditions
) {
Set result = new HashSet<>();
EntitySelector.StopAndTrip entitySelector = new EntitySelector.StopAndTrip(
stop,
trip,
serviceDate,
stopConditions
);
for (TransitAlert alert : alerts.get(entitySelector.key())) {
if (alert.entities().stream().anyMatch(selector -> selector.matches(entitySelector))) {
result.add(alert);
}
}
return result;
}
@Override
public Collection getRouteTypeAndAgencyAlerts(int routeType, FeedScopedId agency) {
return alerts.get(new EntityKey.RouteTypeAndAgency(agency, routeType));
}
@Override
public Collection getRouteTypeAlerts(int routeType, String feedId) {
return alerts.get(new EntityKey.RouteType(feedId, routeType));
}
@Override
public Collection getDirectionAndRouteAlerts(
Direction direction,
FeedScopedId route
) {
return alerts.get(new EntityKey.DirectionAndRoute(route, direction));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy