Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package org.opentripplanner.ext.siri;
import org.opentripplanner.model.FeedScopedId;
import org.opentripplanner.model.Route;
import org.opentripplanner.model.Station;
import org.opentripplanner.model.Stop;
import org.opentripplanner.model.Trip;
import org.opentripplanner.model.TripPattern;
import org.opentripplanner.model.calendar.ServiceDate;
import org.opentripplanner.routing.RoutingService;
import org.opentripplanner.routing.core.TraverseMode;
import org.opentripplanner.routing.trippattern.TripTimes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.org.siri.siri20.EstimatedCall;
import uk.org.siri.siri20.EstimatedVehicleJourney;
import uk.org.siri.siri20.VehicleActivityStructure;
import uk.org.siri.siri20.VehicleModesEnumeration;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* This class is used for matching TripDescriptors without trip_ids to scheduled GTFS data and to
* feed back that information into a new TripDescriptor with proper trip_id.
*
* It is mainly written for Entur (Norway) data, which doesn't yet have complete ID-based matching of SIRI messages
* to transit model objects. But it may be easily adaptable to other locations, as it's mainly looking at the last stop
* and arrival times of the scheduled trip. The matching process will always be applied even in places where you have
* good quality IDs in SIRI data and don't need it - we'd have to add a way to disable it.
*
* Several instances of this SiriFuzzyTripMatcher may appear in different SIRI updaters, but they all share a common
* set of static Map fields. We generally don't advocate using static fields in this way, but as part of a sandbox
* contribution we are maintaining this implementation.
*/
public class SiriFuzzyTripMatcher {
private static final Logger LOG = LoggerFactory.getLogger(SiriFuzzyTripMatcher.class);
private RoutingService routingService;
private static Map> mappedTripsCache = new HashMap<>();
private static Map> mappedVehicleRefCache = new HashMap<>();
private static Map> mappedRoutesCache = new HashMap<>();
private static Map> start_stop_tripCache = new HashMap<>();
private static Map vehicleJourneyTripCache = new HashMap<>();
private static Set nonExistingStops = new HashSet<>();
public SiriFuzzyTripMatcher(RoutingService routingService) {
this.routingService = routingService;
initCache(this.routingService);
}
/**
* Matches VehicleActivity to a set of possible Trips based on tripId
*/
public Set match(VehicleActivityStructure activity) {
VehicleActivityStructure.MonitoredVehicleJourney monitoredVehicleJourney = activity.getMonitoredVehicleJourney();
Set trips = new HashSet<>();
if (monitoredVehicleJourney != null) {
String datedVehicleRef = null;
if (monitoredVehicleJourney.getFramedVehicleJourneyRef() != null) {
datedVehicleRef = monitoredVehicleJourney.getFramedVehicleJourneyRef().getDatedVehicleJourneyRef();
if (datedVehicleRef != null) {
trips = mappedTripsCache.get(datedVehicleRef);
}
}
if (monitoredVehicleJourney.getDestinationRef() != null) {
String destinationRef = monitoredVehicleJourney.getDestinationRef().getValue();
ZonedDateTime arrivalTime = monitoredVehicleJourney.getDestinationAimedArrivalTime();
if (arrivalTime != null) {
trips = getMatchingTripsOnStopOrSiblings(destinationRef, arrivalTime);
}
}
}
return trips;
}
Trip findTripByDatedVehicleJourneyRef(EstimatedVehicleJourney journey) {
String serviceJourneyId = resolveDatedVehicleJourneyRef(journey);
if (serviceJourneyId != null) {
for (String feedId : routingService.getFeedIds()) {
Trip trip = routingService
.getTripForId().get(new FeedScopedId(feedId, serviceJourneyId));
if (trip != null) {
return trip;
}
}
}
return null;
}
private String resolveDatedVehicleJourneyRef(EstimatedVehicleJourney journey) {
if (journey.getFramedVehicleJourneyRef() != null) {
return journey.getFramedVehicleJourneyRef().getDatedVehicleJourneyRef();
} else if (journey.getDatedVehicleJourneyRef() != null) {
return journey.getDatedVehicleJourneyRef().getValue();
}
return null;
}
/**
* Matches EstimatedVehicleJourney to a set of possible Trips based on tripId
*/
public Set match(EstimatedVehicleJourney journey) {
Set trips = null;
if (journey.getVehicleRef() != null &&
(journey.getVehicleModes() != null && journey.getVehicleModes().contains(VehicleModesEnumeration.RAIL))) {
trips = getCachedTripsByVehicleRef(journey.getVehicleRef().getValue());
}
if (trips == null || trips.isEmpty()) {
String serviceJourneyId = resolveDatedVehicleJourneyRef(journey);
if (serviceJourneyId != null) {
trips = getCachedTripsBySiriId(serviceJourneyId);
}
}
if (trips == null || trips.isEmpty()) {
List estimatedCalls = journey.getEstimatedCalls().getEstimatedCalls();
EstimatedCall lastStop = estimatedCalls.get(estimatedCalls.size() - 1);
String lastStopPoint = lastStop.getStopPointRef().getValue();
ZonedDateTime arrivalTime = lastStop.getAimedArrivalTime() != null ? lastStop.getAimedArrivalTime() : lastStop.getAimedDepartureTime();
if (arrivalTime != null) {
trips = getMatchingTripsOnStopOrSiblings(lastStopPoint, arrivalTime);
}
}
return trips;
}
private Set getMatchingTripsOnStopOrSiblings(String lastStopPoint, ZonedDateTime arrivalTime) {
Set trips = start_stop_tripCache.get(createStartStopKey(lastStopPoint, arrivalTime.toLocalTime().toSecondOfDay()));
if (trips == null) {
//Attempt to fetch trips that started yesterday - i.e. add 24 hours to arrival-time
int lastStopArrivalTime = arrivalTime.toLocalTime().toSecondOfDay() + (24 * 60 * 60);
trips = start_stop_tripCache.get(createStartStopKey(lastStopPoint, lastStopArrivalTime));
}
if (trips == null || trips.isEmpty()) {
//SIRI-data may report other platform, but still on the same Parent-stop
String feedId = routingService.getFeedIds().iterator().next();
Stop stop = routingService.getStopForId(new FeedScopedId(feedId, lastStopPoint));
if (stop != null && stop.isPartOfStation()) {
// TODO OTP2 resolve stop-station split
Collection allQuays = stop.getParentStation().getChildStops();
for (Stop quay : allQuays) {
Set tripSet = start_stop_tripCache.get(createStartStopKey(quay.getId().getId(), arrivalTime.toLocalTime().toSecondOfDay()));
if (tripSet != null) {
if (trips == null) {
trips = tripSet;
} else {
trips.addAll(tripSet);
}
}
}
}
}
return trips;
}
private Set getCachedTripsByVehicleRef(String vehicleRef) {
if (vehicleRef == null) {return null;}
return mappedVehicleRefCache.getOrDefault(vehicleRef, new HashSet<>());
}
private Set getCachedTripsBySiriId(String tripId) {
if (tripId == null) {return null;}
return mappedTripsCache.getOrDefault(tripId, new HashSet<>());
}
private static void initCache(RoutingService index) {
if (mappedTripsCache.isEmpty()) {
Set trips = index.getPatternForTrip().keySet();
for (Trip trip : trips) {
TripPattern tripPattern = index.getPatternForTrip().get(trip);
String currentTripId = getUnpaddedTripId(trip.getId().getId());
if (mappedTripsCache.containsKey(currentTripId)) {
mappedTripsCache.get(currentTripId).add(trip);
} else {
Set initialSet = new HashSet<>();
initialSet.add(trip);
mappedTripsCache.put(currentTripId, initialSet);
}
if (tripPattern != null &&
(tripPattern.getMode().equals(TraverseMode.RAIL) /*||
(trip.getTransportSubmode() != null &&
trip.getTransportSubmode().equals(TransmodelTransportSubmode.RAIL_REPLACEMENT_BUS))*/)) {
// TODO - SIRI: Add support for submode
if (trip.getTripShortName() != null) {
String tripShortName = trip.getTripShortName();
if (mappedVehicleRefCache.containsKey(tripShortName)) {
mappedVehicleRefCache.get(tripShortName).add(trip);
} else {
Set initialSet = new HashSet<>();
initialSet.add(trip);
mappedVehicleRefCache.put(tripShortName, initialSet);
}
}
}
String lastStopId = tripPattern.getStops().get(tripPattern.getStops().size()-1).getId().getId();
TripTimes tripTimes = tripPattern.scheduledTimetable.getTripTimes(trip);
if (tripTimes != null) {
int arrivalTime = tripTimes.getArrivalTime(tripTimes.getNumStops() - 1);
String key = createStartStopKey(lastStopId, arrivalTime);
if (start_stop_tripCache.containsKey(key)) {
start_stop_tripCache.get(key).add(trip);
} else {
Set initialSet = new HashSet<>();
initialSet.add(trip);
start_stop_tripCache.put(key, initialSet);
}
}
}
Set routes = index.getPatternsForRoute().keySet();
for (Route route : routes) {
String currentRouteId = getUnpaddedTripId(route.getId().getId());
if (mappedRoutesCache.containsKey(currentRouteId)) {
mappedRoutesCache.get(currentRouteId).add(route);
} else {
Set initialSet = new HashSet<>();
initialSet.add(route);
mappedRoutesCache.put(currentRouteId, initialSet);
}
}
LOG.info("Built route-cache [{}].", mappedRoutesCache.size());
LOG.info("Built vehicleRef-cache [{}].", mappedVehicleRefCache.size());
LOG.info("Built trips-cache [{}].", mappedTripsCache.size());
LOG.info("Built start-stop-cache [{}].", start_stop_tripCache.size());
}
if (vehicleJourneyTripCache.isEmpty()) {
index
.getTripForId()
.values().forEach(trip -> vehicleJourneyTripCache.put(trip.getId().getId(), trip));
}
}
private static String createStartStopKey(String lastStopId, int lastStopArrivalTime) {
return lastStopId + ":" + lastStopArrivalTime;
}
private static String getUnpaddedTripId(String id) {
if (id.indexOf("-") > 0) {
return id.substring(0, id.indexOf("-"));
} else {
return id;
}
}
public Set getRoutesForStop(FeedScopedId siriStopId) {
Stop stop = routingService.getStopForId(siriStopId);
return routingService.getRoutesForStop(stop);
}
public FeedScopedId getStop(String siriStopId) {
if (nonExistingStops.contains(siriStopId)) {
return null;
}
// TODO OTP2 #2838 - Guessing on the feedId is not a deterministic way to find a stop.
//First, assume same agency
Stop firstStop = routingService.getAllStops().stream().findFirst().get();
FeedScopedId id = new FeedScopedId(firstStop.getId().getFeedId(), siriStopId);
if (routingService.getStopForId(id) != null) {
return id;
}
else if (routingService.getStationById(id) != null) {
return id;
}
//Not same agency - loop through all stops/Stations
Collection stops = routingService.getAllStops();
for (Stop stop : stops) {
if (stop.getId().getId().equals(siriStopId)) {
return stop.getId();
}
}
//No match found in quays - check parent-stops (stopplace)
for (Station station : routingService.getStations()) {
if (station.getId().getId().equals(siriStopId)) {
return station.getId();
}
}
nonExistingStops.add(siriStopId);
return null;
}
public Set getRoutes(String lineRefValue) {
return mappedRoutesCache.getOrDefault(lineRefValue, new HashSet<>());
}
public FeedScopedId getTripId(String vehicleJourney) {
Trip trip = vehicleJourneyTripCache.get(vehicleJourney);
if (trip != null) {
return trip.getId();
}
//Fallback to handle extrajourneys
for (String feedId : routingService.getFeedIds()) {
trip = routingService.getTripForId().get(new FeedScopedId(feedId, vehicleJourney));
if (trip != null) {
vehicleJourneyTripCache.put(vehicleJourney, trip);
return trip.getId();
}
}
return null;
}
List getTripIdForTripShortNameServiceDateAndMode(String tripShortName, ServiceDate serviceDate, TraverseMode traverseMode/*, TransmodelTransportSubmode transportSubmode*/) {
Set cachedTripsBySiriId = getCachedTripsBySiriId(tripShortName);
if (cachedTripsBySiriId.isEmpty()) {
cachedTripsBySiriId = getCachedTripsByVehicleRef(tripShortName);
}
List matches = new ArrayList<>();
for (Trip trip : cachedTripsBySiriId) {
if (trip.getRoute().getMode().equals(traverseMode)
/*|| trip.getTransportSubmode().equals(transportSubmode)*/) {
Set serviceDates = routingService.getCalendarService().getServiceDatesForServiceId(trip.getServiceId());
if (serviceDates.contains(serviceDate) &&
trip.getTripShortName() != null &&
trip.getTripShortName().equals(tripShortName)) {
matches.add(trip.getId());
}
}
}
return matches;
}
public int getTripDepartureTime(FeedScopedId tripId) {
Trip trip = routingService.getTripForId().get(tripId);
{
TripPattern tripPattern = routingService.getPatternForTrip().get(trip);
if (tripPattern != null) {
TripTimes tripTimes = tripPattern.scheduledTimetable.getTripTimes(trip);
if (tripTimes != null) {
return tripTimes.getArrivalTime(0);
}
}
}
return -1;
}
public int getTripArrivalTime(FeedScopedId tripId) {
Trip trip = routingService.getTripForId().get(tripId);
{
TripPattern tripPattern = routingService.getPatternForTrip().get(trip);
if (tripPattern != null) {
TripTimes tripTimes = tripPattern.scheduledTimetable.getTripTimes(trip);
if (tripTimes != null) {
return tripTimes.getArrivalTime(tripTimes.getNumStops()-1);
}
}
}
return -1;
}
}