org.opentripplanner.model.impl.OtpTransitServiceBuilder 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
package org.opentripplanner.model.impl;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import org.opentripplanner.ext.flex.trip.FlexTrip;
import org.opentripplanner.model.Agency;
import org.opentripplanner.model.BoardingArea;
import org.opentripplanner.model.Entrance;
import org.opentripplanner.model.FareAttribute;
import org.opentripplanner.model.FareRule;
import org.opentripplanner.model.FeedInfo;
import org.opentripplanner.model.FeedScopedId;
import org.opentripplanner.model.Frequency;
import org.opentripplanner.model.GroupOfStations;
import org.opentripplanner.model.FlexStopLocation;
import org.opentripplanner.model.FlexLocationGroup;
import org.opentripplanner.model.MultiModalStation;
import org.opentripplanner.model.Notice;
import org.opentripplanner.model.Operator;
import org.opentripplanner.model.OtpTransitService;
import org.opentripplanner.model.Pathway;
import org.opentripplanner.model.PathwayNode;
import org.opentripplanner.model.Route;
import org.opentripplanner.model.ShapePoint;
import org.opentripplanner.model.Station;
import org.opentripplanner.model.Stop;
import org.opentripplanner.model.StopPattern;
import org.opentripplanner.model.FareZone;
import org.opentripplanner.model.Transfer;
import org.opentripplanner.model.TransitEntity;
import org.opentripplanner.model.Trip;
import org.opentripplanner.model.TripPattern;
import org.opentripplanner.model.TripStopTimes;
import org.opentripplanner.model.calendar.CalendarServiceData;
import org.opentripplanner.model.calendar.ServiceCalendar;
import org.opentripplanner.model.calendar.ServiceCalendarDate;
import org.opentripplanner.model.calendar.ServiceDateInterval;
import org.opentripplanner.model.calendar.impl.CalendarServiceDataFactoryImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.opentripplanner.model.impl.GenerateMissingIds.generateNoneExistentIds;
/**
* This class is responsible for building a {@link OtpTransitService}. The instance returned by the
* {@link #build()} method is read only, and this class provide a mutable collections to construct
* a {@link OtpTransitService} instance.
*/
public class OtpTransitServiceBuilder {
private static final Logger LOG = LoggerFactory.getLogger(OtpTransitServiceBuilder.class);
private final EntityById agenciesById = new EntityById<>();
private final List calendarDates = new ArrayList<>();
private final List calendars = new ArrayList<>();
private final List fareAttributes = new ArrayList<>();
private final List fareRules = new ArrayList<>();
private final List feedInfos = new ArrayList<>();
private final List frequencies = new ArrayList<>();
private final EntityById groupsOfStationsById = new EntityById<>();
private final EntityById multiModalStationsById = new EntityById<>();
private final Multimap, Notice> noticeAssignments = ArrayListMultimap.create();
private final EntityById operatorsById = new EntityById<>();
private final List pathways = new ArrayList<>();
private final EntityById routesById = new EntityById<>();
private final Multimap shapePoints = ArrayListMultimap.create();
private final EntityById stationsById = new EntityById<>();
private final EntityById stopsById = new EntityById<>();
private final EntityById entrancesById = new EntityById<>();
private final EntityById pathwayNodesById = new EntityById<>();
private final EntityById boardingAreasById = new EntityById<>();
private final EntityById locationsById = new EntityById<>();
private final EntityById locationGroupsById = new EntityById<>();
private final TripStopTimes stopTimesByTrip = new TripStopTimes();
private final EntityById fareZonesById = new EntityById<>();
private final List transfers = new ArrayList<>();
private final EntityById tripsById = new EntityById<>();
private final Multimap tripPatterns = ArrayListMultimap.create();
private final EntityById flexTripsById = new EntityById<>();
public OtpTransitServiceBuilder() {
}
/* Accessors */
public EntityById getAgenciesById() {
return agenciesById;
}
public List getCalendarDates() {
return calendarDates;
}
public List getCalendars() {
return calendars;
}
public List getFareAttributes() {
return fareAttributes;
}
public List getFareRules() {
return fareRules;
}
public List getFeedInfos() {
return feedInfos;
}
public List getFrequencies() {
return frequencies;
}
public EntityById getGroupsOfStationsById() {
return groupsOfStationsById;
}
public EntityById getMultiModalStationsById() {
return multiModalStationsById;
}
/**
* get multimap of Notices by the TransitEntity id (Multiple types; hence the Serializable). Entities
* that might have Notices are Routes, Trips, Stops and StopTimes.
*/
public Multimap, Notice> getNoticeAssignments() {
return noticeAssignments;
}
public EntityById getOperatorsById() {
return operatorsById;
}
public List getPathways() {
return pathways;
}
public EntityById getRoutes() {
return routesById;
}
public Multimap getShapePoints() {
return shapePoints;
}
public EntityById getStations() {
return stationsById;
}
public EntityById getStops() {
return stopsById;
}
public EntityById getEntrances() {
return entrancesById;
}
public EntityById getPathwayNodes() {
return pathwayNodesById;
}
public EntityById getBoardingAreas() {
return boardingAreasById;
}
public EntityById getLocations() {
return locationsById;
}
public EntityById getLocationGroups() {
return locationGroupsById;
}
public TripStopTimes getStopTimesSortedByTrip() {
return stopTimesByTrip;
}
public EntityById getFareZonesById() { return fareZonesById; }
public List getTransfers() {
return transfers;
}
public EntityById getTripsById() {
return tripsById;
}
public Multimap getTripPatterns() {
return tripPatterns;
}
public EntityById getFlexTripsById() {
return flexTripsById;
}
/**
* Find all serviceIds in both CalendarServices and CalendarServiceDates.
*/
Set findAllServiceIds() {
Set serviceIds = new HashSet<>();
for (ServiceCalendar calendar : getCalendars()) {
serviceIds.add(calendar.getServiceId());
}
for (ServiceCalendarDate date : getCalendarDates()) {
serviceIds.add(date.getServiceId());
}
return serviceIds;
}
public CalendarServiceData buildCalendarServiceData() {
return CalendarServiceDataFactoryImpl.createCalendarServiceData(
getAgenciesById().values(),
getCalendarDates(),
getCalendars()
);
}
public OtpTransitService build() {
generateNoneExistentIds(feedInfos);
return new OtpTransitServiceImpl(this);
}
/**
* Limit the transit service to a time period removing calendar dates and services
* outside the period. If a service is start before and/or ends after the period
* then the service is modified to match the period.
*/
public void limitServiceDays(ServiceDateInterval periodLimit) {
if(periodLimit.isUnbounded()) {
LOG.info("Limiting transit service is skipped, the period is unbounded.");
return;
}
LOG.warn("Limiting transit service days to time period: {}", periodLimit);
int orgSize = calendarDates.size();
calendarDates.removeIf(c -> !periodLimit.include(c.getDate()));
logRemove("ServiceCalendarDate", orgSize, calendarDates.size(), "Outside time period.");
List keepCal = new ArrayList<>();
for (ServiceCalendar calendar : calendars) {
if(calendar.getPeriod().overlap(periodLimit)) {
calendar.setPeriod(calendar.getPeriod().intersection(periodLimit));
keepCal.add(calendar);
}
}
orgSize = calendars.size();
if(orgSize != keepCal.size()) {
calendars.clear();
calendars.addAll(keepCal);
logRemove("ServiceCalendar", orgSize, calendars.size(), "Outside time period.");
}
removeEntitiesWithInvalidReferences();
LOG.info("Limiting transit service days to time period complete.");
}
/**
* Check all relations and remove entities witch reference none existing entries. This
* may happen as a result of inconsistent data or by deliberate removal of elements in the
* builder.
*/
private void removeEntitiesWithInvalidReferences() {
removeTripsWithNoneExistingServiceIds();
removeStopTimesForNoneExistingTrips();
fixOrRemovePatternsWhichReferenceNoneExistingTrips();
removeTransfersForNoneExistingTrips();
}
/** Remove all trips witch reference none existing service ids */
private void removeTripsWithNoneExistingServiceIds() {
Set serviceIds = findAllServiceIds();
int orgSize = tripsById.size();
tripsById.removeIf(t -> !serviceIds.contains(t.getServiceId()));
logRemove("Trip", orgSize, tripsById.size(), "Trip service id does not exist.");
}
/** Remove all stopTimes witch reference none existing trips */
private void removeStopTimesForNoneExistingTrips() {
int orgSize = stopTimesByTrip.size();
stopTimesByTrip.removeIf(t -> !tripsById.containsKey(t.getId()));
logRemove("StopTime", orgSize, stopTimesByTrip.size(), "StopTime trip does not exist.");
}
/** Remove none existing trips from patterns and then remove empty patterns */
private void fixOrRemovePatternsWhichReferenceNoneExistingTrips() {
int orgSize = tripPatterns.size();
List> removePatterns = new ArrayList<>();
for (Map.Entry e : tripPatterns.entries()) {
TripPattern ptn = e.getValue();
ptn.removeTrips(t -> !tripsById.containsKey(t.getId()));
if(ptn.getTrips().isEmpty()) {
removePatterns.add(e);
}
}
for (Map.Entry it : removePatterns) {
tripPatterns.remove(it.getKey(), it.getValue());
}
logRemove("TripPattern", orgSize, tripPatterns.size(), "No trips for pattern exist.");
}
/** Remove all transfers witch reference none existing trips */
private void removeTransfersForNoneExistingTrips() {
int orgSize = transfers.size();
transfers.removeIf(it -> noTripExist(it.getFromTrip()) || noTripExist(it.getToTrip()));
logRemove("Trip", orgSize, transfers.size(), "Transfer to/from trip does not exist.");
}
/** Return true if the trip is a valid reference; {@code null} or exist. */
private boolean noTripExist(Trip t) {
return t != null && !tripsById.containsKey(t.getId());
}
private static void logRemove(String type, int orgSize, int newSize, String reason) {
if(orgSize == newSize) { return; }
LOG.info("{} of {} {}(s) removed. Reason: {}", orgSize - newSize, orgSize, type, reason);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy