diff --git a/.github/workflows/smoke-tests.yml b/.github/workflows/smoke-tests.yml
index f4b2eed56f2..ff1c76ebebd 100644
--- a/.github/workflows/smoke-tests.yml
+++ b/.github/workflows/smoke-tests.yml
@@ -23,10 +23,10 @@ jobs:
sleep: 15
- name: houston
sleep: 30
- #- name: denver
- # sleep: 15
- - name: septa
+ - name: denver
sleep: 15
+ #- name: septa
+ # sleep: 15
- name: portland
# have to sleep longer since computing geofencing zones takes a while
sleep: 125
diff --git a/application/pom.xml b/application/pom.xml
index 6f97e3d17e2..62eb761213f 100644
--- a/application/pom.xml
+++ b/application/pom.xml
@@ -302,7 +302,7 @@
org.onebusawayonebusaway-gtfs
- 4.3.0
+ 5.0.0
@@ -318,9 +318,9 @@
- org.openstreetmap.osmosis
- osmosis-osm-binary
- 0.48.3
+ org.openstreetmap.pbf
+ osmpbf
+ 1.6.0
diff --git a/application/src/client/index.html b/application/src/client/index.html
index db412af9df5..d3dd8544a53 100644
--- a/application/src/client/index.html
+++ b/application/src/client/index.html
@@ -5,8 +5,8 @@
OTP Debug
-
-
+
+
diff --git a/application/src/ext/java/org/opentripplanner/ext/geocoder/LuceneIndex.java b/application/src/ext/java/org/opentripplanner/ext/geocoder/LuceneIndex.java
index f742ddb131a..50452899deb 100644
--- a/application/src/ext/java/org/opentripplanner/ext/geocoder/LuceneIndex.java
+++ b/application/src/ext/java/org/opentripplanner/ext/geocoder/LuceneIndex.java
@@ -18,7 +18,7 @@
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.codecs.Codec;
import org.apache.lucene.codecs.PostingsFormat;
-import org.apache.lucene.codecs.lucene912.Lucene912Codec;
+import org.apache.lucene.codecs.lucene101.Lucene101Codec;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.StoredField;
@@ -34,7 +34,7 @@
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.TermQuery;
-import org.apache.lucene.search.suggest.document.Completion912PostingsFormat;
+import org.apache.lucene.search.suggest.document.Completion101PostingsFormat;
import org.apache.lucene.search.suggest.document.CompletionAnalyzer;
import org.apache.lucene.search.suggest.document.ContextQuery;
import org.apache.lucene.search.suggest.document.ContextSuggestField;
@@ -203,8 +203,8 @@ private StopCluster toStopCluster(Document document) {
static IndexWriterConfig iwcWithSuggestField(Analyzer analyzer, final Set suggestFields) {
IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
- Codec filterCodec = new Lucene912Codec() {
- final PostingsFormat postingsFormat = new Completion912PostingsFormat();
+ Codec filterCodec = new Lucene101Codec() {
+ final PostingsFormat postingsFormat = new Completion101PostingsFormat();
@Override
public PostingsFormat getPostingsFormatForField(String field) {
@@ -285,7 +285,7 @@ private Stream matchingDocuments(
.stream(topDocs.scoreDocs)
.map(scoreDoc -> {
try {
- return searcher.doc(scoreDoc.doc);
+ return searcher.storedFields().document(scoreDoc.doc);
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -330,7 +330,7 @@ private Stream matchingDocuments(
.stream(topDocs.scoreDocs)
.map(scoreDoc -> {
try {
- return searcher.doc(scoreDoc.doc);
+ return searcher.storedFields().document(scoreDoc.doc);
} catch (IOException e) {
throw new RuntimeException(e);
}
diff --git a/application/src/ext/java/org/opentripplanner/ext/parkAndRideApi/ParkAndRideResource.java b/application/src/ext/java/org/opentripplanner/ext/parkAndRideApi/ParkAndRideResource.java
index 747ba0617ec..611f4d46420 100644
--- a/application/src/ext/java/org/opentripplanner/ext/parkAndRideApi/ParkAndRideResource.java
+++ b/application/src/ext/java/org/opentripplanner/ext/parkAndRideApi/ParkAndRideResource.java
@@ -42,7 +42,7 @@ public ParkAndRideResource(
// - serverContext.graphFinder(). This needs at least a comment!
// - This can be replaced with a search done with the SiteRepository
// - if we have a radius search there.
- this.graphFinder = new DirectGraphFinder(serverContext.transitService()::findRegularStops);
+ this.graphFinder = new DirectGraphFinder(serverContext.transitService()::findRegularStopsByBoundingBox);
}
/** Envelopes are in latitude, longitude format */
diff --git a/application/src/ext/java/org/opentripplanner/ext/restapi/resources/IndexAPI.java b/application/src/ext/java/org/opentripplanner/ext/restapi/resources/IndexAPI.java
index 7dbfabed156..b9c049f547e 100644
--- a/application/src/ext/java/org/opentripplanner/ext/restapi/resources/IndexAPI.java
+++ b/application/src/ext/java/org/opentripplanner/ext/restapi/resources/IndexAPI.java
@@ -200,7 +200,7 @@ public List getStopsInRadius(
radius = Math.min(radius, MAX_STOP_SEARCH_RADIUS);
- return new DirectGraphFinder(serverContext.transitService()::findRegularStops)
+ return new DirectGraphFinder(serverContext.transitService()::findRegularStopsByBoundingBox)
.findClosestStops(new Coordinate(lon, lat), radius)
.stream()
.map(it -> StopMapper.mapToApiShort(it.stop, it.distance))
@@ -221,10 +221,9 @@ public List getStopsInRadius(
new Coordinate(maxLon, maxLat)
);
- var stops = transitService().findRegularStops(envelope);
+ var stops = transitService().findRegularStopsByBoundingBox(envelope);
return stops
.stream()
- .filter(stop -> envelope.contains(stop.getCoordinate().asJtsCoordinate()))
.map(StopMapper::mapToApiShort)
.toList();
}
diff --git a/application/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/StopsLayerBuilder.java b/application/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/StopsLayerBuilder.java
index 141157f8f3e..c1e03cdefca 100644
--- a/application/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/StopsLayerBuilder.java
+++ b/application/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/StopsLayerBuilder.java
@@ -44,7 +44,7 @@ public StopsLayerBuilder(
protected List getGeometries(Envelope query) {
return transitService
- .findRegularStops(query)
+ .findRegularStopsByBoundingBox(query)
.stream()
.filter(filter)
.map(stop -> {
diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java
index c56540a73f9..fa38deeab84 100644
--- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java
+++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java
@@ -752,9 +752,8 @@ public DataFetcher> stopsByBbox() {
);
Stream stopStream = getTransitService(environment)
- .findRegularStops(envelope)
- .stream()
- .filter(stop -> envelope.contains(stop.getCoordinate().asJtsCoordinate()));
+ .findRegularStopsByBoundingBox(envelope)
+ .stream();
if (args.getGraphQLFeeds() != null) {
List feedIds = args.getGraphQLFeeds();
diff --git a/application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLSchema.java b/application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLSchema.java
index 922f9f5244b..0561ec9de85 100644
--- a/application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLSchema.java
+++ b/application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLSchema.java
@@ -3,6 +3,7 @@
import static java.lang.Boolean.TRUE;
import static java.util.Collections.emptyList;
import static org.opentripplanner.apis.transmodel.mapping.SeverityMapper.getTransmodelSeverity;
+import static org.opentripplanner.apis.transmodel.mapping.TransitIdMapper.mapIDToDomain;
import static org.opentripplanner.apis.transmodel.mapping.TransitIdMapper.mapIDsToDomainNullSafe;
import static org.opentripplanner.apis.transmodel.model.EnumTypes.FILTER_PLACE_TYPE_ENUM;
import static org.opentripplanner.apis.transmodel.model.EnumTypes.MULTI_MODAL_MODE;
@@ -115,6 +116,7 @@
import org.opentripplanner.routing.graphfinder.PlaceType;
import org.opentripplanner.service.vehiclerental.model.VehicleRentalPlace;
import org.opentripplanner.transit.api.model.FilterValues;
+import org.opentripplanner.transit.api.request.FindRegularStopsByBoundingBoxRequest;
import org.opentripplanner.transit.api.request.TripRequest;
import org.opentripplanner.transit.model.basic.TransitMode;
import org.opentripplanner.transit.model.framework.FeedScopedId;
@@ -439,10 +441,7 @@ private GraphQLSchema create() {
.build()
)
.dataFetcher(env ->
- StopPlaceType.fetchStopPlaceById(
- TransitIdMapper.mapIDToDomain(env.getArgument("id")),
- env
- )
+ StopPlaceType.fetchStopPlaceById(mapIDToDomain(env.getArgument("id")), env)
)
.build()
)
@@ -576,7 +575,7 @@ private GraphQLSchema create() {
.dataFetcher(environment ->
GqlUtil
.getTransitService(environment)
- .getStopLocation(TransitIdMapper.mapIDToDomain(environment.getArgument("id")))
+ .getStopLocation(mapIDToDomain(environment.getArgument("id")))
)
.build()
)
@@ -610,7 +609,7 @@ private GraphQLSchema create() {
}
TransitService transitService = GqlUtil.getTransitService(environment);
return ((List) environment.getArgument("ids")).stream()
- .map(id -> transitService.getStopLocation(TransitIdMapper.mapIDToDomain(id)))
+ .map(id -> transitService.getStopLocation(mapIDToDomain(id)))
.collect(Collectors.toList());
}
if (environment.getArgument("name") == null) {
@@ -661,7 +660,14 @@ private GraphQLSchema create() {
.build()
)
.argument(
- GraphQLArgument.newArgument().name("authority").type(Scalars.GraphQLString).build()
+ GraphQLArgument
+ .newArgument()
+ .name("authority")
+ .deprecate(
+ "This is the Transmodel namespace or the GTFS feedID - avoid using this. Request a new field if necessary."
+ )
+ .type(Scalars.GraphQLString)
+ .build()
)
.argument(
GraphQLArgument
@@ -669,7 +675,7 @@ private GraphQLSchema create() {
.name("filterByInUse")
.description("If true only quays with at least one visiting line are included.")
.type(Scalars.GraphQLBoolean)
- .defaultValue(Boolean.FALSE)
+ .defaultValueProgrammatic(Boolean.FALSE)
.build()
)
.dataFetcher(environment -> {
@@ -683,24 +689,19 @@ private GraphQLSchema create() {
environment.getArgument("maximumLatitude")
)
);
+
+ var authority = environment.getArgument("authority");
+ var filterInUse = environment.getArgument("filterByInUse");
+
+ FindRegularStopsByBoundingBoxRequest findRegularStopsByBoundingBoxRequest = FindRegularStopsByBoundingBoxRequest
+ .of(envelope)
+ .withFeedId(authority)
+ .filterByInUse(filterInUse)
+ .build();
+
return GqlUtil
.getTransitService(environment)
- .findRegularStops(envelope)
- .stream()
- .filter(stop -> envelope.contains(stop.getCoordinate().asJtsCoordinate()))
- .filter(stop ->
- environment.getArgument("authority") == null ||
- stop.getId().getFeedId().equalsIgnoreCase(environment.getArgument("authority"))
- )
- .filter(stop -> {
- boolean filterByInUse = TRUE.equals(environment.getArgument("filterByInUse"));
- boolean inUse = !GqlUtil
- .getTransitService(environment)
- .findPatterns(stop, true)
- .isEmpty();
- return !filterByInUse || inUse;
- })
- .collect(Collectors.toList());
+ .findRegularStopsByBoundingBox(findRegularStopsByBoundingBoxRequest);
})
.build()
)
@@ -1438,7 +1439,7 @@ private GraphQLSchema create() {
.build()
)
.dataFetcher(environment -> {
- var bikeParkId = TransitIdMapper.mapIDToDomain(environment.getArgument("id"));
+ var bikeParkId = mapIDToDomain(environment.getArgument("id"));
return GqlUtil
.getVehicleParkingService(environment)
.listBikeParks()
@@ -1573,7 +1574,7 @@ private GraphQLSchema create() {
return GqlUtil
.getTransitService(environment)
.getTransitAlertService()
- .getAlertById(TransitIdMapper.mapIDToDomain(situationNumber));
+ .getAlertById(mapIDToDomain(situationNumber));
})
.build()
)
diff --git a/application/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopPlaceType.java b/application/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopPlaceType.java
index fa755e8c6f7..9b8fd25c68a 100644
--- a/application/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopPlaceType.java
+++ b/application/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopPlaceType.java
@@ -546,9 +546,8 @@ public static Collection fetchStopPlaces(
);
Stream stations = transitService
- .findRegularStops(envelope)
+ .findRegularStopsByBoundingBox(envelope)
.stream()
- .filter(stop -> envelope.contains(stop.getCoordinate().asJtsCoordinate()))
.map(StopLocation::getParentStation)
.filter(Objects::nonNull)
.distinct();
diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java
index 0576e91f312..0336a57c5de 100644
--- a/application/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java
+++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java
@@ -183,7 +183,7 @@ private static LayerBuilder> createLayerBuilder(
case RegularStop -> new StopLayerBuilder<>(
layerParameters,
locale,
- e -> context.transitService().findRegularStops(e)
+ e -> context.transitService().findRegularStopsByBoundingBox(e)
);
case AreaStop -> new StopLayerBuilder<>(
layerParameters,
diff --git a/application/src/main/java/org/opentripplanner/framework/application/OTPFeature.java b/application/src/main/java/org/opentripplanner/framework/application/OTPFeature.java
index f71283b572e..6e13b05a7e6 100644
--- a/application/src/main/java/org/opentripplanner/framework/application/OTPFeature.java
+++ b/application/src/main/java/org/opentripplanner/framework/application/OTPFeature.java
@@ -92,6 +92,12 @@ public enum OTPFeature {
false,
"Whether the @async annotation in the GraphQL schema should lead to the fetch being executed asynchronously. This allows batch or alias queries to run in parallel at the cost of consuming extra threads."
),
+ WaitForGraphUpdateInPollingUpdaters(
+ true,
+ false,
+ "Make all polling updaters wait for graph updates to complete before finishing. " +
+ "If this is not enabled, the updaters will finish after submitting the task to update the graph."
+ ),
Co2Emissions(false, true, "Enable the emissions sandbox module."),
DataOverlay(
false,
diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/StraightLineNearbyStopFinder.java b/application/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/StraightLineNearbyStopFinder.java
index 5b304d0d20c..ccdcb68446b 100644
--- a/application/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/StraightLineNearbyStopFinder.java
+++ b/application/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/StraightLineNearbyStopFinder.java
@@ -22,7 +22,7 @@ public StraightLineNearbyStopFinder(TransitService transitService, Duration dura
// We need to accommodate straight line distance (in meters) but when streets are present we
// use an earliest arrival search, which optimizes on time. Ideally we'd specify in meters,
// but we don't have much of a choice here. Use the default walking speed to convert.
- this.directGraphFinder = new DirectGraphFinder(transitService::findRegularStops);
+ this.directGraphFinder = new DirectGraphFinder(transitService::findRegularStopsByBoundingBox);
}
/**
diff --git a/application/src/main/java/org/opentripplanner/gtfs/graphbuilder/GtfsModule.java b/application/src/main/java/org/opentripplanner/gtfs/graphbuilder/GtfsModule.java
index a5fe3641e3c..3548312b79a 100644
--- a/application/src/main/java/org/opentripplanner/gtfs/graphbuilder/GtfsModule.java
+++ b/application/src/main/java/org/opentripplanner/gtfs/graphbuilder/GtfsModule.java
@@ -14,6 +14,7 @@
import org.onebusaway.csv_entities.EntityHandler;
import org.onebusaway.gtfs.impl.GtfsRelationalDaoImpl;
import org.onebusaway.gtfs.model.Agency;
+import org.onebusaway.gtfs.model.Area;
import org.onebusaway.gtfs.model.FareAttribute;
import org.onebusaway.gtfs.model.FareLegRule;
import org.onebusaway.gtfs.model.FareMedium;
@@ -27,7 +28,7 @@
import org.onebusaway.gtfs.model.ServiceCalendarDate;
import org.onebusaway.gtfs.model.ShapePoint;
import org.onebusaway.gtfs.model.Stop;
-import org.onebusaway.gtfs.model.StopArea;
+import org.onebusaway.gtfs.model.StopAreaElement;
import org.onebusaway.gtfs.model.Trip;
import org.onebusaway.gtfs.serialization.GtfsReader;
import org.onebusaway.gtfs.services.GenericMutableDao;
@@ -66,7 +67,8 @@ public class GtfsModule implements GraphBuilderModule {
FareTransferRule.class,
RiderCategory.class,
FareMedium.class,
- StopArea.class
+ StopAreaElement.class,
+ Area.class
);
private static final Logger LOG = LoggerFactory.getLogger(GtfsModule.class);
diff --git a/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java
index 55e4bccfdec..ab912eae85b 100644
--- a/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java
+++ b/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java
@@ -98,6 +98,7 @@ protected ScheduledTransitLeg(ScheduledTransitLegBuilder> builder) {
getDistanceFromCoordinates(
List.of(transitLegCoordinates.getFirst(), transitLegCoordinates.getLast())
);
+ this.transitAlerts.addAll(builder.alerts());
}
public ZoneId getZoneId() {
diff --git a/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLegBuilder.java b/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLegBuilder.java
index 3e9b5540b1c..e132137e982 100644
--- a/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLegBuilder.java
+++ b/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLegBuilder.java
@@ -3,7 +3,10 @@
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
+import java.util.HashSet;
+import java.util.Set;
import org.opentripplanner.model.transfer.ConstrainedTransfer;
+import org.opentripplanner.routing.alertpatch.TransitAlert;
import org.opentripplanner.transit.model.network.TripPattern;
import org.opentripplanner.transit.model.timetable.TripOnServiceDate;
import org.opentripplanner.transit.model.timetable.TripTimes;
@@ -23,6 +26,7 @@ public class ScheduledTransitLegBuilder>
private ConstrainedTransfer transferToNextLeg;
private int generalizedCost;
private Float accessibilityScore;
+ private Set alerts = new HashSet<>();
public ScheduledTransitLegBuilder() {}
@@ -40,6 +44,7 @@ public ScheduledTransitLegBuilder(ScheduledTransitLeg original) {
generalizedCost = original.getGeneralizedCost();
accessibilityScore = original.accessibilityScore();
zoneId = original.getZoneId();
+ alerts = original.getTransitAlerts();
}
public B withTripTimes(TripTimes tripTimes) {
@@ -159,6 +164,10 @@ public Float accessibilityScore() {
return accessibilityScore;
}
+ public Set alerts() {
+ return alerts;
+ }
+
public ScheduledTransitLeg build() {
return new ScheduledTransitLeg(this);
}
diff --git a/application/src/main/java/org/opentripplanner/osm/OsmParser.java b/application/src/main/java/org/opentripplanner/osm/OsmParser.java
index 8a5f8e32448..4b443e6a505 100644
--- a/application/src/main/java/org/opentripplanner/osm/OsmParser.java
+++ b/application/src/main/java/org/opentripplanner/osm/OsmParser.java
@@ -1,11 +1,11 @@
package org.opentripplanner.osm;
+import crosby.binary.BinaryParser;
+import crosby.binary.Osmformat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import org.openstreetmap.osmosis.osmbinary.BinaryParser;
-import org.openstreetmap.osmosis.osmbinary.Osmformat;
import org.opentripplanner.graph_builder.module.osm.OsmDatabase;
import org.opentripplanner.osm.model.OsmMemberType;
import org.opentripplanner.osm.model.OsmNode;
diff --git a/application/src/main/java/org/opentripplanner/osm/OsmProvider.java b/application/src/main/java/org/opentripplanner/osm/OsmProvider.java
index 597fd516b0e..91944a95b86 100644
--- a/application/src/main/java/org/opentripplanner/osm/OsmProvider.java
+++ b/application/src/main/java/org/opentripplanner/osm/OsmProvider.java
@@ -1,11 +1,11 @@
package org.opentripplanner.osm;
+import crosby.binary.file.BlockInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.time.ZoneId;
-import org.openstreetmap.osmosis.osmbinary.file.BlockInputStream;
import org.opentripplanner.datastore.api.DataSource;
import org.opentripplanner.datastore.api.FileType;
import org.opentripplanner.datastore.file.FileDataSource;
diff --git a/application/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java b/application/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java
index f088a3de60e..139bac6dcc9 100644
--- a/application/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java
+++ b/application/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java
@@ -121,7 +121,7 @@ public interface OtpServerRequestContext {
TraverseVisitor traverseVisitor();
default GraphFinder graphFinder() {
- return GraphFinder.getInstance(graph(), transitService()::findRegularStops);
+ return GraphFinder.getInstance(graph(), transitService()::findRegularStopsByBoundingBox);
}
FlexParameters flexParameters();
diff --git a/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/UpdatersConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/UpdatersConfig.java
index ac69b43e275..a71d5ee40f8 100644
--- a/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/UpdatersConfig.java
+++ b/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/UpdatersConfig.java
@@ -8,7 +8,9 @@
import static org.opentripplanner.standalone.config.routerconfig.UpdatersConfig.Type.SIRI_AZURE_ET_UPDATER;
import static org.opentripplanner.standalone.config.routerconfig.UpdatersConfig.Type.SIRI_AZURE_SX_UPDATER;
import static org.opentripplanner.standalone.config.routerconfig.UpdatersConfig.Type.SIRI_ET_GOOGLE_PUBSUB_UPDATER;
+import static org.opentripplanner.standalone.config.routerconfig.UpdatersConfig.Type.SIRI_ET_LITE;
import static org.opentripplanner.standalone.config.routerconfig.UpdatersConfig.Type.SIRI_ET_UPDATER;
+import static org.opentripplanner.standalone.config.routerconfig.UpdatersConfig.Type.SIRI_SX_LITE;
import static org.opentripplanner.standalone.config.routerconfig.UpdatersConfig.Type.SIRI_SX_UPDATER;
import static org.opentripplanner.standalone.config.routerconfig.UpdatersConfig.Type.STOP_TIME_UPDATER;
import static org.opentripplanner.standalone.config.routerconfig.UpdatersConfig.Type.VEHICLE_PARKING;
@@ -30,7 +32,9 @@
import org.opentripplanner.standalone.config.routerconfig.updaters.MqttGtfsRealtimeUpdaterConfig;
import org.opentripplanner.standalone.config.routerconfig.updaters.PollingTripUpdaterConfig;
import org.opentripplanner.standalone.config.routerconfig.updaters.SiriETGooglePubsubUpdaterConfig;
+import org.opentripplanner.standalone.config.routerconfig.updaters.SiriETLiteUpdaterConfig;
import org.opentripplanner.standalone.config.routerconfig.updaters.SiriETUpdaterConfig;
+import org.opentripplanner.standalone.config.routerconfig.updaters.SiriSXLiteUpdaterConfig;
import org.opentripplanner.standalone.config.routerconfig.updaters.SiriSXUpdaterConfig;
import org.opentripplanner.standalone.config.routerconfig.updaters.VehicleParkingUpdaterConfig;
import org.opentripplanner.standalone.config.routerconfig.updaters.VehiclePositionsUpdaterConfig;
@@ -44,6 +48,8 @@
import org.opentripplanner.updater.siri.updater.SiriETUpdaterParameters;
import org.opentripplanner.updater.siri.updater.SiriSXUpdaterParameters;
import org.opentripplanner.updater.siri.updater.google.SiriETGooglePubsubUpdaterParameters;
+import org.opentripplanner.updater.siri.updater.lite.SiriETLiteUpdaterParameters;
+import org.opentripplanner.updater.siri.updater.lite.SiriSXLiteUpdaterParameters;
import org.opentripplanner.updater.trip.MqttGtfsRealtimeUpdaterParameters;
import org.opentripplanner.updater.trip.PollingTripUpdaterParameters;
import org.opentripplanner.updater.vehicle_parking.VehicleParkingUpdaterParameters;
@@ -182,6 +188,16 @@ public List getSiriSXUpdaterParameters() {
return getParameters(SIRI_SX_UPDATER);
}
+ @Override
+ public List getSiriETLiteUpdaterParameters() {
+ return getParameters(SIRI_ET_LITE);
+ }
+
+ @Override
+ public List getSiriSXLiteUpdaterParameters() {
+ return getParameters(SIRI_SX_LITE);
+ }
+
@Override
public List getMqttGtfsRealtimeUpdaterParameters() {
return getParameters(MQTT_GTFS_RT_UPDATER);
@@ -218,8 +234,10 @@ public enum Type {
REAL_TIME_ALERTS(GtfsRealtimeAlertsUpdaterConfig::create),
VEHICLE_POSITIONS(VehiclePositionsUpdaterConfig::create),
SIRI_ET_UPDATER(SiriETUpdaterConfig::create),
+ SIRI_ET_LITE(SiriETLiteUpdaterConfig::create),
SIRI_ET_GOOGLE_PUBSUB_UPDATER(SiriETGooglePubsubUpdaterConfig::create),
SIRI_SX_UPDATER(SiriSXUpdaterConfig::create),
+ SIRI_SX_LITE(SiriSXLiteUpdaterConfig::create),
SIRI_AZURE_ET_UPDATER(SiriAzureETUpdaterConfig::create),
SIRI_AZURE_SX_UPDATER(SiriAzureSXUpdaterConfig::create);
diff --git a/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/SiriETLiteUpdaterConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/SiriETLiteUpdaterConfig.java
new file mode 100644
index 00000000000..b26bdd2a727
--- /dev/null
+++ b/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/SiriETLiteUpdaterConfig.java
@@ -0,0 +1,39 @@
+package org.opentripplanner.standalone.config.routerconfig.updaters;
+
+import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_7;
+
+import java.time.Duration;
+import org.opentripplanner.standalone.config.framework.json.NodeAdapter;
+import org.opentripplanner.updater.siri.updater.lite.SiriETLiteUpdaterParameters;
+
+public class SiriETLiteUpdaterConfig {
+
+ public static SiriETLiteUpdaterParameters create(String configRef, NodeAdapter c) {
+ return new SiriETLiteUpdaterParameters(
+ configRef,
+ c.of("feedId").since(V2_7).summary("The ID of the feed to apply the updates to.").asString(),
+ c
+ .of("url")
+ .since(V2_7)
+ .summary("The URL to send the HTTP requests to.")
+ .description(SiriSXUpdaterConfig.URL_DESCRIPTION)
+ .asUri(),
+ c
+ .of("frequency")
+ .since(V2_7)
+ .summary("How often the updates should be retrieved.")
+ .asDuration(Duration.ofMinutes(1)),
+ c
+ .of("timeout")
+ .since(V2_7)
+ .summary("The HTTP timeout to download the updates.")
+ .asDuration(Duration.ofSeconds(15)),
+ c
+ .of("fuzzyTripMatching")
+ .since(V2_7)
+ .summary("If the fuzzy trip matcher should be used to match trips.")
+ .asBoolean(false),
+ HttpHeadersConfig.headers(c, V2_7)
+ );
+ }
+}
diff --git a/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/SiriSXLiteUpdaterConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/SiriSXLiteUpdaterConfig.java
new file mode 100644
index 00000000000..27c1bcba0be
--- /dev/null
+++ b/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/SiriSXLiteUpdaterConfig.java
@@ -0,0 +1,46 @@
+package org.opentripplanner.standalone.config.routerconfig.updaters;
+
+import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_0;
+import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_7;
+
+import java.time.Duration;
+import org.opentripplanner.standalone.config.framework.json.NodeAdapter;
+import org.opentripplanner.updater.siri.updater.lite.SiriSXLiteUpdaterParameters;
+
+public class SiriSXLiteUpdaterConfig {
+
+ public static SiriSXLiteUpdaterParameters create(String configRef, NodeAdapter c) {
+ return new SiriSXLiteUpdaterParameters(
+ configRef,
+ c.of("feedId").since(V2_7).summary("The ID of the feed to apply the updates to.").asString(),
+ c
+ .of("url")
+ .since(V2_7)
+ .summary("The URL to send the HTTP requests to.")
+ .description(SiriSXUpdaterConfig.URL_DESCRIPTION)
+ .asUri(),
+ c
+ .of("frequency")
+ .since(V2_7)
+ .summary("How often the updates should be retrieved.")
+ .asDuration(Duration.ofMinutes(1)),
+ c
+ .of("timeout")
+ .since(V2_7)
+ .summary("The HTTP timeout to download the updates.")
+ .asDuration(Duration.ofSeconds(15)),
+ c
+ .of("earlyStart")
+ .since(V2_0)
+ .summary("This value is subtracted from the actual validity defined in the message.")
+ .description(
+ """
+ Normally the planned departure time is used, so setting this to 10s will cause the
+ SX-message to be included in trip-results 10 seconds before the the planned departure
+ time."""
+ )
+ .asDuration(Duration.ZERO),
+ HttpHeadersConfig.headers(c, V2_7)
+ );
+ }
+}
diff --git a/application/src/main/java/org/opentripplanner/transit/api/model/FilterValues.java b/application/src/main/java/org/opentripplanner/transit/api/model/FilterValues.java
index 391b2531231..63befe3add6 100644
--- a/application/src/main/java/org/opentripplanner/transit/api/model/FilterValues.java
+++ b/application/src/main/java/org/opentripplanner/transit/api/model/FilterValues.java
@@ -1,8 +1,8 @@
package org.opentripplanner.transit.api.model;
-import com.beust.jcommander.internal.Nullable;
import java.util.Collection;
import java.util.NoSuchElementException;
+import javax.annotation.Nullable;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.transit.service.TransitService;
diff --git a/application/src/main/java/org/opentripplanner/transit/api/request/FindRegularStopsByBoundingBoxRequest.java b/application/src/main/java/org/opentripplanner/transit/api/request/FindRegularStopsByBoundingBoxRequest.java
new file mode 100644
index 00000000000..476e23d7cd8
--- /dev/null
+++ b/application/src/main/java/org/opentripplanner/transit/api/request/FindRegularStopsByBoundingBoxRequest.java
@@ -0,0 +1,48 @@
+package org.opentripplanner.transit.api.request;
+
+import javax.annotation.Nullable;
+import org.locationtech.jts.geom.Envelope;
+import org.opentripplanner.transit.model.site.RegularStop;
+
+/**
+ * A request for {@link RegularStop}s within a bounding box.
+ *
+ * This request is used to retrieve {@link RegularStop}s that are within a provided bounding box and
+ * match the other criteria.
+ */
+public class FindRegularStopsByBoundingBoxRequest {
+
+ private final Envelope envelope;
+
+ @Nullable
+ private final String feedId;
+
+ private final boolean filterByInUse;
+
+ FindRegularStopsByBoundingBoxRequest(
+ Envelope envelope,
+ @Nullable String feedId,
+ boolean filterByInUse
+ ) {
+ this.envelope = envelope;
+ this.feedId = feedId;
+ this.filterByInUse = filterByInUse;
+ }
+
+ public static FindRegularStopsByBoundingBoxRequestBuilder of(Envelope envelope) {
+ return new FindRegularStopsByBoundingBoxRequestBuilder(envelope);
+ }
+
+ public Envelope envelope() {
+ return envelope;
+ }
+
+ @Nullable
+ public String feedId() {
+ return feedId;
+ }
+
+ public boolean filterByInUse() {
+ return filterByInUse;
+ }
+}
diff --git a/application/src/main/java/org/opentripplanner/transit/api/request/FindRegularStopsByBoundingBoxRequestBuilder.java b/application/src/main/java/org/opentripplanner/transit/api/request/FindRegularStopsByBoundingBoxRequestBuilder.java
new file mode 100644
index 00000000000..49d31c33db9
--- /dev/null
+++ b/application/src/main/java/org/opentripplanner/transit/api/request/FindRegularStopsByBoundingBoxRequestBuilder.java
@@ -0,0 +1,32 @@
+package org.opentripplanner.transit.api.request;
+
+import javax.annotation.Nullable;
+import org.locationtech.jts.geom.Envelope;
+
+public class FindRegularStopsByBoundingBoxRequestBuilder {
+
+ private final Envelope envelope;
+
+ @Nullable
+ private String feedId;
+
+ private boolean filterByInUse = false;
+
+ FindRegularStopsByBoundingBoxRequestBuilder(Envelope envelope) {
+ this.envelope = envelope;
+ }
+
+ public FindRegularStopsByBoundingBoxRequestBuilder withFeedId(@Nullable String feedId) {
+ this.feedId = feedId;
+ return this;
+ }
+
+ public FindRegularStopsByBoundingBoxRequestBuilder filterByInUse(boolean filterByInUse) {
+ this.filterByInUse = filterByInUse;
+ return this;
+ }
+
+ public FindRegularStopsByBoundingBoxRequest build() {
+ return new FindRegularStopsByBoundingBoxRequest(envelope, feedId, filterByInUse);
+ }
+}
diff --git a/application/src/main/java/org/opentripplanner/transit/api/request/TripOnServiceDateRequest.java b/application/src/main/java/org/opentripplanner/transit/api/request/TripOnServiceDateRequest.java
index c61bb8ad107..54dd1c7aea6 100644
--- a/application/src/main/java/org/opentripplanner/transit/api/request/TripOnServiceDateRequest.java
+++ b/application/src/main/java/org/opentripplanner/transit/api/request/TripOnServiceDateRequest.java
@@ -23,7 +23,7 @@ public class TripOnServiceDateRequest {
private final FilterValues netexInternalPlanningCodes;
private final FilterValues alterations;
- protected TripOnServiceDateRequest(
+ TripOnServiceDateRequest(
RequiredFilterValues serviceDates,
FilterValues agencies,
FilterValues routes,
@@ -41,7 +41,7 @@ protected TripOnServiceDateRequest(
this.alterations = alterations;
}
- public static TripOnServiceDateRequestBuilder of(RequiredFilterValues serviceDates) {
+ public static TripOnServiceDateRequestBuilder of(RequiredFilterValues serviceDates) {
return new TripOnServiceDateRequestBuilder(serviceDates);
}
diff --git a/application/src/main/java/org/opentripplanner/transit/api/request/TripOnServiceDateRequestBuilder.java b/application/src/main/java/org/opentripplanner/transit/api/request/TripOnServiceDateRequestBuilder.java
index 534557c15d8..3181819a400 100644
--- a/application/src/main/java/org/opentripplanner/transit/api/request/TripOnServiceDateRequestBuilder.java
+++ b/application/src/main/java/org/opentripplanner/transit/api/request/TripOnServiceDateRequestBuilder.java
@@ -30,9 +30,9 @@ public class TripOnServiceDateRequestBuilder {
"alterations",
List.of()
);
- private RequiredFilterValues serviceDates;
+ private final RequiredFilterValues serviceDates;
- protected TripOnServiceDateRequestBuilder(RequiredFilterValues serviceDates) {
+ TripOnServiceDateRequestBuilder(RequiredFilterValues serviceDates) {
this.serviceDates = serviceDates;
}
diff --git a/application/src/main/java/org/opentripplanner/transit/api/request/TripRequest.java b/application/src/main/java/org/opentripplanner/transit/api/request/TripRequest.java
index c73e800582b..5e05b472937 100644
--- a/application/src/main/java/org/opentripplanner/transit/api/request/TripRequest.java
+++ b/application/src/main/java/org/opentripplanner/transit/api/request/TripRequest.java
@@ -17,7 +17,7 @@ public class TripRequest {
private final FilterValues netexInternalPlanningCodes;
private final FilterValues serviceDates;
- protected TripRequest(
+ TripRequest(
FilterValues agencies,
FilterValues routes,
FilterValues netexInternalPlanningCodes,
diff --git a/application/src/main/java/org/opentripplanner/transit/api/request/TripRequestBuilder.java b/application/src/main/java/org/opentripplanner/transit/api/request/TripRequestBuilder.java
index 3a2f80a3e34..32ca31d5cd6 100644
--- a/application/src/main/java/org/opentripplanner/transit/api/request/TripRequestBuilder.java
+++ b/application/src/main/java/org/opentripplanner/transit/api/request/TripRequestBuilder.java
@@ -21,7 +21,7 @@ public class TripRequestBuilder {
List.of()
);
- protected TripRequestBuilder() {}
+ TripRequestBuilder() {}
public TripRequestBuilder withAgencies(FilterValues agencies) {
this.agencies = agencies;
diff --git a/application/src/main/java/org/opentripplanner/transit/model/filter/expr/ExpressionBuilder.java b/application/src/main/java/org/opentripplanner/transit/model/filter/expr/ExpressionBuilder.java
index f2910a4c8d2..87533ab1b5e 100644
--- a/application/src/main/java/org/opentripplanner/transit/model/filter/expr/ExpressionBuilder.java
+++ b/application/src/main/java/org/opentripplanner/transit/model/filter/expr/ExpressionBuilder.java
@@ -22,6 +22,11 @@ public static ExpressionBuilder of() {
return new ExpressionBuilder<>();
}
+ public ExpressionBuilder matches(Matcher matcher) {
+ matchers.add(matcher);
+ return this;
+ }
+
public ExpressionBuilder atLeastOneMatch(
FilterValues filterValues,
Function> matcherProvider
diff --git a/application/src/main/java/org/opentripplanner/transit/model/filter/expr/GenericUnaryMatcher.java b/application/src/main/java/org/opentripplanner/transit/model/filter/expr/GenericUnaryMatcher.java
new file mode 100644
index 00000000000..0ac6c5f17ee
--- /dev/null
+++ b/application/src/main/java/org/opentripplanner/transit/model/filter/expr/GenericUnaryMatcher.java
@@ -0,0 +1,33 @@
+package org.opentripplanner.transit.model.filter.expr;
+
+import java.util.function.Predicate;
+
+/**
+ * A generic matcher that takes a predicate function that returns a boolean given the matched type.
+ *
+ * @param The type of the entity being matched.
+ */
+public class GenericUnaryMatcher implements Matcher {
+
+ private final String typeName;
+ private final Predicate matchPredicate;
+
+ /**
+ * @param typeName The typeName appears in the toString for easier debugging.
+ * @param matchPredicate The predicate that will be used to test the entity being matched.
+ */
+ public GenericUnaryMatcher(String typeName, Predicate matchPredicate) {
+ this.typeName = typeName;
+ this.matchPredicate = matchPredicate;
+ }
+
+ @Override
+ public boolean match(T entity) {
+ return matchPredicate.test(entity);
+ }
+
+ @Override
+ public String toString() {
+ return "GenericUnaryMatcher: " + typeName;
+ }
+}
diff --git a/application/src/main/java/org/opentripplanner/transit/model/filter/transit/RegularStopMatcherFactory.java b/application/src/main/java/org/opentripplanner/transit/model/filter/transit/RegularStopMatcherFactory.java
new file mode 100644
index 00000000000..261e7057d95
--- /dev/null
+++ b/application/src/main/java/org/opentripplanner/transit/model/filter/transit/RegularStopMatcherFactory.java
@@ -0,0 +1,47 @@
+package org.opentripplanner.transit.model.filter.transit;
+
+import java.util.function.Predicate;
+import org.opentripplanner.transit.api.request.FindRegularStopsByBoundingBoxRequest;
+import org.opentripplanner.transit.model.filter.expr.EqualityMatcher;
+import org.opentripplanner.transit.model.filter.expr.ExpressionBuilder;
+import org.opentripplanner.transit.model.filter.expr.GenericUnaryMatcher;
+import org.opentripplanner.transit.model.filter.expr.Matcher;
+import org.opentripplanner.transit.model.site.RegularStop;
+
+/**
+ * A factory for creating matchers for {@link RegularStop} objects.
+ *
+ * This factory is used to create matchers for {@link RegularStop} objects based on a request. The
+ * resulting matcher can be used to filter a list of {@link RegularStop} objects.
+ */
+public class RegularStopMatcherFactory {
+
+ /**
+ * Creates a matcher that filters {@link RegularStop} objects with the provided {@code request}
+ * and {@code inUseProvider}. The {@code inUseProvider} is used to determine if a {@link RegularStop} is
+ * in use. The inUseProvider is an injected function, because the check is done by the transit service
+ * which has access to all stops and routes. A stop is used if it has routes visiting the stop.
+ */
+ public static Matcher of(
+ FindRegularStopsByBoundingBoxRequest request,
+ Predicate inUseProvider
+ ) {
+ ExpressionBuilder expr = ExpressionBuilder.of();
+
+ if (request.feedId() != null) {
+ expr.matches(feedId(request.feedId()));
+ }
+ if (request.filterByInUse()) {
+ expr.matches(inUseMatcher(inUseProvider));
+ }
+ return expr.build();
+ }
+
+ static Matcher feedId(String feedId) {
+ return new EqualityMatcher<>("feedId", feedId, stop -> stop.getId().getFeedId());
+ }
+
+ static Matcher inUseMatcher(Predicate inUseProvider) {
+ return new GenericUnaryMatcher<>("inUse", inUseProvider);
+ }
+}
diff --git a/application/src/main/java/org/opentripplanner/transit/model/timetable/OccupancyStatus.java b/application/src/main/java/org/opentripplanner/transit/model/timetable/OccupancyStatus.java
index 9c32ca39394..fe760747ef4 100644
--- a/application/src/main/java/org/opentripplanner/transit/model/timetable/OccupancyStatus.java
+++ b/application/src/main/java/org/opentripplanner/transit/model/timetable/OccupancyStatus.java
@@ -9,7 +9,7 @@
*
* Descriptions are copied from the GTFS-RT specification with additions of SIRI nordic profile documentation.
*/
-public enum OccupancyStatus implements DocumentedEnum {
+public enum OccupancyStatus implements DocumentedEnum {
NO_DATA_AVAILABLE,
EMPTY,
MANY_SEATS_AVAILABLE,
diff --git a/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java b/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java
index cf5bb11c3b3..d27fe138ef4 100644
--- a/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java
+++ b/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java
@@ -35,11 +35,13 @@
import org.opentripplanner.routing.services.TransitAlertService;
import org.opentripplanner.routing.stoptimes.ArrivalDeparture;
import org.opentripplanner.routing.stoptimes.StopTimesHelper;
+import org.opentripplanner.transit.api.request.FindRegularStopsByBoundingBoxRequest;
import org.opentripplanner.transit.api.request.TripOnServiceDateRequest;
import org.opentripplanner.transit.api.request.TripRequest;
import org.opentripplanner.transit.model.basic.Notice;
import org.opentripplanner.transit.model.basic.TransitMode;
import org.opentripplanner.transit.model.filter.expr.Matcher;
+import org.opentripplanner.transit.model.filter.transit.RegularStopMatcherFactory;
import org.opentripplanner.transit.model.filter.transit.TripMatcherFactory;
import org.opentripplanner.transit.model.filter.transit.TripOnServiceDateMatcherFactory;
import org.opentripplanner.transit.model.framework.AbstractTransitEntity;
@@ -698,11 +700,27 @@ public ZonedDateTime getTransitServiceStarts() {
}
@Override
- public Collection findRegularStops(Envelope envelope) {
+ public Collection findRegularStopsByBoundingBox(Envelope envelope) {
OTPRequestTimeoutException.checkForTimeout();
return timetableRepository.getSiteRepository().findRegularStops(envelope);
}
+ @Override
+ public Collection findRegularStopsByBoundingBox(
+ FindRegularStopsByBoundingBoxRequest request
+ ) {
+ OTPRequestTimeoutException.checkForTimeout();
+ Collection stops = timetableRepository
+ .getSiteRepository()
+ .findRegularStops(request.envelope());
+
+ Matcher matcher = RegularStopMatcherFactory.of(
+ request,
+ stop -> !findPatterns(stop, true).isEmpty()
+ );
+ return stops.stream().filter(matcher::match).toList();
+ }
+
@Override
public Collection findAreaStops(Envelope envelope) {
OTPRequestTimeoutException.checkForTimeout();
diff --git a/application/src/main/java/org/opentripplanner/transit/service/StopModelIndex.java b/application/src/main/java/org/opentripplanner/transit/service/StopModelIndex.java
index 13a8c0d278d..effa8f95f7e 100644
--- a/application/src/main/java/org/opentripplanner/transit/service/StopModelIndex.java
+++ b/application/src/main/java/org/opentripplanner/transit/service/StopModelIndex.java
@@ -71,10 +71,17 @@ class SiteRepositoryIndex {
}
/**
- * Find a regular stop in the spatial index
+ * Find a regular stop in the spatial index, where the stop is inside of the passed Envelope.
+ *
+ * @param envelope - The {@link Envelope} to search for stops in.
+ * @return A collection of {@link RegularStop}s that are inside of the passed envelope.
*/
Collection findRegularStops(Envelope envelope) {
- return regularStopSpatialIndex.query(envelope);
+ return regularStopSpatialIndex
+ .query(envelope)
+ .stream()
+ .filter(stop -> envelope.contains(stop.getCoordinate().asJtsCoordinate()))
+ .toList();
}
MultiModalStation getMultiModalStationForStation(Station station) {
diff --git a/application/src/main/java/org/opentripplanner/transit/service/TransitService.java b/application/src/main/java/org/opentripplanner/transit/service/TransitService.java
index 11a628508d6..6e005b355d1 100644
--- a/application/src/main/java/org/opentripplanner/transit/service/TransitService.java
+++ b/application/src/main/java/org/opentripplanner/transit/service/TransitService.java
@@ -24,6 +24,7 @@
import org.opentripplanner.routing.algorithm.raptoradapter.transit.TransitLayer;
import org.opentripplanner.routing.services.TransitAlertService;
import org.opentripplanner.routing.stoptimes.ArrivalDeparture;
+import org.opentripplanner.transit.api.request.FindRegularStopsByBoundingBoxRequest;
import org.opentripplanner.transit.api.request.TripOnServiceDateRequest;
import org.opentripplanner.transit.api.request.TripRequest;
import org.opentripplanner.transit.model.basic.Notice;
@@ -271,7 +272,7 @@ List findTripTimeOnDate(
boolean transitFeedCovers(Instant dateTime);
- Collection findRegularStops(Envelope envelope);
+ Collection findRegularStopsByBoundingBox(Envelope envelope);
Collection findAreaStops(Envelope envelope);
@@ -287,6 +288,7 @@ List findTripTimeOnDate(
* So, if more patterns of mode BUS than RAIL visit the group, the result will be [BUS,RAIL].
*/
List findTransitModes(StopLocationsGroup station);
+
/**
* For a {@link StopLocation} return its modes.
*
@@ -307,18 +309,13 @@ List findTripTimeOnDate(
Map getServiceCodesRunningForDate();
/**
- * Returns a list of TripOnServiceDates that match the filtering defined in the request.
- *
- * @param request - A TripOnServiceDateRequest object with filtering defined.
- * @return - A list of TripOnServiceDates
+ * Returns a list of {@link TripOnServiceDate}s that match the filtering defined in the request.
*/
List findTripsOnServiceDate(TripOnServiceDateRequest request);
/**
- * Returns a list of Trips that match the filtering defined in the request.
+ * Returns a list of {@link Trip}s that match the filtering defined in the request.
*
- * @param request - A TripRequest object with filtering defined.
- * @return - A list of Trips
*/
List getTrips(TripRequest request);
@@ -329,4 +326,12 @@ List findTripTimeOnDate(
* @return true if the trip exists, false otherwise
*/
boolean containsTrip(FeedScopedId id);
+
+ /**
+ * Returns a list of {@link RegularStop}s that lay within a bounding box and match the other criteria
+ * in the request object.
+ */
+ Collection findRegularStopsByBoundingBox(
+ FindRegularStopsByBoundingBoxRequest request
+ );
}
diff --git a/application/src/main/java/org/opentripplanner/updater/UpdatersParameters.java b/application/src/main/java/org/opentripplanner/updater/UpdatersParameters.java
index 312fa3e2fbc..cb613580495 100644
--- a/application/src/main/java/org/opentripplanner/updater/UpdatersParameters.java
+++ b/application/src/main/java/org/opentripplanner/updater/UpdatersParameters.java
@@ -8,6 +8,8 @@
import org.opentripplanner.updater.siri.updater.SiriETUpdaterParameters;
import org.opentripplanner.updater.siri.updater.SiriSXUpdaterParameters;
import org.opentripplanner.updater.siri.updater.google.SiriETGooglePubsubUpdaterParameters;
+import org.opentripplanner.updater.siri.updater.lite.SiriETLiteUpdaterParameters;
+import org.opentripplanner.updater.siri.updater.lite.SiriSXLiteUpdaterParameters;
import org.opentripplanner.updater.trip.MqttGtfsRealtimeUpdaterParameters;
import org.opentripplanner.updater.trip.PollingTripUpdaterParameters;
import org.opentripplanner.updater.vehicle_parking.VehicleParkingUpdaterParameters;
@@ -33,6 +35,10 @@ public interface UpdatersParameters {
List getSiriSXUpdaterParameters();
+ List getSiriETLiteUpdaterParameters();
+
+ List getSiriSXLiteUpdaterParameters();
+
List getMqttGtfsRealtimeUpdaterParameters();
List getVehicleParkingUpdaterParameters();
diff --git a/application/src/main/java/org/opentripplanner/updater/alert/GtfsRealtimeAlertsUpdater.java b/application/src/main/java/org/opentripplanner/updater/alert/GtfsRealtimeAlertsUpdater.java
index a5be5ef4185..8deddd35b61 100644
--- a/application/src/main/java/org/opentripplanner/updater/alert/GtfsRealtimeAlertsUpdater.java
+++ b/application/src/main/java/org/opentripplanner/updater/alert/GtfsRealtimeAlertsUpdater.java
@@ -2,6 +2,7 @@
import com.google.transit.realtime.GtfsRealtime.FeedMessage;
import java.net.URI;
+import java.util.concurrent.ExecutionException;
import org.opentripplanner.framework.io.OtpHttpClient;
import org.opentripplanner.framework.io.OtpHttpClientFactory;
import org.opentripplanner.routing.impl.TransitAlertServiceImpl;
@@ -26,7 +27,6 @@ public class GtfsRealtimeAlertsUpdater extends PollingGraphUpdater implements Tr
private final TransitAlertService transitAlertService;
private final HttpHeaders headers;
private final OtpHttpClient otpHttpClient;
- private WriteToGraphCallback saveResultOnGraph;
private Long lastTimestamp = Long.MIN_VALUE;
public GtfsRealtimeAlertsUpdater(
@@ -48,11 +48,6 @@ public GtfsRealtimeAlertsUpdater(
LOG.info("Creating real-time alert updater running every {}: {}", pollingPeriod(), url);
}
- @Override
- public void setup(WriteToGraphCallback writeToGraphCallback) {
- this.saveResultOnGraph = writeToGraphCallback;
- }
-
public TransitAlertService getTransitAlertService() {
return transitAlertService;
}
@@ -63,32 +58,26 @@ public String toString() {
}
@Override
- protected void runPolling() {
- try {
- final FeedMessage feed = otpHttpClient.getAndMap(
- URI.create(url),
- this.headers.asMap(),
- FeedMessage.PARSER::parseFrom
- );
+ protected void runPolling() throws InterruptedException, ExecutionException {
+ final FeedMessage feed = otpHttpClient.getAndMap(
+ URI.create(url),
+ this.headers.asMap(),
+ FeedMessage::parseFrom
+ );
- long feedTimestamp = feed.getHeader().getTimestamp();
- if (feedTimestamp == lastTimestamp) {
- LOG.debug("Ignoring feed with a timestamp that has not been updated from {}", url);
- return;
- }
- if (feedTimestamp < lastTimestamp) {
- LOG.info("Ignoring feed with older than previous timestamp from {}", url);
- return;
- }
+ long feedTimestamp = feed.getHeader().getTimestamp();
+ if (feedTimestamp == lastTimestamp) {
+ LOG.debug("Ignoring feed with a timestamp that has not been updated from {}", url);
+ return;
+ }
+ if (feedTimestamp < lastTimestamp) {
+ LOG.info("Ignoring feed with older than previous timestamp from {}", url);
+ return;
+ }
- // Handle update in graph writer runnable
- saveResultOnGraph.execute(context ->
- updateHandler.update(feed, context.gtfsRealtimeFuzzyTripMatcher())
- );
+ // Handle update in graph writer runnable
+ updateGraph(context -> updateHandler.update(feed, context.gtfsRealtimeFuzzyTripMatcher()));
- lastTimestamp = feedTimestamp;
- } catch (Exception e) {
- LOG.error("Failed to process GTFS-RT Alerts feed from {}", url, e);
- }
+ lastTimestamp = feedTimestamp;
}
}
diff --git a/application/src/main/java/org/opentripplanner/updater/configure/UpdaterConfigurator.java b/application/src/main/java/org/opentripplanner/updater/configure/UpdaterConfigurator.java
index 1106d621873..11be185fa2a 100644
--- a/application/src/main/java/org/opentripplanner/updater/configure/UpdaterConfigurator.java
+++ b/application/src/main/java/org/opentripplanner/updater/configure/UpdaterConfigurator.java
@@ -20,9 +20,11 @@
import org.opentripplanner.updater.UpdatersParameters;
import org.opentripplanner.updater.alert.GtfsRealtimeAlertsUpdater;
import org.opentripplanner.updater.siri.SiriTimetableSnapshotSource;
-import org.opentripplanner.updater.siri.updater.SiriETUpdater;
+import org.opentripplanner.updater.siri.updater.SiriHttpLoader;
import org.opentripplanner.updater.siri.updater.SiriSXUpdater;
+import org.opentripplanner.updater.siri.updater.configure.SiriUpdaterModule;
import org.opentripplanner.updater.siri.updater.google.SiriETGooglePubsubUpdater;
+import org.opentripplanner.updater.siri.updater.lite.SiriLiteHttpLoader;
import org.opentripplanner.updater.spi.GraphUpdater;
import org.opentripplanner.updater.spi.TimetableSnapshotFlush;
import org.opentripplanner.updater.trip.MqttGtfsRealtimeUpdater;
@@ -182,13 +184,23 @@ private List createUpdatersFromConfig() {
updaters.add(new PollingVehiclePositionUpdater(configItem, realtimeVehicleRepository));
}
for (var configItem : updatersParameters.getSiriETUpdaterParameters()) {
- updaters.add(new SiriETUpdater(configItem, provideSiriTimetableSnapshot()));
+ updaters.add(
+ SiriUpdaterModule.createSiriETUpdater(configItem, provideSiriTimetableSnapshot())
+ );
+ }
+ for (var configItem : updatersParameters.getSiriETLiteUpdaterParameters()) {
+ updaters.add(
+ SiriUpdaterModule.createSiriETUpdater(configItem, provideSiriTimetableSnapshot())
+ );
}
for (var configItem : updatersParameters.getSiriETGooglePubsubUpdaterParameters()) {
updaters.add(new SiriETGooglePubsubUpdater(configItem, provideSiriTimetableSnapshot()));
}
for (var configItem : updatersParameters.getSiriSXUpdaterParameters()) {
- updaters.add(new SiriSXUpdater(configItem, timetableRepository));
+ updaters.add(SiriUpdaterModule.createSiriSXUpdater(configItem, timetableRepository));
+ }
+ for (var configItem : updatersParameters.getSiriSXLiteUpdaterParameters()) {
+ updaters.add(SiriUpdaterModule.createSiriSXUpdater(configItem, timetableRepository));
}
for (var configItem : updatersParameters.getMqttGtfsRealtimeUpdaterParameters()) {
updaters.add(new MqttGtfsRealtimeUpdater(configItem, provideGtfsTimetableSnapshot()));
diff --git a/application/src/main/java/org/opentripplanner/updater/siri/updater/EstimatedTimetableSource.java b/application/src/main/java/org/opentripplanner/updater/siri/updater/EstimatedTimetableSource.java
index f8a1b549c96..3636fd2b96f 100644
--- a/application/src/main/java/org/opentripplanner/updater/siri/updater/EstimatedTimetableSource.java
+++ b/application/src/main/java/org/opentripplanner/updater/siri/updater/EstimatedTimetableSource.java
@@ -23,6 +23,4 @@ public interface EstimatedTimetableSource {
* {@link UpdateIncrementality}
*/
UpdateIncrementality incrementalityOfLastUpdates();
-
- String getFeedId();
}
diff --git a/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriETHttpTripUpdateSource.java b/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriETHttpTripUpdateSource.java
index fec6e2885a7..9d0373e1a16 100644
--- a/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriETHttpTripUpdateSource.java
+++ b/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriETHttpTripUpdateSource.java
@@ -11,6 +11,7 @@
import org.opentripplanner.framework.io.OtpHttpClientException;
import org.opentripplanner.updater.spi.HttpHeaders;
import org.opentripplanner.updater.trip.UpdateIncrementality;
+import org.opentripplanner.utils.tostring.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.org.siri.siri20.Siri;
@@ -19,11 +20,6 @@ public class SiriETHttpTripUpdateSource implements EstimatedTimetableSource {
private static final Logger LOG = LoggerFactory.getLogger(SiriETHttpTripUpdateSource.class);
- /**
- * Feed id that is used to match trip ids in the TripUpdates
- */
- private final String feedId;
-
private final String url;
private final SiriLoader siriLoader;
@@ -35,8 +31,7 @@ public class SiriETHttpTripUpdateSource implements EstimatedTimetableSource {
private UpdateIncrementality updateIncrementality = FULL_DATASET;
private ZonedDateTime lastTimestamp = ZonedDateTime.now().minusMonths(1);
- public SiriETHttpTripUpdateSource(Parameters parameters) {
- this.feedId = parameters.feedId();
+ public SiriETHttpTripUpdateSource(Parameters parameters, SiriLoader siriLoader) {
this.url = parameters.url();
this.requestorRef =
@@ -44,7 +39,7 @@ public SiriETHttpTripUpdateSource(Parameters parameters) {
? "otp-" + UUID.randomUUID()
: parameters.requestorRef();
- this.siriLoader = createLoader(url, parameters);
+ this.siriLoader = siriLoader;
}
@Override
@@ -82,28 +77,8 @@ public UpdateIncrementality incrementalityOfLastUpdates() {
}
@Override
- public String getFeedId() {
- return this.feedId;
- }
-
public String toString() {
- return "SiriETHttpTripUpdateSource(" + url + ")";
- }
-
- private static SiriLoader createLoader(String url, Parameters parameters) {
- // Load real-time updates from a file.
- if (SiriFileLoader.matchesUrl(url)) {
- return new SiriFileLoader(url);
- }
- // Fallback to default loader
- else {
- return new SiriHttpLoader(
- url,
- parameters.timeout(),
- parameters.httpRequestHeaders(),
- parameters.previewInterval()
- );
- }
+ return ToStringBuilder.of(SiriETHttpTripUpdateSource.class).addStr("url", url).toString();
}
public interface Parameters {
diff --git a/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriETUpdater.java b/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriETUpdater.java
index 087bf28e875..8901a49faef 100644
--- a/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriETUpdater.java
+++ b/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriETUpdater.java
@@ -4,10 +4,12 @@
import java.util.function.Consumer;
import org.opentripplanner.updater.siri.SiriTimetableSnapshotSource;
import org.opentripplanner.updater.spi.PollingGraphUpdater;
+import org.opentripplanner.updater.spi.PollingGraphUpdaterParameters;
import org.opentripplanner.updater.spi.ResultLogger;
import org.opentripplanner.updater.spi.UpdateResult;
import org.opentripplanner.updater.spi.WriteToGraphCallback;
-import org.opentripplanner.updater.trip.metrics.TripUpdateMetrics;
+import org.opentripplanner.updater.trip.UrlUpdaterParameters;
+import org.opentripplanner.utils.tostring.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.org.siri.siri20.EstimatedTimetableDeliveryStructure;
@@ -28,42 +30,30 @@ public class SiriETUpdater extends PollingGraphUpdater {
* Feed id that is used for the trip ids in the TripUpdates
*/
private final String feedId;
- /**
- * Parent update manager. Is used to execute graph writer runnables.
- */
- protected WriteToGraphCallback saveResultOnGraph;
private final EstimatedTimetableHandler estimatedTimetableHandler;
- private final Consumer recordMetrics;
+ private final Consumer metricsConsumer;
public SiriETUpdater(
- SiriETUpdaterParameters config,
- SiriTimetableSnapshotSource timetableSnapshotSource
+ Parameters config,
+ SiriTimetableSnapshotSource timetableSnapshotSource,
+ EstimatedTimetableSource source,
+ Consumer metricsConsumer
) {
super(config);
- // Create update streamer from preferences
this.feedId = config.feedId();
- this.updateSource = new SiriETHttpTripUpdateSource(config.sourceParameters());
+ this.updateSource = source;
this.blockReadinessUntilInitialized = config.blockReadinessUntilInitialized();
- LOG.info(
- "Creating stop time updater (SIRI ET) running every {} seconds : {}",
- pollingPeriod(),
- updateSource
- );
+ LOG.info("Creating SIRI-ET updater running every {}: {}", pollingPeriod(), updateSource);
estimatedTimetableHandler =
new EstimatedTimetableHandler(timetableSnapshotSource, config.fuzzyTripMatching(), feedId);
- recordMetrics = TripUpdateMetrics.streaming(config);
- }
-
- @Override
- public void setup(WriteToGraphCallback writeToGraphCallback) {
- this.saveResultOnGraph = writeToGraphCallback;
+ this.metricsConsumer = metricsConsumer;
}
/**
@@ -87,7 +77,7 @@ public void runPolling() {
saveResultOnGraph.execute(context -> {
var result = estimatedTimetableHandler.applyUpdate(etds, incrementality, context);
ResultLogger.logUpdateResult(feedId, "siri-et", result);
- recordMetrics.accept(result);
+ metricsConsumer.accept(result);
if (markPrimed) {
primed = true;
}
@@ -97,8 +87,20 @@ public void runPolling() {
} while (moreData);
}
+ @Override
public String toString() {
- String s = (updateSource == null) ? "NONE" : updateSource.toString();
- return "Polling SIRI ET updater with update source = " + s;
+ return ToStringBuilder
+ .of(SiriETUpdater.class)
+ .addStr("source", updateSource.toString())
+ .addDuration("frequency", pollingPeriod())
+ .toString();
+ }
+
+ public interface Parameters extends UrlUpdaterParameters, PollingGraphUpdaterParameters {
+ String url();
+
+ boolean blockReadinessUntilInitialized();
+
+ boolean fuzzyTripMatching();
}
}
diff --git a/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriETUpdaterParameters.java b/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriETUpdaterParameters.java
index dc479c034e1..71217225da1 100644
--- a/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriETUpdaterParameters.java
+++ b/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriETUpdaterParameters.java
@@ -2,8 +2,6 @@
import java.time.Duration;
import org.opentripplanner.updater.spi.HttpHeaders;
-import org.opentripplanner.updater.spi.PollingGraphUpdaterParameters;
-import org.opentripplanner.updater.trip.UrlUpdaterParameters;
public record SiriETUpdaterParameters(
String configRef,
@@ -18,8 +16,7 @@ public record SiriETUpdaterParameters(
HttpHeaders httpRequestHeaders,
boolean producerMetrics
)
- implements
- PollingGraphUpdaterParameters, UrlUpdaterParameters, SiriETHttpTripUpdateSource.Parameters {
+ implements SiriETUpdater.Parameters, SiriETHttpTripUpdateSource.Parameters {
public SiriETHttpTripUpdateSource.Parameters sourceParameters() {
return this;
}
diff --git a/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriHttpLoader.java b/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriHttpLoader.java
index 0ad9309e354..29de28efaee 100644
--- a/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriHttpLoader.java
+++ b/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriHttpLoader.java
@@ -11,7 +11,8 @@
import uk.org.siri.siri20.Siri;
/**
- * Load real-time updates from SIRI-SX and SIRI-ET feeds over HTTP.
+ * Load real-time updates from SIRI-SX and SIRI-ET feeds over HTTP using the request/response
+ * flow, which asks the server to only send the latest updates for a given requestor ref.
*/
public class SiriHttpLoader implements SiriLoader {
diff --git a/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriSXUpdater.java b/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriSXUpdater.java
index 83200db30d3..f089ea69bfd 100644
--- a/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriSXUpdater.java
+++ b/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriSXUpdater.java
@@ -13,7 +13,9 @@
import org.opentripplanner.updater.alert.TransitAlertProvider;
import org.opentripplanner.updater.siri.SiriAlertsUpdateHandler;
import org.opentripplanner.updater.spi.PollingGraphUpdater;
-import org.opentripplanner.updater.spi.WriteToGraphCallback;
+import org.opentripplanner.updater.spi.PollingGraphUpdaterParameters;
+import org.opentripplanner.updater.trip.UrlUpdaterParameters;
+import org.opentripplanner.utils.tostring.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.org.siri.siri20.ServiceDelivery;
@@ -33,19 +35,21 @@ public class SiriSXUpdater extends PollingGraphUpdater implements TransitAlertPr
// TODO RT_AB: Document why SiriAlertsUpdateHandler is a separate instance that persists across
// many graph update operations.
private final SiriAlertsUpdateHandler updateHandler;
- private WriteToGraphCallback writeToGraphCallback;
private ZonedDateTime lastTimestamp = ZonedDateTime.now().minusWeeks(1);
private String requestorRef;
/**
* Global retry counter used to create a new unique requestorRef after each retry.
*/
private int retryCount = 0;
- private final SiriHttpLoader siriHttpLoader;
+ private final SiriLoader siriHttpLoader;
private final OtpRetry retry;
- public SiriSXUpdater(SiriSXUpdaterParameters config, TimetableRepository timetableRepository) {
+ public SiriSXUpdater(
+ Parameters config,
+ TimetableRepository timetableRepository,
+ SiriLoader siriLoader
+ ) {
super(config);
- // TODO: add options to choose different patch services
this.url = config.url();
this.requestorRef = config.requestorRef();
@@ -59,7 +63,7 @@ public SiriSXUpdater(SiriSXUpdaterParameters config, TimetableRepository timetab
this.transitAlertService = new TransitAlertServiceImpl(timetableRepository);
this.updateHandler =
new SiriAlertsUpdateHandler(config.feedId(), transitAlertService, config.earlyStart());
- siriHttpLoader = new SiriHttpLoader(url, config.timeout(), config.requestHeaders());
+ siriHttpLoader = siriLoader;
retry =
new OtpRetryBuilder()
@@ -71,31 +75,27 @@ public SiriSXUpdater(SiriSXUpdaterParameters config, TimetableRepository timetab
.withOnRetry(this::updateRequestorRef)
.build();
- LOG.info(
- "Creating real-time alert updater (SIRI SX) running every {} seconds : {}",
- pollingPeriod(),
- url
- );
- }
-
- @Override
- public void setup(WriteToGraphCallback writeToGraphCallback) {
- this.writeToGraphCallback = writeToGraphCallback;
+ LOG.info("Creating SIRI-SX updater running every {}: {}", pollingPeriod(), url);
}
public TransitAlertService getTransitAlertService() {
return transitAlertService;
}
- public String toString() {
- return "SiriSXUpdater (" + url + ")";
- }
-
@Override
protected void runPolling() throws InterruptedException {
retry.execute(this::updateSiri);
}
+ @Override
+ public String toString() {
+ return ToStringBuilder
+ .of(SiriSXUpdater.class)
+ .addStr("url", url)
+ .addDuration("frequency", pollingPeriod())
+ .toString();
+ }
+
/**
* This part of the update process has been factored out to allow repeated retries of the HTTP
* fetching operation in case the connection fails or some other disruption happens.
@@ -141,7 +141,7 @@ private void updateSiri() {
// All that said, out of all the update types, Alerts (and SIRI SX) are probably the ones
// that would be most tolerant of non-versioned application-wide storage since they don't
// participate in routing and are tacked on to already-completed routing responses.
- writeToGraphCallback.execute(context -> {
+ saveResultOnGraph.execute(context -> {
updateHandler.update(serviceDelivery, context);
if (markPrimed) {
primed = true;
@@ -200,4 +200,12 @@ private void updateRequestorRef() {
retryCount++;
requestorRef = originalRequestorRef + "-retry-" + retryCount;
}
+
+ public interface Parameters extends PollingGraphUpdaterParameters, UrlUpdaterParameters {
+ String requestorRef();
+
+ boolean blockReadinessUntilInitialized();
+
+ Duration earlyStart();
+ }
}
diff --git a/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriSXUpdaterParameters.java b/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriSXUpdaterParameters.java
index f51584f86f5..d1796557658 100644
--- a/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriSXUpdaterParameters.java
+++ b/application/src/main/java/org/opentripplanner/updater/siri/updater/SiriSXUpdaterParameters.java
@@ -2,7 +2,6 @@
import java.time.Duration;
import org.opentripplanner.updater.spi.HttpHeaders;
-import org.opentripplanner.updater.spi.PollingGraphUpdaterParameters;
public record SiriSXUpdaterParameters(
String configRef,
@@ -15,4 +14,4 @@ public record SiriSXUpdaterParameters(
boolean blockReadinessUntilInitialized,
HttpHeaders requestHeaders
)
- implements PollingGraphUpdaterParameters {}
+ implements SiriSXUpdater.Parameters {}
diff --git a/application/src/main/java/org/opentripplanner/updater/siri/updater/configure/SiriUpdaterModule.java b/application/src/main/java/org/opentripplanner/updater/siri/updater/configure/SiriUpdaterModule.java
new file mode 100644
index 00000000000..f39fbbb3134
--- /dev/null
+++ b/application/src/main/java/org/opentripplanner/updater/siri/updater/configure/SiriUpdaterModule.java
@@ -0,0 +1,112 @@
+package org.opentripplanner.updater.siri.updater.configure;
+
+import java.util.function.Consumer;
+import org.opentripplanner.transit.service.TimetableRepository;
+import org.opentripplanner.updater.siri.SiriTimetableSnapshotSource;
+import org.opentripplanner.updater.siri.updater.EstimatedTimetableSource;
+import org.opentripplanner.updater.siri.updater.SiriETHttpTripUpdateSource;
+import org.opentripplanner.updater.siri.updater.SiriETUpdater;
+import org.opentripplanner.updater.siri.updater.SiriETUpdaterParameters;
+import org.opentripplanner.updater.siri.updater.SiriFileLoader;
+import org.opentripplanner.updater.siri.updater.SiriHttpLoader;
+import org.opentripplanner.updater.siri.updater.SiriLoader;
+import org.opentripplanner.updater.siri.updater.SiriSXUpdater;
+import org.opentripplanner.updater.siri.updater.SiriSXUpdaterParameters;
+import org.opentripplanner.updater.siri.updater.lite.SiriETLiteHttpTripUpdateSource;
+import org.opentripplanner.updater.siri.updater.lite.SiriETLiteUpdaterParameters;
+import org.opentripplanner.updater.siri.updater.lite.SiriLiteHttpLoader;
+import org.opentripplanner.updater.siri.updater.lite.SiriSXLiteUpdaterParameters;
+import org.opentripplanner.updater.spi.UpdateResult;
+import org.opentripplanner.updater.trip.metrics.TripUpdateMetrics;
+
+/**
+ * Dependency injection for instantiating SIRI-ET and SX updaters.
+ */
+public class SiriUpdaterModule {
+
+ public static SiriETUpdater createSiriETUpdater(
+ SiriETUpdater.Parameters params,
+ SiriTimetableSnapshotSource timetableSnapshotSource
+ ) {
+ return new SiriETUpdater(
+ params,
+ timetableSnapshotSource,
+ createSource(params),
+ createMetricsConsumer(params)
+ );
+ }
+
+ public static SiriSXUpdater createSiriSXUpdater(
+ SiriSXUpdater.Parameters params,
+ TimetableRepository timetableRepository
+ ) {
+ return new SiriSXUpdater(params, timetableRepository, createLoader(params));
+ }
+
+ private static EstimatedTimetableSource createSource(SiriETUpdater.Parameters params) {
+ return switch (params) {
+ case SiriETUpdaterParameters p -> new SiriETHttpTripUpdateSource(
+ p.sourceParameters(),
+ createLoader(params)
+ );
+ case SiriETLiteUpdaterParameters p -> new SiriETLiteHttpTripUpdateSource(
+ p.sourceParameters(),
+ createLoader(params)
+ );
+ default -> throw new IllegalArgumentException("Unexpected value: " + params);
+ };
+ }
+
+ private static SiriLoader createLoader(SiriSXUpdater.Parameters params) {
+ // Load real-time updates from a file.
+ if (SiriFileLoader.matchesUrl(params.url())) {
+ return new SiriFileLoader(params.url());
+ }
+ // Fallback to default loader
+ return switch (params) {
+ case SiriSXUpdaterParameters p -> new SiriHttpLoader(
+ p.url(),
+ p.timeout(),
+ p.requestHeaders()
+ );
+ case SiriSXLiteUpdaterParameters p -> new SiriLiteHttpLoader(
+ p.uri(),
+ p.timeout(),
+ p.requestHeaders()
+ );
+ default -> throw new IllegalArgumentException("Unexpected value: " + params);
+ };
+ }
+
+ private static SiriLoader createLoader(SiriETUpdater.Parameters params) {
+ // Load real-time updates from a file.
+ if (SiriFileLoader.matchesUrl(params.url())) {
+ return new SiriFileLoader(params.url());
+ }
+ // Fallback to default loader
+ else {
+ return switch (params) {
+ case SiriETUpdaterParameters p -> new SiriHttpLoader(
+ p.url(),
+ p.timeout(),
+ p.httpRequestHeaders(),
+ p.previewInterval()
+ );
+ case SiriETLiteUpdaterParameters p -> new SiriLiteHttpLoader(
+ p.uri(),
+ p.timeout(),
+ p.httpRequestHeaders()
+ );
+ default -> throw new IllegalArgumentException("Unexpected value: " + params);
+ };
+ }
+ }
+
+ private static Consumer createMetricsConsumer(SiriETUpdater.Parameters params) {
+ return switch (params) {
+ case SiriETUpdaterParameters p -> TripUpdateMetrics.streaming(p);
+ case SiriETLiteUpdaterParameters p -> TripUpdateMetrics.batch(p);
+ default -> throw new IllegalArgumentException("Unexpected value: " + params);
+ };
+ }
+}
diff --git a/application/src/main/java/org/opentripplanner/updater/siri/updater/lite/SiriETLiteHttpTripUpdateSource.java b/application/src/main/java/org/opentripplanner/updater/siri/updater/lite/SiriETLiteHttpTripUpdateSource.java
new file mode 100644
index 00000000000..30801a64c7f
--- /dev/null
+++ b/application/src/main/java/org/opentripplanner/updater/siri/updater/lite/SiriETLiteHttpTripUpdateSource.java
@@ -0,0 +1,76 @@
+package org.opentripplanner.updater.siri.updater.lite;
+
+import static org.opentripplanner.updater.trip.UpdateIncrementality.FULL_DATASET;
+
+import java.net.URI;
+import java.time.Duration;
+import java.util.Optional;
+import org.opentripplanner.framework.io.OtpHttpClientException;
+import org.opentripplanner.updater.siri.updater.EstimatedTimetableSource;
+import org.opentripplanner.updater.siri.updater.SiriLoader;
+import org.opentripplanner.updater.spi.HttpHeaders;
+import org.opentripplanner.updater.trip.UpdateIncrementality;
+import org.opentripplanner.utils.tostring.ToStringBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import uk.org.siri.siri20.Siri;
+
+/**
+ * SIRI Lite periodically downloads all messages as a single GET request.
+ */
+public class SiriETLiteHttpTripUpdateSource implements EstimatedTimetableSource {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SiriETLiteHttpTripUpdateSource.class);
+ /**
+ * The framework code requires a requestor ref but in SIRI Lite this is not used.
+ */
+ private static final String DUMMY_REQUESTOR_REF = "OpenTripPlanner";
+
+ private final Parameters parameters;
+
+ private final SiriLoader siriLoader;
+
+ public SiriETLiteHttpTripUpdateSource(Parameters parameters, SiriLoader siriLoader) {
+ this.parameters = parameters;
+ this.siriLoader = siriLoader;
+ }
+
+ @Override
+ public Optional getUpdates() {
+ try {
+ var siri = siriLoader.fetchETFeed(DUMMY_REQUESTOR_REF);
+ if (siri.map(Siri::getServiceDelivery).isEmpty()) {
+ return Optional.empty();
+ }
+ return siri;
+ } catch (OtpHttpClientException e) {
+ LOG.warn("Could not get SIRI-ET data from {}", parameters.uri(), e);
+ } catch (Exception e) {
+ LOG.warn("Failed to parse SIRI-ET feed from {}", parameters.uri(), e);
+ }
+ return Optional.empty();
+ }
+
+ @Override
+ public UpdateIncrementality incrementalityOfLastUpdates() {
+ return FULL_DATASET;
+ }
+
+ public String toString() {
+ return ToStringBuilder
+ .of(this.getClass())
+ .addStr("feedId", parameters.feedId())
+ .addStr("uri", parameters.uri().toString())
+ .toString();
+ }
+
+ public interface Parameters {
+ URI uri();
+
+ String feedId();
+
+ Duration timeout();
+
+ HttpHeaders httpRequestHeaders();
+ }
+}
diff --git a/application/src/main/java/org/opentripplanner/updater/siri/updater/lite/SiriETLiteUpdaterParameters.java b/application/src/main/java/org/opentripplanner/updater/siri/updater/lite/SiriETLiteUpdaterParameters.java
new file mode 100644
index 00000000000..1eed702e625
--- /dev/null
+++ b/application/src/main/java/org/opentripplanner/updater/siri/updater/lite/SiriETLiteUpdaterParameters.java
@@ -0,0 +1,31 @@
+package org.opentripplanner.updater.siri.updater.lite;
+
+import java.net.URI;
+import java.time.Duration;
+import org.opentripplanner.updater.siri.updater.SiriETUpdater;
+import org.opentripplanner.updater.spi.HttpHeaders;
+
+public record SiriETLiteUpdaterParameters(
+ String configRef,
+ String feedId,
+ URI uri,
+ Duration frequency,
+ Duration timeout,
+ boolean fuzzyTripMatching,
+ HttpHeaders httpRequestHeaders
+)
+ implements SiriETUpdater.Parameters, SiriETLiteHttpTripUpdateSource.Parameters {
+ public SiriETLiteHttpTripUpdateSource.Parameters sourceParameters() {
+ return this;
+ }
+
+ @Override
+ public String url() {
+ return uri.toString();
+ }
+
+ @Override
+ public boolean blockReadinessUntilInitialized() {
+ return false;
+ }
+}
diff --git a/application/src/main/java/org/opentripplanner/updater/siri/updater/lite/SiriLiteHttpLoader.java b/application/src/main/java/org/opentripplanner/updater/siri/updater/lite/SiriLiteHttpLoader.java
new file mode 100644
index 00000000000..c9b35be7b19
--- /dev/null
+++ b/application/src/main/java/org/opentripplanner/updater/siri/updater/lite/SiriLiteHttpLoader.java
@@ -0,0 +1,58 @@
+package org.opentripplanner.updater.siri.updater.lite;
+
+import java.net.URI;
+import java.time.Duration;
+import java.util.Optional;
+import org.opentripplanner.framework.io.OtpHttpClient;
+import org.opentripplanner.framework.io.OtpHttpClientFactory;
+import org.opentripplanner.updater.siri.updater.SiriHelper;
+import org.opentripplanner.updater.siri.updater.SiriLoader;
+import org.opentripplanner.updater.spi.HttpHeaders;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import uk.org.siri.siri20.Siri;
+
+/**
+ * Load real-time updates from SIRI-SX and SIRI-ET feeds over HTTP via a single request
+ * that contains all updates.
+ */
+public class SiriLiteHttpLoader implements SiriLoader {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SiriLiteHttpLoader.class);
+ private final HttpHeaders headers;
+ private final URI uri;
+ private final Duration timeout;
+ private final OtpHttpClient otpHttpClient;
+
+ public SiriLiteHttpLoader(URI uri, Duration timeout, HttpHeaders headers) {
+ this.uri = uri;
+ this.timeout = timeout;
+ this.headers = HttpHeaders.of().acceptApplicationXML().add(headers).build();
+ this.otpHttpClient = new OtpHttpClientFactory(timeout, timeout).create(LOG);
+ }
+
+ /**
+ * Send a HTTP GET request and unmarshal the response as JAXB.
+ */
+ @Override
+ public Optional fetchSXFeed(String ignored) {
+ return fetchFeed();
+ }
+
+ /**
+ * Send a HTTP GET service request and unmarshal the response as JAXB.
+ */
+ @Override
+ public Optional fetchETFeed(String ignored) {
+ return fetchFeed();
+ }
+
+ private Optional fetchFeed() {
+ return otpHttpClient.getAndMap(
+ uri,
+ timeout,
+ headers.asMap(),
+ is -> Optional.of(SiriHelper.unmarshal(is))
+ );
+ }
+}
diff --git a/application/src/main/java/org/opentripplanner/updater/siri/updater/lite/SiriSXLiteUpdaterParameters.java b/application/src/main/java/org/opentripplanner/updater/siri/updater/lite/SiriSXLiteUpdaterParameters.java
new file mode 100644
index 00000000000..5c48ca3e04b
--- /dev/null
+++ b/application/src/main/java/org/opentripplanner/updater/siri/updater/lite/SiriSXLiteUpdaterParameters.java
@@ -0,0 +1,32 @@
+package org.opentripplanner.updater.siri.updater.lite;
+
+import java.net.URI;
+import java.time.Duration;
+import org.opentripplanner.updater.siri.updater.SiriSXUpdater;
+import org.opentripplanner.updater.spi.HttpHeaders;
+
+public record SiriSXLiteUpdaterParameters(
+ String configRef,
+ String feedId,
+ URI uri,
+ Duration frequency,
+ Duration earlyStart,
+ Duration timeout,
+ HttpHeaders requestHeaders
+)
+ implements SiriSXUpdater.Parameters {
+ @Override
+ public String requestorRef() {
+ return "OpenTripPlanner";
+ }
+
+ @Override
+ public boolean blockReadinessUntilInitialized() {
+ return false;
+ }
+
+ @Override
+ public String url() {
+ return uri.toString();
+ }
+}
diff --git a/application/src/main/java/org/opentripplanner/updater/spi/PollingGraphUpdater.java b/application/src/main/java/org/opentripplanner/updater/spi/PollingGraphUpdater.java
index e0859371de8..e8faa4b6aba 100644
--- a/application/src/main/java/org/opentripplanner/updater/spi/PollingGraphUpdater.java
+++ b/application/src/main/java/org/opentripplanner/updater/spi/PollingGraphUpdater.java
@@ -2,6 +2,9 @@
import java.time.Duration;
import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import org.opentripplanner.framework.application.OTPFeature;
+import org.opentripplanner.updater.GraphWriterRunnable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,6 +37,10 @@ public abstract class PollingGraphUpdater implements GraphUpdater {
* removed that.
*/
protected volatile boolean primed;
+ /**
+ * Parent update manager. Is used to execute graph writer runnables.
+ */
+ protected WriteToGraphCallback saveResultOnGraph;
/** Shared configuration code for all polling graph updaters. */
protected PollingGraphUpdater(PollingGraphUpdaterParameters config) {
@@ -95,9 +102,22 @@ public String getConfigRef() {
return configRef;
}
+ @Override
+ public final void setup(WriteToGraphCallback writeToGraphCallback) {
+ this.saveResultOnGraph = writeToGraphCallback;
+ }
+
/**
* Mirrors GraphUpdater.run method. Only difference is that runPolling will be run multiple times
* with pauses in between. The length of the pause is defined in the preference frequency.
*/
protected abstract void runPolling() throws Exception;
+
+ protected final void updateGraph(GraphWriterRunnable task)
+ throws ExecutionException, InterruptedException {
+ var result = saveResultOnGraph.execute(task);
+ if (OTPFeature.WaitForGraphUpdateInPollingUpdaters.isOn()) {
+ result.get();
+ }
+ }
}
diff --git a/application/src/main/java/org/opentripplanner/updater/trip/MqttGtfsRealtimeUpdater.java b/application/src/main/java/org/opentripplanner/updater/trip/MqttGtfsRealtimeUpdater.java
index 20b49ed022f..0580cd4ea63 100644
--- a/application/src/main/java/org/opentripplanner/updater/trip/MqttGtfsRealtimeUpdater.java
+++ b/application/src/main/java/org/opentripplanner/updater/trip/MqttGtfsRealtimeUpdater.java
@@ -138,7 +138,7 @@ public void messageArrived(String topic, MqttMessage message) {
UpdateIncrementality updateIncrementality = FULL_DATASET;
try {
// Decode message
- GtfsRealtime.FeedMessage feedMessage = GtfsRealtime.FeedMessage.PARSER.parseFrom(
+ GtfsRealtime.FeedMessage feedMessage = GtfsRealtime.FeedMessage.parseFrom(
message.getPayload()
);
List feedEntityList = feedMessage.getEntityList();
diff --git a/application/src/main/java/org/opentripplanner/updater/trip/PollingTripUpdater.java b/application/src/main/java/org/opentripplanner/updater/trip/PollingTripUpdater.java
index c725c8b1088..8331bf19d3b 100644
--- a/application/src/main/java/org/opentripplanner/updater/trip/PollingTripUpdater.java
+++ b/application/src/main/java/org/opentripplanner/updater/trip/PollingTripUpdater.java
@@ -2,10 +2,10 @@
import com.google.transit.realtime.GtfsRealtime.TripUpdate;
import java.util.List;
+import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import org.opentripplanner.updater.spi.PollingGraphUpdater;
import org.opentripplanner.updater.spi.UpdateResult;
-import org.opentripplanner.updater.spi.WriteToGraphCallback;
import org.opentripplanner.updater.trip.metrics.BatchTripUpdateMetrics;
import org.opentripplanner.utils.tostring.ToStringBuilder;
import org.slf4j.Logger;
@@ -33,10 +33,6 @@ public class PollingTripUpdater extends PollingGraphUpdater {
private final BackwardsDelayPropagationType backwardsDelayPropagationType;
private final Consumer recordMetrics;
- /**
- * Parent update manager. Is used to execute graph writer runnables.
- */
- private WriteToGraphCallback saveResultOnGraph;
/**
* Set only if we should attempt to match the trip_id from other data in TripDescriptor
*/
@@ -63,17 +59,12 @@ public PollingTripUpdater(
);
}
- @Override
- public void setup(WriteToGraphCallback writeToGraphCallback) {
- this.saveResultOnGraph = writeToGraphCallback;
- }
-
/**
* Repeatedly makes blocking calls to an UpdateStreamer to retrieve new stop time updates, and
* applies those updates to the graph.
*/
@Override
- public void runPolling() {
+ public void runPolling() throws InterruptedException, ExecutionException {
// Get update lists from update source
List updates = updateSource.getUpdates();
var incrementality = updateSource.incrementalityOfLastUpdates();
@@ -89,7 +80,7 @@ public void runPolling() {
feedId,
recordMetrics
);
- saveResultOnGraph.execute(runnable);
+ updateGraph(runnable);
}
}
diff --git a/application/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingAvailabilityUpdater.java b/application/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingAvailabilityUpdater.java
index e548d5d75be..29e820ff952 100644
--- a/application/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingAvailabilityUpdater.java
+++ b/application/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingAvailabilityUpdater.java
@@ -2,6 +2,7 @@
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.opentripplanner.service.vehicleparking.VehicleParkingRepository;
@@ -12,7 +13,6 @@
import org.opentripplanner.updater.RealTimeUpdateContext;
import org.opentripplanner.updater.spi.DataSource;
import org.opentripplanner.updater.spi.PollingGraphUpdater;
-import org.opentripplanner.updater.spi.WriteToGraphCallback;
import org.opentripplanner.utils.tostring.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -27,8 +27,6 @@ public class VehicleParkingAvailabilityUpdater extends PollingGraphUpdater {
VehicleParkingAvailabilityUpdater.class
);
private final DataSource source;
- private WriteToGraphCallback saveResultOnGraph;
-
private final VehicleParkingRepository repository;
public VehicleParkingAvailabilityUpdater(
@@ -44,17 +42,12 @@ public VehicleParkingAvailabilityUpdater(
}
@Override
- public void setup(WriteToGraphCallback writeToGraphCallback) {
- this.saveResultOnGraph = writeToGraphCallback;
- }
-
- @Override
- protected void runPolling() {
+ protected void runPolling() throws InterruptedException, ExecutionException {
if (source.update()) {
var updates = source.getUpdates();
var graphWriterRunnable = new AvailabilityUpdater(updates);
- saveResultOnGraph.execute(graphWriterRunnable);
+ updateGraph(graphWriterRunnable);
}
}
diff --git a/application/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdater.java b/application/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdater.java
index 8e4cf8a862b..5513e224f57 100644
--- a/application/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdater.java
+++ b/application/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdater.java
@@ -6,6 +6,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.opentripplanner.routing.graph.Graph;
@@ -26,7 +27,6 @@
import org.opentripplanner.updater.RealTimeUpdateContext;
import org.opentripplanner.updater.spi.DataSource;
import org.opentripplanner.updater.spi.PollingGraphUpdater;
-import org.opentripplanner.updater.spi.WriteToGraphCallback;
import org.opentripplanner.utils.tostring.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -42,7 +42,6 @@ public class VehicleParkingUpdater extends PollingGraphUpdater {
private final Map> tempEdgesByPark = new HashMap<>();
private final DataSource source;
private final List oldVehicleParkings = new ArrayList<>();
- private WriteToGraphCallback saveResultOnGraph;
private final VertexLinker linker;
private final VehicleParkingRepository parkingRepository;
@@ -64,12 +63,7 @@ public VehicleParkingUpdater(
}
@Override
- public void setup(WriteToGraphCallback writeToGraphCallback) {
- this.saveResultOnGraph = writeToGraphCallback;
- }
-
- @Override
- protected void runPolling() {
+ protected void runPolling() throws InterruptedException, ExecutionException {
LOG.debug("Updating vehicle parkings from {}", source);
if (!source.update()) {
LOG.debug("No updates");
@@ -81,7 +75,7 @@ protected void runPolling() {
VehicleParkingGraphWriterRunnable graphWriterRunnable = new VehicleParkingGraphWriterRunnable(
vehicleParkings
);
- saveResultOnGraph.execute(graphWriterRunnable);
+ updateGraph(graphWriterRunnable);
}
private class VehicleParkingGraphWriterRunnable implements GraphWriterRunnable {
diff --git a/application/src/main/java/org/opentripplanner/updater/vehicle_position/PollingVehiclePositionUpdater.java b/application/src/main/java/org/opentripplanner/updater/vehicle_position/PollingVehiclePositionUpdater.java
index 4c487ac997b..f53d3010e59 100644
--- a/application/src/main/java/org/opentripplanner/updater/vehicle_position/PollingVehiclePositionUpdater.java
+++ b/application/src/main/java/org/opentripplanner/updater/vehicle_position/PollingVehiclePositionUpdater.java
@@ -3,11 +3,11 @@
import com.google.transit.realtime.GtfsRealtime.VehiclePosition;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.ExecutionException;
import org.opentripplanner.service.realtimevehicles.RealtimeVehicleRepository;
import org.opentripplanner.service.realtimevehicles.model.RealtimeVehicle;
import org.opentripplanner.standalone.config.routerconfig.updaters.VehiclePositionsUpdaterConfig;
import org.opentripplanner.updater.spi.PollingGraphUpdater;
-import org.opentripplanner.updater.spi.WriteToGraphCallback;
import org.opentripplanner.utils.tostring.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -27,10 +27,6 @@ public class PollingVehiclePositionUpdater extends PollingGraphUpdater {
private final GtfsRealtimeHttpVehiclePositionSource vehiclePositionSource;
private final Set vehiclePositionFeatures;
- /**
- * Parent update manager. Is used to execute graph writer runnables.
- */
- private WriteToGraphCallback saveResultOnGraph;
private final String feedId;
private final RealtimeVehicleRepository realtimeVehicleRepository;
private final boolean fuzzyTripMatching;
@@ -54,17 +50,12 @@ public PollingVehiclePositionUpdater(
);
}
- @Override
- public void setup(WriteToGraphCallback writeToGraphCallback) {
- this.saveResultOnGraph = writeToGraphCallback;
- }
-
/**
* Repeatedly makes blocking calls to an UpdateStreamer to retrieve new stop time updates, and
* applies those updates to the graph.
*/
@Override
- public void runPolling() {
+ public void runPolling() throws InterruptedException, ExecutionException {
// Get update lists from update source
List updates = vehiclePositionSource.getPositions();
@@ -77,7 +68,7 @@ public void runPolling() {
fuzzyTripMatching,
updates
);
- saveResultOnGraph.execute(runnable);
+ updateGraph(runnable);
}
}
diff --git a/application/src/main/java/org/opentripplanner/updater/vehicle_rental/VehicleRentalUpdater.java b/application/src/main/java/org/opentripplanner/updater/vehicle_rental/VehicleRentalUpdater.java
index 24686edce6c..8419d004138 100644
--- a/application/src/main/java/org/opentripplanner/updater/vehicle_rental/VehicleRentalUpdater.java
+++ b/application/src/main/java/org/opentripplanner/updater/vehicle_rental/VehicleRentalUpdater.java
@@ -8,6 +8,7 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.opentripplanner.routing.linking.DisposableEdgeCollection;
@@ -30,7 +31,6 @@
import org.opentripplanner.updater.RealTimeUpdateContext;
import org.opentripplanner.updater.spi.PollingGraphUpdater;
import org.opentripplanner.updater.spi.UpdaterConstructionException;
-import org.opentripplanner.updater.spi.WriteToGraphCallback;
import org.opentripplanner.updater.vehicle_rental.datasources.VehicleRentalDatasource;
import org.opentripplanner.utils.lang.ObjectUtils;
import org.opentripplanner.utils.logging.Throttle;
@@ -53,8 +53,6 @@ public class VehicleRentalUpdater extends PollingGraphUpdater {
private final VehicleRentalDatasource source;
private final String nameForLogging;
- private WriteToGraphCallback saveResultOnGraph;
-
private Map latestModifiedEdges = Map.of();
private Set latestAppliedGeofencingZones = Set.of();
private final Map verticesByStation = new HashMap<>();
@@ -108,11 +106,6 @@ public VehicleRentalUpdater(
}
}
- @Override
- public void setup(WriteToGraphCallback writeToGraphCallback) {
- this.saveResultOnGraph = writeToGraphCallback;
- }
-
@Override
public String toString() {
return ToStringBuilder.of(VehicleRentalUpdater.class).addObj("source", source).toString();
@@ -124,7 +117,7 @@ public String getConfigRef() {
}
@Override
- protected void runPolling() {
+ protected void runPolling() throws InterruptedException, ExecutionException {
LOG.debug("Updating vehicle rental stations from {}", nameForLogging);
if (!source.update()) {
LOG.debug("No updates from {}", nameForLogging);
@@ -138,7 +131,7 @@ protected void runPolling() {
stations,
geofencingZones
);
- saveResultOnGraph.execute(graphWriterRunnable);
+ updateGraph(graphWriterRunnable);
}
private class VehicleRentalGraphWriterRunnable implements GraphWriterRunnable {
diff --git a/application/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql b/application/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql
index b76f28649a4..6834d375bf1 100644
--- a/application/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql
+++ b/application/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql
@@ -702,7 +702,7 @@ type QueryType {
quays(ids: [String], name: String): [Quay]! @timingData
"Get all quays within the specified bounding box"
quaysByBbox(
- authority: String,
+ authority: String @deprecated(reason : "This is the Transmodel namespace or the GTFS feedID - avoid using this. Request a new field if necessary."),
"If true only quays with at least one visiting line are included."
filterByInUse: Boolean = false,
maximumLatitude: Float!,
diff --git a/application/src/test/java/org/opentripplanner/GtfsTest.java b/application/src/test/java/org/opentripplanner/GtfsTest.java
index 5d548e4012c..05b7bfbf4f6 100644
--- a/application/src/test/java/org/opentripplanner/GtfsTest.java
+++ b/application/src/test/java/org/opentripplanner/GtfsTest.java
@@ -221,7 +221,7 @@ protected void setUp() throws Exception {
try {
InputStream inputStream = new FileInputStream(gtfsRealTime);
- FeedMessage feedMessage = FeedMessage.PARSER.parseFrom(inputStream);
+ FeedMessage feedMessage = FeedMessage.parseFrom(inputStream);
List feedEntityList = feedMessage.getEntityList();
List updates = new ArrayList<>(feedEntityList.size());
for (FeedEntity feedEntity : feedEntityList) {
diff --git a/application/src/test/java/org/opentripplanner/apis/gtfs/mapping/routerequest/LegacyRouteRequestMapperTest.java b/application/src/test/java/org/opentripplanner/apis/gtfs/mapping/routerequest/LegacyRouteRequestMapperTest.java
index 43dd10dbdce..17193ad02c1 100644
--- a/application/src/test/java/org/opentripplanner/apis/gtfs/mapping/routerequest/LegacyRouteRequestMapperTest.java
+++ b/application/src/test/java/org/opentripplanner/apis/gtfs/mapping/routerequest/LegacyRouteRequestMapperTest.java
@@ -65,7 +65,7 @@ class LegacyRouteRequestMapperTest implements PlanTestConstants {
new DefaultVehicleRentalService(),
new DefaultVehicleParkingService(new DefaultVehicleParkingRepository()),
new DefaultRealtimeVehicleService(transitService),
- GraphFinder.getInstance(graph, transitService::findRegularStops),
+ GraphFinder.getInstance(graph, transitService::findRegularStopsByBoundingBox),
new RouteRequest()
);
}
diff --git a/application/src/test/java/org/opentripplanner/apis/gtfs/mapping/routerequest/RouteRequestMapperTest.java b/application/src/test/java/org/opentripplanner/apis/gtfs/mapping/routerequest/RouteRequestMapperTest.java
index 34cb865c81a..925e5009e77 100644
--- a/application/src/test/java/org/opentripplanner/apis/gtfs/mapping/routerequest/RouteRequestMapperTest.java
+++ b/application/src/test/java/org/opentripplanner/apis/gtfs/mapping/routerequest/RouteRequestMapperTest.java
@@ -75,7 +75,7 @@ class RouteRequestMapperTest {
new DefaultVehicleRentalService(),
new DefaultVehicleParkingService(new DefaultVehicleParkingRepository()),
new DefaultRealtimeVehicleService(transitService),
- GraphFinder.getInstance(graph, transitService::findRegularStops),
+ GraphFinder.getInstance(graph, transitService::findRegularStopsByBoundingBox),
new RouteRequest()
);
}
diff --git a/application/src/test/java/org/opentripplanner/ext/transmodelapi/_support/TestDataFetcherDecorator.java b/application/src/test/java/org/opentripplanner/apis/transmodel/_support/TestDataFetcherDecorator.java
similarity index 100%
rename from application/src/test/java/org/opentripplanner/ext/transmodelapi/_support/TestDataFetcherDecorator.java
rename to application/src/test/java/org/opentripplanner/apis/transmodel/_support/TestDataFetcherDecorator.java
diff --git a/application/src/test/java/org/opentripplanner/generate/doc/SiriConfigDocTest.java b/application/src/test/java/org/opentripplanner/generate/doc/SiriConfigDocTest.java
index b53c5370b53..5b65ca228c9 100644
--- a/application/src/test/java/org/opentripplanner/generate/doc/SiriConfigDocTest.java
+++ b/application/src/test/java/org/opentripplanner/generate/doc/SiriConfigDocTest.java
@@ -29,7 +29,12 @@ public class SiriConfigDocTest {
private static final File OUT_FILE = new File(USER_DOC_PATH, "sandbox/siri/SiriUpdater.md");
private static final String ROUTER_CONFIG_PATH = "standalone/config/" + ROUTER_CONFIG_FILENAME;
- private static final Set INCLUDE_UPDATERS = Set.of("siri-et-updater", "siri-sx-updater");
+ private static final Set INCLUDE_UPDATERS = Set.of(
+ "siri-et-updater",
+ "siri-sx-updater",
+ "siri-et-lite",
+ "siri-sx-lite"
+ );
private static final SkipNodes SKIP_NODES = SkipNodes.of().build();
public static final ObjectMapper mapper = new ObjectMapper();
diff --git a/application/src/test/java/org/opentripplanner/generate/doc/UpdaterConfigDocTest.java b/application/src/test/java/org/opentripplanner/generate/doc/UpdaterConfigDocTest.java
index 234d4c68b33..b88b0a38e80 100644
--- a/application/src/test/java/org/opentripplanner/generate/doc/UpdaterConfigDocTest.java
+++ b/application/src/test/java/org/opentripplanner/generate/doc/UpdaterConfigDocTest.java
@@ -35,7 +35,9 @@ public class UpdaterConfigDocTest {
"vehicle-parking",
"siri-et-updater",
"siri-et-google-pubsub-updater",
- "siri-sx-updater"
+ "siri-sx-updater",
+ "siri-et-lite",
+ "siri-sx-lite"
);
private static final SkipNodes SKIP_NODES = SkipNodes.of().build();
public static final ObjectMapper mapper = new ObjectMapper();
diff --git a/application/src/test/java/org/opentripplanner/model/plan/ScheduledTransitLegBuilderTest.java b/application/src/test/java/org/opentripplanner/model/plan/ScheduledTransitLegBuilderTest.java
index 8d3d6ed7c1e..c8ae617fd20 100644
--- a/application/src/test/java/org/opentripplanner/model/plan/ScheduledTransitLegBuilderTest.java
+++ b/application/src/test/java/org/opentripplanner/model/plan/ScheduledTransitLegBuilderTest.java
@@ -1,15 +1,24 @@
package org.opentripplanner.model.plan;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.opentripplanner.transit.model._data.TimetableRepositoryForTest.id;
import java.time.LocalDate;
+import java.util.Set;
import org.junit.jupiter.api.Test;
import org.opentripplanner._support.time.ZoneIds;
+import org.opentripplanner.framework.i18n.I18NString;
+import org.opentripplanner.routing.alertpatch.TransitAlert;
import org.opentripplanner.transit.model._data.TimetableRepositoryForTest;
import org.opentripplanner.transit.model.basic.TransitMode;
class ScheduledTransitLegBuilderTest {
+ private static final TransitAlert ALERT = TransitAlert
+ .of(id("alert"))
+ .withDescriptionText(I18NString.of("alert"))
+ .build();
+
@Test
void transferZoneId() {
var pattern = TimetableRepositoryForTest.of().pattern(TransitMode.BUS).build();
@@ -28,4 +37,24 @@ void transferZoneId() {
assertEquals(ZoneIds.BERLIN, withScore.getZoneId());
}
+
+ @Test
+ void alerts() {
+ var pattern = TimetableRepositoryForTest.of().pattern(TransitMode.BUS).build();
+ var leg = new ScheduledTransitLegBuilder<>()
+ .withZoneId(ZoneIds.BERLIN)
+ .withServiceDate(LocalDate.of(2023, 11, 15))
+ .withTripPattern(pattern)
+ .withBoardStopIndexInPattern(0)
+ .withAlightStopIndexInPattern(1)
+ .build();
+
+ leg.addAlert(ALERT);
+
+ var newLeg = new ScheduledTransitLegBuilder<>(leg);
+
+ var withScore = newLeg.withAccessibilityScore(4f).build();
+
+ assertEquals(Set.of(ALERT), withScore.getTransitAlerts());
+ }
}
diff --git a/application/src/test/java/org/opentripplanner/routing/graph/DefaultRoutingServiceTest.java b/application/src/test/java/org/opentripplanner/routing/graph/DefaultRoutingServiceTest.java
index ab897e3410b..48363a98c88 100644
--- a/application/src/test/java/org/opentripplanner/routing/graph/DefaultRoutingServiceTest.java
+++ b/application/src/test/java/org/opentripplanner/routing/graph/DefaultRoutingServiceTest.java
@@ -115,7 +115,7 @@ public void testSpatialIndex() {
SphericalDistanceLibrary.metersToLonDegrees(100, stopJ.getLat()),
SphericalDistanceLibrary.metersToDegrees(100)
);
- Collection stops = transitService.findRegularStops(env);
+ Collection stops = transitService.findRegularStopsByBoundingBox(env);
assertTrue(stops.contains(stopJ));
assertTrue(stops.contains(stopL));
assertTrue(stops.contains(stopM));
diff --git a/application/src/test/java/org/opentripplanner/smoketest/SeptaSmokeTest.java b/application/src/test/java/org/opentripplanner/smoketest/SeptaSmokeTest.java
index 1fd8269d2c2..4ac74f3cfbb 100644
--- a/application/src/test/java/org/opentripplanner/smoketest/SeptaSmokeTest.java
+++ b/application/src/test/java/org/opentripplanner/smoketest/SeptaSmokeTest.java
@@ -47,7 +47,7 @@ public void routeFromAirportToNorthPhiladelphia() {
.map(FareProductUse::product)
.toList();
- assertFalse(products.isEmpty());
+ //assertFalse(products.isEmpty());
var prices = products
.stream()
@@ -55,8 +55,7 @@ public void routeFromAirportToNorthPhiladelphia() {
.collect(Collectors.toSet());
LOG.info("Received fare products {}", products);
-
- assertTrue(prices.contains(6.75d));
+ //assertTrue(prices.contains(6.75d));
//SmokeTest.assertThatAllTransitLegsHaveFareProducts(plan);
}
diff --git a/application/src/test/java/org/opentripplanner/transit/model/filter/expr/GenericUnaryMatcherTest.java b/application/src/test/java/org/opentripplanner/transit/model/filter/expr/GenericUnaryMatcherTest.java
new file mode 100644
index 00000000000..ef93df53dbd
--- /dev/null
+++ b/application/src/test/java/org/opentripplanner/transit/model/filter/expr/GenericUnaryMatcherTest.java
@@ -0,0 +1,15 @@
+package org.opentripplanner.transit.model.filter.expr;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+class GenericUnaryMatcherTest {
+
+ @Test
+ void testMatches() {
+ var matcher = new GenericUnaryMatcher<>("int", i -> i.equals(42));
+ assertTrue(matcher.match(42));
+ assertFalse(matcher.match(43));
+ }
+}
diff --git a/application/src/test/java/org/opentripplanner/transit/model/filter/transit/RegularStopMatcherFactoryTest.java b/application/src/test/java/org/opentripplanner/transit/model/filter/transit/RegularStopMatcherFactoryTest.java
new file mode 100644
index 00000000000..5cfeaf2780f
--- /dev/null
+++ b/application/src/test/java/org/opentripplanner/transit/model/filter/transit/RegularStopMatcherFactoryTest.java
@@ -0,0 +1,44 @@
+package org.opentripplanner.transit.model.filter.transit;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.opentripplanner.transit.model.framework.FeedScopedId;
+import org.opentripplanner.transit.model.site.RegularStop;
+
+class RegularStopMatcherFactoryTest {
+
+ private static RegularStop stop1;
+ private static RegularStop stop2;
+
+ @BeforeAll
+ static void setup() {
+ stop1 =
+ RegularStop
+ .of(new FeedScopedId("agency", "stopId"), new AtomicInteger()::getAndIncrement)
+ .build();
+
+ stop2 =
+ RegularStop
+ .of(new FeedScopedId("otherAgency", "otherStopId"), new AtomicInteger()::getAndIncrement)
+ .build();
+ }
+
+ @Test
+ void testFeedIds() {
+ var matcher = RegularStopMatcherFactory.feedId("agency");
+ assertTrue(matcher.match(stop1));
+ assertFalse(matcher.match(stop2));
+ }
+
+ @Test
+ void testInUseMatcher() {
+ var matcher = RegularStopMatcherFactory.inUseMatcher(stop ->
+ stop.getId().getFeedId().equals("agency")
+ );
+ assertTrue(matcher.match(stop1));
+ assertFalse(matcher.match(stop2));
+ }
+}
diff --git a/application/src/test/java/org/opentripplanner/updater/siri/updater/lite/SiriLiteHttpLoaderTest.java b/application/src/test/java/org/opentripplanner/updater/siri/updater/lite/SiriLiteHttpLoaderTest.java
new file mode 100644
index 00000000000..c05e248747a
--- /dev/null
+++ b/application/src/test/java/org/opentripplanner/updater/siri/updater/lite/SiriLiteHttpLoaderTest.java
@@ -0,0 +1,33 @@
+package org.opentripplanner.updater.siri.updater.lite;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.time.Duration;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.opentripplanner.test.support.ResourceLoader;
+import org.opentripplanner.updater.spi.HttpHeaders;
+import uk.org.siri.siri20.NaturalLanguageStringStructure;
+
+class SiriLiteHttpLoaderTest {
+
+ private static final Duration ONE_MIN = Duration.ofMinutes(1);
+
+ @Test
+ void test() {
+ var uri = ResourceLoader.of(this).uri("siri-sx.xml");
+ var loader = new SiriLiteHttpLoader(uri, ONE_MIN, HttpHeaders.empty());
+ var siri = loader.fetchETFeed("OTP");
+ var delivery = siri.get().getServiceDelivery().getSituationExchangeDeliveries().getFirst();
+ var element = delivery.getSituations().getPtSituationElements().getFirst();
+ assertEquals(
+ List.of(
+ "Hindernis auf Strecke",
+ "Obstacle on the route",
+ "Ostacolo sul percorso",
+ "Ostacul su la via"
+ ),
+ element.getReasonNames().stream().map(NaturalLanguageStringStructure::getValue).toList()
+ );
+ }
+}
diff --git a/application/src/test/java/org/opentripplanner/updater/spi/PollingGraphUpdaterTest.java b/application/src/test/java/org/opentripplanner/updater/spi/PollingGraphUpdaterTest.java
new file mode 100644
index 00000000000..6132988d92b
--- /dev/null
+++ b/application/src/test/java/org/opentripplanner/updater/spi/PollingGraphUpdaterTest.java
@@ -0,0 +1,78 @@
+package org.opentripplanner.updater.spi;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.time.Duration;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.opentripplanner.framework.application.OTPFeature;
+import org.opentripplanner.updater.GraphWriterRunnable;
+
+public class PollingGraphUpdaterTest {
+
+ private static final PollingGraphUpdaterParameters config = new PollingGraphUpdaterParameters() {
+ @Override
+ public Duration frequency() {
+ return Duration.ZERO;
+ }
+
+ @Override
+ public String configRef() {
+ return "";
+ }
+ };
+
+ private static final PollingGraphUpdater subject = new PollingGraphUpdater(config) {
+ @Override
+ protected void runPolling() {}
+ };
+
+ private boolean updateCompleted;
+
+ @BeforeAll
+ static void beforeAll() {
+ subject.setup(runnable -> CompletableFuture.runAsync(() -> runnable.run(null)));
+ }
+
+ @BeforeEach
+ void setUp() {
+ updateCompleted = false;
+ }
+
+ private final GraphWriterRunnable graphWriterRunnable = context -> {
+ try {
+ Thread.sleep(100);
+ updateCompleted = true;
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ };
+
+ @Test
+ void testUpdateGraphWithWaitFeatureOn() {
+ OTPFeature.WaitForGraphUpdateInPollingUpdaters.testOn(() -> {
+ callUpdater();
+ assertTrue(updateCompleted);
+ });
+ }
+
+ @Test
+ void testProcessGraphUpdaterResultWithWaitFeatureOff() {
+ OTPFeature.WaitForGraphUpdateInPollingUpdaters.testOff(() -> {
+ callUpdater();
+ assertFalse(updateCompleted);
+ });
+ }
+
+ private void callUpdater() {
+ try {
+ subject.updateGraph(graphWriterRunnable);
+ } catch (ExecutionException | InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/application/src/test/resources/org/opentripplanner/updater/siri/updater/lite/siri-sx.xml b/application/src/test/resources/org/opentripplanner/updater/siri/updater/lite/siri-sx.xml
new file mode 100644
index 00000000000..be63b158bc6
--- /dev/null
+++ b/application/src/test/resources/org/opentripplanner/updater/siri/updater/lite/siri-sx.xml
@@ -0,0 +1,243 @@
+
+
+
+ 2024-11-27T11:48:04.308988Z
+ DDIP-M
+
+ 2024-11-27T11:48:04.308988Z
+
+
+ 2024-10-04T13:11:34.547+02:00
+ STA
+ 2024-3443167
+ 6
+
+
+
+ 2024-10-04T13:08:00+02:00
+ 2024-11-30T13:08:00+01:00
+
+
+ 2024-10-04T00:00:00+02:00
+ 2024-11-30T23:59:00+01:00
+
+ routeBlockage
+ Hindernis auf Strecke
+ Obstacle on the route
+ Ostacolo sul percorso
+ Ostacul su la via
+ 3
+ line
+ de
+ Straßen-/Streckenhindernis
+ The busroute: 120 obstacle on the track
+ 120 Linea 120 . Ostacolo su strada/pista
+
+
+
+
+ it:apb:Line:80120_.24a
+ 120
+
+ 28554
+ Salorno, Autostazione
+
+
+
+
+
+
+
+
+ 2024-10-04T13:08:00+02:00
+ 2024-11-30T13:08:00+01:00
+
+ tripCancellation
+ normal
+
+
+
+
+ it:apb:Line:80120_.24a
+ 120
+
+ 28554
+ Salorno, Autostazione
+
+
+
+
+
+
+
+
+
+
+
+ line
+
+
+
+
+ it:apb:Line:80120_.24a
+ 120
+
+ 28554
+ Salorno, Autostazione
+
+
+
+
+
+
+
+
+ published
+ 2024-3443167
+ 2024-10-04T13:11:34.547+02:00
+ 6
+ ControlCenter
+ STA
+ general
+ 3
+
+ L
+
+ Straßen-/Streckenhindernis
+
+ The busroute: 120 obstacle on the
+ track
+
+ 120 Linea 120 . Ostacolo su
+ strada/pista
+
+
+
+ Hindernis auf Strecke
+ Obstacle on the route
+ Ostacolo sul percorso
+ Ostacul su la via
+
+
+ Freitext
+ Free text
+ Testo libero
+
+
+
+ Umsteigen auf andere
+ Linie
+
+ Change to another line
+
+ Cambiare linea
+
+
+
+ Dauer der Beeinträchtigung bis
+ vsl. 2024-11-30 13:08:00
+
+
+
+
+
+ M
+
+ Straßen-/Streckenhindernis
+
+ The busroute: 120 obstacle on the
+ track
+
+ 120 Linea 120 . Ostacolo su
+ strada/pista
+
+
+
+ Hindernis auf Strecke
+ Obstacle on the route
+ Ostacolo sul percorso
+ Ostacul su la via
+
+
+ Freitext
+ Free text
+ Testo libero
+
+
+
+ Umsteigen auf andere
+ Linie
+
+ Change to another line
+
+ Cambiare linea
+
+
+
+ Dauer der Beeinträchtigung bis
+ vsl. 2024-11-30 13:08:00
+
+
+
+
+
+ S
+
+ Straßen-/Streckenhindernis
+
+ The busroute: 120 obstacle on the
+ track
+
+ 120 Linea 120 . Ostacolo su
+ strada/pista
+
+
+
+ Hindernis auf Strecke
+ Obstacle on the route
+ Ostacolo sul percorso
+ Ostacul su la via
+
+
+ Aufgrund Stand: 04.10.2024 -
+ 30.11.2024 ; 13:08
+
+ Due to Update: 04.10.2024 ;
+ 13:08
+
+ A causa di Aggiornamento:
+ 04.10.2024 ; 13:08
+
+
+
+ Freitext
+ Free text
+ Testo libero
+
+
+
+ Umsteigen auf andere
+ Linie
+
+ Change to another line
+
+ Cambiare linea
+
+
+
+ Dauer der Beeinträchtigung bis
+ vsl. 2024-11-30 13:08:00
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/test/resources/standalone/config/router-config.json b/application/src/test/resources/standalone/config/router-config.json
index 3616007c087..77c67d85742 100644
--- a/application/src/test/resources/standalone/config/router-config.json
+++ b/application/src/test/resources/standalone/config/router-config.json
@@ -434,6 +434,17 @@
"feedId": "parking",
"sourceType": "siri-fm",
"url": "https://transmodel.api.opendatahub.com/siri-lite/fm/parking"
+ },
+ {
+ "type": "siri-et-lite",
+ "feedId": "sta",
+ "url": "https://example.com/siri-lite/estimated-timetable/xml",
+ "fuzzyTripMatching": true
+ },
+ {
+ "type": "siri-sx-lite",
+ "feedId": "sta",
+ "url": "https://example.com/siri-lite/situation-exchange/xml"
}
],
"rideHailingServices": [
diff --git a/client/package-lock.json b/client/package-lock.json
index a50d6d07f73..bb145274bd4 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -17,21 +17,21 @@
"react": "19.0.0",
"react-bootstrap": "2.10.7",
"react-dom": "19.0.0",
- "react-map-gl": "7.1.7"
+ "react-map-gl": "7.1.8"
},
"devDependencies": {
- "@eslint/compat": "1.2.4",
- "@eslint/js": "9.17.0",
+ "@eslint/compat": "1.2.5",
+ "@eslint/js": "9.18.0",
"@graphql-codegen/cli": "5.0.3",
"@graphql-codegen/client-preset": "4.5.1",
"@graphql-codegen/introspection": "4.0.3",
"@parcel/watcher": "2.5.0",
"@testing-library/react": "16.1.0",
- "@types/react": "19.0.1",
+ "@types/react": "19.0.4",
"@types/react-dom": "19.0.2",
"@vitejs/plugin-react": "4.3.4",
"@vitest/coverage-v8": "2.1.8",
- "eslint": "9.17.0",
+ "eslint": "9.18.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-jsx-a11y": "6.10.2",
@@ -39,11 +39,11 @@
"eslint-plugin-react-hooks": "5.1.0",
"eslint-plugin-react-refresh": "0.4.16",
"globals": "15.14.0",
- "jsdom": "25.0.1",
+ "jsdom": "26.0.0",
"prettier": "3.4.2",
- "typescript": "5.7.2",
- "typescript-eslint": "8.19.0",
- "vite": "6.0.3",
+ "typescript": "5.7.3",
+ "typescript-eslint": "8.19.1",
+ "vite": "6.0.7",
"vitest": "2.1.8"
}
},
@@ -207,6 +207,30 @@
"node": ">=14"
}
},
+ "node_modules/@asamuzakjp/css-color": {
+ "version": "2.8.2",
+ "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-2.8.2.tgz",
+ "integrity": "sha512-RtWv9jFN2/bLExuZgFFZ0I3pWWeezAHGgrmjqGGWclATl1aDe3yhCUaI0Ilkp6OCk9zX7+FjvDasEX8Q9Rxc5w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@csstools/css-calc": "^2.1.1",
+ "@csstools/css-color-parser": "^3.0.7",
+ "@csstools/css-parser-algorithms": "^3.0.4",
+ "@csstools/css-tokenizer": "^3.0.3",
+ "lru-cache": "^11.0.2"
+ }
+ },
+ "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": {
+ "version": "11.0.2",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz",
+ "integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
"node_modules/@babel/code-frame": {
"version": "7.26.2",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
@@ -1007,6 +1031,121 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
+ "node_modules/@csstools/color-helpers": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz",
+ "integrity": "sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT-0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@csstools/css-calc": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.1.tgz",
+ "integrity": "sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@csstools/css-parser-algorithms": "^3.0.4",
+ "@csstools/css-tokenizer": "^3.0.3"
+ }
+ },
+ "node_modules/@csstools/css-color-parser": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.7.tgz",
+ "integrity": "sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@csstools/color-helpers": "^5.0.1",
+ "@csstools/css-calc": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@csstools/css-parser-algorithms": "^3.0.4",
+ "@csstools/css-tokenizer": "^3.0.3"
+ }
+ },
+ "node_modules/@csstools/css-parser-algorithms": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz",
+ "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@csstools/css-tokenizer": "^3.0.3"
+ }
+ },
+ "node_modules/@csstools/css-tokenizer": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz",
+ "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@envelop/core": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/@envelop/core/-/core-5.0.2.tgz",
@@ -1472,10 +1611,11 @@
}
},
"node_modules/@eslint/compat": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.4.tgz",
- "integrity": "sha512-S8ZdQj/N69YAtuqFt7653jwcvuUj131+6qGLUyDqfDg1OIoBQ66OCuXC473YQfO2AaxITTutiRQiDwoo7ZLYyg==",
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.5.tgz",
+ "integrity": "sha512-5iuG/StT+7OfvhoBHPlmxkPA9om6aDUFgmD4+mWKAGsYt4vCe8rypneG03AuseyRHBmcCLXQtIH5S26tIoggLg==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
@@ -1503,10 +1643,11 @@
}
},
"node_modules/@eslint/core": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz",
- "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==",
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz",
+ "integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
"@types/json-schema": "^7.0.15"
},
@@ -1550,10 +1691,11 @@
}
},
"node_modules/@eslint/js": {
- "version": "9.17.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz",
- "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==",
+ "version": "9.18.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz",
+ "integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
@@ -1568,11 +1710,13 @@
}
},
"node_modules/@eslint/plugin-kit": {
- "version": "0.2.4",
- "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz",
- "integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==",
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz",
+ "integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
+ "@eslint/core": "^0.10.0",
"levn": "^0.4.1"
},
"engines": {
@@ -3736,9 +3880,10 @@
"integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ=="
},
"node_modules/@types/react": {
- "version": "19.0.1",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.1.tgz",
- "integrity": "sha512-YW6614BDhqbpR5KtUYzTA+zlA7nayzJRA9ljz9CQoxthR0sDisYZLuvSMsil36t4EH/uAt8T52Xb4sVw17G+SQ==",
+ "version": "19.0.4",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.4.tgz",
+ "integrity": "sha512-3O4QisJDYr1uTUMZHA2YswiQZRq+Pd8D+GdVFYikTutYsTz+QZgWkAPnP7rx9txoI6EXKcPiluMqWPFV3tT9Wg==",
+ "license": "MIT",
"dependencies": {
"csstype": "^3.0.2"
}
@@ -3783,20 +3928,21 @@
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.19.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.0.tgz",
- "integrity": "sha512-NggSaEZCdSrFddbctrVjkVZvFC6KGfKfNK0CU7mNK/iKHGKbzT4Wmgm08dKpcZECBu9f5FypndoMyRHkdqfT1Q==",
+ "version": "8.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.1.tgz",
+ "integrity": "sha512-tJzcVyvvb9h/PB96g30MpxACd9IrunT7GF9wfA9/0TJ1LxGOJx1TdPzSbBBnNED7K9Ka8ybJsnEpiXPktolTLg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.19.0",
- "@typescript-eslint/type-utils": "8.19.0",
- "@typescript-eslint/utils": "8.19.0",
- "@typescript-eslint/visitor-keys": "8.19.0",
+ "@typescript-eslint/scope-manager": "8.19.1",
+ "@typescript-eslint/type-utils": "8.19.1",
+ "@typescript-eslint/utils": "8.19.1",
+ "@typescript-eslint/visitor-keys": "8.19.1",
"graphemer": "^1.4.0",
"ignore": "^5.3.1",
"natural-compare": "^1.4.0",
- "ts-api-utils": "^1.3.0"
+ "ts-api-utils": "^2.0.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3812,15 +3958,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "8.19.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.19.0.tgz",
- "integrity": "sha512-6M8taKyOETY1TKHp0x8ndycipTVgmp4xtg5QpEZzXxDhNvvHOJi5rLRkLr8SK3jTgD5l4fTlvBiRdfsuWydxBw==",
+ "version": "8.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.19.1.tgz",
+ "integrity": "sha512-67gbfv8rAwawjYx3fYArwldTQKoYfezNUT4D5ioWetr/xCrxXxvleo3uuiFuKfejipvq+og7mjz3b0G2bVyUCw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/scope-manager": "8.19.0",
- "@typescript-eslint/types": "8.19.0",
- "@typescript-eslint/typescript-estree": "8.19.0",
- "@typescript-eslint/visitor-keys": "8.19.0",
+ "@typescript-eslint/scope-manager": "8.19.1",
+ "@typescript-eslint/types": "8.19.1",
+ "@typescript-eslint/typescript-estree": "8.19.1",
+ "@typescript-eslint/visitor-keys": "8.19.1",
"debug": "^4.3.4"
},
"engines": {
@@ -3836,13 +3983,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "8.19.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.0.tgz",
- "integrity": "sha512-hkoJiKQS3GQ13TSMEiuNmSCvhz7ujyqD1x3ShbaETATHrck+9RaDdUbt+osXaUuns9OFwrDTTrjtwsU8gJyyRA==",
+ "version": "8.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.1.tgz",
+ "integrity": "sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.19.0",
- "@typescript-eslint/visitor-keys": "8.19.0"
+ "@typescript-eslint/types": "8.19.1",
+ "@typescript-eslint/visitor-keys": "8.19.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3853,15 +4001,16 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "8.19.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.19.0.tgz",
- "integrity": "sha512-TZs0I0OSbd5Aza4qAMpp1cdCYVnER94IziudE3JU328YUHgWu9gwiwhag+fuLeJ2LkWLXI+F/182TbG+JaBdTg==",
+ "version": "8.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.19.1.tgz",
+ "integrity": "sha512-Rp7k9lhDKBMRJB/nM9Ksp1zs4796wVNyihG9/TU9R6KCJDNkQbc2EOKjrBtLYh3396ZdpXLtr/MkaSEmNMtykw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/typescript-estree": "8.19.0",
- "@typescript-eslint/utils": "8.19.0",
+ "@typescript-eslint/typescript-estree": "8.19.1",
+ "@typescript-eslint/utils": "8.19.1",
"debug": "^4.3.4",
- "ts-api-utils": "^1.3.0"
+ "ts-api-utils": "^2.0.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3876,10 +4025,11 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "8.19.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.0.tgz",
- "integrity": "sha512-8XQ4Ss7G9WX8oaYvD4OOLCjIQYgRQxO+qCiR2V2s2GxI9AUpo7riNwo6jDhKtTcaJjT8PY54j2Yb33kWtSJsmA==",
+ "version": "8.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.1.tgz",
+ "integrity": "sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
@@ -3889,19 +4039,20 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.19.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.0.tgz",
- "integrity": "sha512-WW9PpDaLIFW9LCbucMSdYUuGeFUz1OkWYS/5fwZwTA+l2RwlWFdJvReQqMUMBw4yJWJOfqd7An9uwut2Oj8sLw==",
+ "version": "8.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.1.tgz",
+ "integrity": "sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.19.0",
- "@typescript-eslint/visitor-keys": "8.19.0",
+ "@typescript-eslint/types": "8.19.1",
+ "@typescript-eslint/visitor-keys": "8.19.1",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
"minimatch": "^9.0.4",
"semver": "^7.6.0",
- "ts-api-utils": "^1.3.0"
+ "ts-api-utils": "^2.0.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3919,6 +4070,7 @@
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
@@ -3928,6 +4080,7 @@
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
@@ -3943,6 +4096,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"dev": true,
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@@ -3951,15 +4105,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
- "version": "8.19.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.0.tgz",
- "integrity": "sha512-PTBG+0oEMPH9jCZlfg07LCB2nYI0I317yyvXGfxnvGvw4SHIOuRnQ3kadyyXY6tGdChusIHIbM5zfIbp4M6tCg==",
+ "version": "8.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.1.tgz",
+ "integrity": "sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
- "@typescript-eslint/scope-manager": "8.19.0",
- "@typescript-eslint/types": "8.19.0",
- "@typescript-eslint/typescript-estree": "8.19.0"
+ "@typescript-eslint/scope-manager": "8.19.1",
+ "@typescript-eslint/types": "8.19.1",
+ "@typescript-eslint/typescript-estree": "8.19.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3974,12 +4129,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.19.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.0.tgz",
- "integrity": "sha512-mCFtBbFBJDCNCWUl5y6sZSCHXw1DEFEk3c/M3nRK2a4XUB8StGFtmcEMizdjKuBzB6e/smJAAWYug3VrdLMr1w==",
+ "version": "8.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.1.tgz",
+ "integrity": "sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.19.0",
+ "@typescript-eslint/types": "8.19.1",
"eslint-visitor-keys": "^4.2.0"
},
"engines": {
@@ -5178,12 +5334,14 @@
}
},
"node_modules/cssstyle": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz",
- "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==",
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.2.1.tgz",
+ "integrity": "sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "rrweb-cssom": "^0.7.1"
+ "@asamuzakjp/css-color": "^2.8.2",
+ "rrweb-cssom": "^0.8.0"
},
"engines": {
"node": ">=18"
@@ -5774,18 +5932,19 @@
}
},
"node_modules/eslint": {
- "version": "9.17.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz",
- "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==",
+ "version": "9.18.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.18.0.tgz",
+ "integrity": "sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.19.0",
- "@eslint/core": "^0.9.0",
+ "@eslint/core": "^0.10.0",
"@eslint/eslintrc": "^3.2.0",
- "@eslint/js": "9.17.0",
- "@eslint/plugin-kit": "^0.2.3",
+ "@eslint/js": "9.18.0",
+ "@eslint/plugin-kit": "^0.2.5",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.1",
@@ -7761,22 +7920,23 @@
"integrity": "sha512-SnZNcinB4RIcnEyZqFPdGPVgrg2AcnykiBy0sHVJQKHYeaLUvi3Exj+iaPpLnFVkDPZIV4U0yvgC9/R4uEAZ9g=="
},
"node_modules/jsdom": {
- "version": "25.0.1",
- "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz",
- "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==",
+ "version": "26.0.0",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.0.0.tgz",
+ "integrity": "sha512-BZYDGVAIriBWTpIxYzrXjv3E/4u8+/pSG5bQdIYCbNCGOvsPkDQfTVLAIXAf9ETdCpduCVTkDe2NNZ8NIwUVzw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "cssstyle": "^4.1.0",
+ "cssstyle": "^4.2.1",
"data-urls": "^5.0.0",
"decimal.js": "^10.4.3",
- "form-data": "^4.0.0",
+ "form-data": "^4.0.1",
"html-encoding-sniffer": "^4.0.0",
"http-proxy-agent": "^7.0.2",
- "https-proxy-agent": "^7.0.5",
+ "https-proxy-agent": "^7.0.6",
"is-potential-custom-element-name": "^1.0.1",
- "nwsapi": "^2.2.12",
- "parse5": "^7.1.2",
- "rrweb-cssom": "^0.7.1",
+ "nwsapi": "^2.2.16",
+ "parse5": "^7.2.1",
+ "rrweb-cssom": "^0.8.0",
"saxes": "^6.0.0",
"symbol-tree": "^3.2.4",
"tough-cookie": "^5.0.0",
@@ -7784,7 +7944,7 @@
"webidl-conversions": "^7.0.0",
"whatwg-encoding": "^3.1.1",
"whatwg-mimetype": "^4.0.0",
- "whatwg-url": "^14.0.0",
+ "whatwg-url": "^14.1.0",
"ws": "^8.18.0",
"xml-name-validator": "^5.0.0"
},
@@ -7792,7 +7952,7 @@
"node": ">=18"
},
"peerDependencies": {
- "canvas": "^2.11.2"
+ "canvas": "^3.0.0"
},
"peerDependenciesMeta": {
"canvas": {
@@ -9175,9 +9335,10 @@
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"node_modules/react-map-gl": {
- "version": "7.1.7",
- "resolved": "https://registry.npmjs.org/react-map-gl/-/react-map-gl-7.1.7.tgz",
- "integrity": "sha512-mwjc0obkBJOXCcoXQr3VoLqmqwo9vS4bXfbGsdxXzEgVCv/PM0v+1QggL7W0d/ccIy+VCjbXNlGij+PENz6VNg==",
+ "version": "7.1.8",
+ "resolved": "https://registry.npmjs.org/react-map-gl/-/react-map-gl-7.1.8.tgz",
+ "integrity": "sha512-zwF16XMOdOKH4py5ehS1bgQIChqW8UN3b1bXps+JnADbYLSbOoUPQ3tNw0EZ2OTBWArR5aaQlhlEqg4lE47T8A==",
+ "license": "MIT",
"dependencies": {
"@maplibre/maplibre-gl-style-spec": "^19.2.1",
"@types/mapbox-gl": ">=1.0.0"
@@ -9201,6 +9362,7 @@
"version": "19.3.3",
"resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-19.3.3.tgz",
"integrity": "sha512-cOZZOVhDSulgK0meTsTkmNXb1ahVvmTmWmfx9gRBwc6hq98wS9JP35ESIoNq3xqEan+UN+gn8187Z6E4NKhLsw==",
+ "license": "ISC",
"dependencies": {
"@mapbox/jsonlint-lines-primitives": "~2.0.2",
"@mapbox/unitbezier": "^0.0.1",
@@ -9218,7 +9380,8 @@
"node_modules/react-map-gl/node_modules/json-stringify-pretty-compact": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz",
- "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA=="
+ "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==",
+ "license": "MIT"
},
"node_modules/react-refresh": {
"version": "0.14.2",
@@ -9455,10 +9618,11 @@
}
},
"node_modules/rrweb-cssom": {
- "version": "0.7.1",
- "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz",
- "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==",
- "dev": true
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz",
+ "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/run-async": {
"version": "2.4.1",
@@ -10386,15 +10550,16 @@
}
},
"node_modules/ts-api-utils": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz",
- "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz",
+ "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=16"
+ "node": ">=18.12"
},
"peerDependencies": {
- "typescript": ">=4.2.0"
+ "typescript": ">=4.8.4"
}
},
"node_modules/ts-log": {
@@ -10531,10 +10696,11 @@
}
},
"node_modules/typescript": {
- "version": "5.7.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
- "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
+ "version": "5.7.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
+ "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
"dev": true,
+ "license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -10544,14 +10710,15 @@
}
},
"node_modules/typescript-eslint": {
- "version": "8.19.0",
- "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.19.0.tgz",
- "integrity": "sha512-Ni8sUkVWYK4KAcTtPjQ/UTiRk6jcsuDhPpxULapUDi8A/l8TSBk+t1GtJA1RsCzIJg0q6+J7bf35AwQigENWRQ==",
+ "version": "8.19.1",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.19.1.tgz",
+ "integrity": "sha512-LKPUQpdEMVOeKluHi8md7rwLcoXHhwvWp3x+sJkMuq3gGm9yaYJtPo8sRZSblMFJ5pcOGCAak/scKf1mvZDlQw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/eslint-plugin": "8.19.0",
- "@typescript-eslint/parser": "8.19.0",
- "@typescript-eslint/utils": "8.19.0"
+ "@typescript-eslint/eslint-plugin": "8.19.1",
+ "@typescript-eslint/parser": "8.19.1",
+ "@typescript-eslint/utils": "8.19.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -10756,12 +10923,13 @@
}
},
"node_modules/vite": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.3.tgz",
- "integrity": "sha512-Cmuo5P0ENTN6HxLSo6IHsjCLn/81Vgrp81oaiFFMRa8gGDj5xEjIcEpf2ZymZtZR8oU0P2JX5WuUp/rlXcHkAw==",
+ "version": "6.0.7",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.7.tgz",
+ "integrity": "sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "esbuild": "^0.24.0",
+ "esbuild": "^0.24.2",
"postcss": "^8.4.49",
"rollup": "^4.23.0"
},
diff --git a/client/package.json b/client/package.json
index b16a1fe8527..78180de6b6a 100644
--- a/client/package.json
+++ b/client/package.json
@@ -26,21 +26,21 @@
"react": "19.0.0",
"react-bootstrap": "2.10.7",
"react-dom": "19.0.0",
- "react-map-gl": "7.1.7"
+ "react-map-gl": "7.1.8"
},
"devDependencies": {
- "@eslint/compat": "1.2.4",
- "@eslint/js": "9.17.0",
+ "@eslint/compat": "1.2.5",
+ "@eslint/js": "9.18.0",
"@graphql-codegen/cli": "5.0.3",
"@graphql-codegen/client-preset": "4.5.1",
"@graphql-codegen/introspection": "4.0.3",
"@parcel/watcher": "2.5.0",
"@testing-library/react": "16.1.0",
- "@types/react": "19.0.1",
+ "@types/react": "19.0.4",
"@types/react-dom": "19.0.2",
"@vitejs/plugin-react": "4.3.4",
"@vitest/coverage-v8": "2.1.8",
- "eslint": "9.17.0",
+ "eslint": "9.18.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-jsx-a11y": "6.10.2",
@@ -48,11 +48,11 @@
"eslint-plugin-react-hooks": "5.1.0",
"eslint-plugin-react-refresh": "0.4.16",
"globals": "15.14.0",
- "jsdom": "25.0.1",
+ "jsdom": "26.0.0",
"prettier": "3.4.2",
- "typescript": "5.7.2",
- "typescript-eslint": "8.19.0",
- "vite": "6.0.3",
+ "typescript": "5.7.3",
+ "typescript-eslint": "8.19.1",
+ "vite": "6.0.7",
"vitest": "2.1.8"
}
}
diff --git a/doc/templates/StopConsolidation.md b/doc/templates/StopConsolidation.md
index 70866882bd1..ef32a3c29d6 100644
--- a/doc/templates/StopConsolidation.md
+++ b/doc/templates/StopConsolidation.md
@@ -32,7 +32,7 @@ This has the following consequences
- It makes real-time trip updates referencing a stop id much more complicated and in many cases
impossible to resolve.
- You can only reference a stop by its sequence, which only works in GTFS-RT, not Siri.
+ You can only reference a stop by its sequence, which only works in GTFS-RT, not SIRI.
- Fare calculation and transfers are unlikely to work as expected.
diff --git a/doc/templates/UpdaterConfig.md b/doc/templates/UpdaterConfig.md
index aab5631e6e2..21db7bdb6a4 100644
--- a/doc/templates/UpdaterConfig.md
+++ b/doc/templates/UpdaterConfig.md
@@ -82,8 +82,8 @@ GBFS form factors:
## Other updaters in sandboxes
- [Vehicle parking](sandbox/VehicleParking.md)
-- [Siri over HTTP](sandbox/siri/SiriUpdater.md)
-- [Siri over Google Cloud PubSub](sandbox/siri/SiriGooglePubSubUpdater.md)
-- [Siri over Azure Message Bus](sandbox/siri/SiriAzureUpdater.md)
+- [SIRI over HTTP](sandbox/siri/SiriUpdater.md)
+- [SIRI over Google Cloud PubSub](sandbox/siri/SiriGooglePubSubUpdater.md)
+- [SIRI over Azure Message Bus](sandbox/siri/SiriAzureUpdater.md)
- [VehicleRentalServiceDirectory](sandbox/VehicleRentalServiceDirectory.md)
diff --git a/doc/templates/sandbox/siri/SiriAzureUpdater.md b/doc/templates/sandbox/siri/SiriAzureUpdater.md
index 85e22e30bda..5e9e1065519 100644
--- a/doc/templates/sandbox/siri/SiriAzureUpdater.md
+++ b/doc/templates/sandbox/siri/SiriAzureUpdater.md
@@ -1,6 +1,6 @@
-# Siri Azure Updater
+# SIRI Azure Updater
-This is a sandbox extension developed by Skånetrafiken that allows OTP to fetch Siri ET & SX messages
+This is a sandbox extension developed by Skånetrafiken that allows OTP to fetch SIRI ET & SX messages
through *Azure Service Bus*.
It also enables OTP to download historical data from en HTTP endpoint on startup.
@@ -17,11 +17,11 @@ Documentation available [here](../../examples/skanetrafiken/Readme.md).
To enable the SIRI updater you need to add it to the updaters section of the `router-config.json`.
-### Siri Azure ET Updater
+### SIRI Azure ET Updater
-### Siri Azure SX Updater
+### SIRI Azure SX Updater
diff --git a/doc/templates/sandbox/siri/SiriGooglePubSubUpdater.md b/doc/templates/sandbox/siri/SiriGooglePubSubUpdater.md
index 09fd3996bef..9d3fff5e00d 100644
--- a/doc/templates/sandbox/siri/SiriGooglePubSubUpdater.md
+++ b/doc/templates/sandbox/siri/SiriGooglePubSubUpdater.md
@@ -1,4 +1,4 @@
-# Siri-ET Google PubSub Updater
+# SIRI-ET Google PubSub Updater
Support for consuming SIRI-ET messages over a Google Cloud PubSub subscription.
Similarly to the SIRI-ET HTTP updater, this updater is developed to support the Nordic SIRI profile
@@ -23,7 +23,7 @@ the [Norwegian SIRI profile](https://enturas.atlassian.net/wiki/spaces/PUBLIC/pa
To enable the SIRI-ET Google PubSub updater you need to add it to the updaters section
of the `router-config.json`.
-### Siri-ET via Google PubSub
+### SIRI-ET via Google PubSub
diff --git a/doc/templates/sandbox/siri/SiriUpdater.md b/doc/templates/sandbox/siri/SiriUpdater.md
index f695d304475..bed90ded3a3 100644
--- a/doc/templates/sandbox/siri/SiriUpdater.md
+++ b/doc/templates/sandbox/siri/SiriUpdater.md
@@ -1,35 +1,50 @@
-# Siri Updater
+# SIRI Updaters
-Support for consuming SIRI ET and SX messages. The updater is developed to support the Nordic
-SIRI profile which is a subset of the SIRI specification.
+Support for consuming SIRI ET and SX messages via HTTPS. The updaters aim to support the [Nordic
+and EPIP SIRI profiles](../../features-explained/Netex-Siri-Compatibility.md) which
+are subsets of the SIRI specification.
+
+For more documentation about the Norwegian profile and data, go to
+the [Entur Real-Time Data](https://developer.entur.org/pages-real-time-intro) documentation and
+the [Norwegian SIRI profile](https://enturas.atlassian.net/wiki/spaces/PUBLIC/pages/637370420/Norwegian+SIRI+profile).
## Contact Info
- Lasse Tyrihjell, Entur, Norway
-
-## Documentation
-
-This updater consumes SIRI real time information. It is developed by Entur and supports the Nordic
-Profile for SIRI. It should be possible to develop it further to support a broader set of the SIRI
-specification.
-
-For more documentation goto
-the [Entur Real-Time Data](https://developer.entur.org/pages-real-time-intro) documentation and
-the [Norwegian SIRI profile](https://enturas.atlassian.net/wiki/spaces/PUBLIC/pages/637370420/Norwegian+SIRI+profile)
-.
+- Leonard Ehrenfried, Germany
## Configuration
-To enable the SIRI updater you need to add it to the updaters section of the `router-config.json`.
+To enable the SIRI updater you need to add it to the `updaters` section of the `router-config.json`.
-### Siri-ET via HTTPS
+### SIRI-ET Request/Response via HTTPS
-### Siri-SX via HTTPS
+### SIRI-SX Request/Response via HTTPS
+### SIRI-ET Lite
+
+SIRI Lite is [not very well](https://nextcloud.leonard.io/s/2tdYdmYBGtLQMfi/download?path=&files=Proposition-Profil-SIRI-Lite-initial-v1-3%20en.pdf)
+[specified](https://normes.transport.data.gouv.fr/normes/siri/profil-france/#protocoles-d%C3%A9change-des-donn%C3%A9es-siri),
+but this updater supports the following definition:
+
+Fetching XML-formatted SIRI messages as single GET request rather than the more common request/response
+flow. This means that the XML feed must contain all updates for all trips, just like it is the case
+for GTFS-RT TripUpdates.
+
+
+
+### SIRI-SX Lite
+
+This updater follows the same definition of SIRI Lite as the SIRI-ET one: it downloads the entire
+feed in a single HTTP GET request.
+
+
+
+
## Changelog
- Initial version of SIRI updater (October 2019)
diff --git a/doc/user/Changelog.md b/doc/user/Changelog.md
index a3d798051a7..5f4e1a054e2 100644
--- a/doc/user/Changelog.md
+++ b/doc/user/Changelog.md
@@ -68,6 +68,10 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle
- Add default penalty to all car API modes [#6302](https://github.com/opentripplanner/OpenTripPlanner/pull/6302)
- Make flex linking work together with boarding locations [#6311](https://github.com/opentripplanner/OpenTripPlanner/pull/6311)
- Add fallback name for corridors [#6303](https://github.com/opentripplanner/OpenTripPlanner/pull/6303)
+- Implement SIRI Lite [#6284](https://github.com/opentripplanner/OpenTripPlanner/pull/6284)
+- Add a matcher API for filters in the transit service used for regularStop lookup [#6234](https://github.com/opentripplanner/OpenTripPlanner/pull/6234)
+- Make all polling updaters wait for graph update finish [#6262](https://github.com/opentripplanner/OpenTripPlanner/pull/6262)
+- When using ScheduledTransitLeg's copy builder, also copy alerts [#6368](https://github.com/opentripplanner/OpenTripPlanner/pull/6368)
[](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE)
## 2.6.0 (2024-09-18)
@@ -413,7 +417,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle
- Preserve language in SIRI/GTFS-RT alert messages [#4117](https://github.com/opentripplanner/OpenTripPlanner/pull/4117)
- Use board/alight cost only for transits [#4079](https://github.com/opentripplanner/OpenTripPlanner/pull/4079)
- Improve SIRI real-time performance by reducing stopPattern duplicates [#4038](https://github.com/opentripplanner/OpenTripPlanner/pull/4038)
-- Siri updaters for Azure ServiceBus [#4106](https://github.com/opentripplanner/OpenTripPlanner/pull/4106)
+- SIRI updaters for Azure ServiceBus [#4106](https://github.com/opentripplanner/OpenTripPlanner/pull/4106)
- Fallback to recorded/expected arrival/departure time if other one is missing in SIRI-ET [#4055](https://github.com/opentripplanner/OpenTripPlanner/pull/4055)
- Allow overriding GBFS system_id with configuration [#4147](https://github.com/opentripplanner/OpenTripPlanner/pull/4147)
- Fix error with transfer-slack and GTFS minTransferTime [#4120](https://github.com/opentripplanner/OpenTripPlanner/pull/4120)
@@ -421,7 +425,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle
- Don't indicate stop has been updated when NO_DATA is defined [#3962](https://github.com/opentripplanner/OpenTripPlanner/pull/3962)
- Implement nearby searches for car and bicycle parking [#4165](https://github.com/opentripplanner/OpenTripPlanner/pull/4165)
- Do not link cars to stop vertices in routing [#4166](https://github.com/opentripplanner/OpenTripPlanner/pull/4166)
-- Add Siri real-time occupancy info [#4180](https://github.com/opentripplanner/OpenTripPlanner/pull/4180)
+- Add SIRI real-time occupancy info [#4180](https://github.com/opentripplanner/OpenTripPlanner/pull/4180)
- Add gtfs stop description translations [#4158](https://github.com/opentripplanner/OpenTripPlanner/pull/4158)
- Add option to discard min transfer times [#4195](https://github.com/opentripplanner/OpenTripPlanner/pull/4195)
- Use negative delay from first stop in a GTFS RT update in previous stop times when required [#4035](https://github.com/opentripplanner/OpenTripPlanner/pull/4035)
diff --git a/doc/user/Configuration.md b/doc/user/Configuration.md
index bec637fe51c..326ccfa8a77 100644
--- a/doc/user/Configuration.md
+++ b/doc/user/Configuration.md
@@ -221,39 +221,40 @@ Here is a list of all features which can be toggled on/off and their default val
-| Feature | Description | Enabled by default | Sandbox |
-|--------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------:|:-------:|
-| `APIBikeRental` | Enable the bike rental endpoint. | ✓️ | |
-| `APIServerInfo` | Enable the server info endpoint. | ✓️ | |
-| `APIUpdaterStatus` | Enable endpoint for graph updaters status. | ✓️ | |
-| `IncludeEmptyRailStopsInTransfers` | Turning this on guarantees that Rail stops without scheduled departures still get included when generating transfers using `ConsiderPatternsForDirectTransfers`. It is common for stops to be assign at real-time for Rail. Turning this on will help to avoid dropping transfers which are needed, when the stop is in use later. Turning this on, if ConsiderPatternsForDirectTransfers is off has no effect. | | |
-| `ConsiderPatternsForDirectTransfers` | Enable limiting transfers so that there is only a single transfer to each pattern. | ✓️ | |
-| `DebugUi` | Enable the debug GraphQL client and web UI and located at the root of the web server as well as the debug map tiles it uses. Be aware that the map tiles are not a stable API and can change without notice. Use the [vector tiles feature if](sandbox/MapboxVectorTilesApi.md) you want a stable map tiles API. | ✓️ | |
-| `ExtraTransferLegOnSameStop` | Should there be a transfer leg when transferring on the very same stop. Note that for in-seat/interlined transfers no transfer leg will be generated. | | |
-| `FloatingBike` | Enable floating bike routing. | ✓️ | |
-| `GtfsGraphQlApi` | Enable the [GTFS GraphQL API](apis/GTFS-GraphQL-API.md). | ✓️ | |
-| `MinimumTransferTimeIsDefinitive` | If the minimum transfer time is a lower bound (default) or the definitive time for the transfer. Set this to `true` if you want to set a transfer time lower than what OTP derives from OSM data. | | |
-| `OptimizeTransfers` | OTP will inspect all itineraries found and optimize where (which stops) the transfer will happen. Waiting time, priority and guaranteed transfers are taken into account. | ✓️ | |
-| `ParallelRouting` | Enable performing parts of the trip planning in parallel. | | |
-| `TransferConstraints` | Enforce transfers to happen according to the _transfers.txt_ (GTFS) and Interchanges (NeTEx). Turning this _off_ will increase the routing performance a little. | ✓️ | |
-| `TransmodelGraphQlApi` | Enable the [Transmodel (NeTEx) GraphQL API](apis/TransmodelApi.md). | ✓️ | ✓️ |
-| `ActuatorAPI` | Endpoint for actuators (service health status). | | ✓️ |
-| `AsyncGraphQLFetchers` | Whether the @async annotation in the GraphQL schema should lead to the fetch being executed asynchronously. This allows batch or alias queries to run in parallel at the cost of consuming extra threads. | | |
-| `Co2Emissions` | Enable the emissions sandbox module. | | ✓️ |
-| `DataOverlay` | Enable usage of data overlay when calculating costs for the street network. | | ✓️ |
-| `FaresV2` | Enable import of GTFS-Fares v2 data. | | ✓️ |
-| `FlexRouting` | Enable FLEX routing. | | ✓️ |
-| `GoogleCloudStorage` | Enable Google Cloud Storage integration. | | ✓️ |
-| `LegacyRestApi` | Enable legacy REST API. This API will be removed in the future. | | ✓️ |
-| `MultiCriteriaGroupMaxFilter` | Keep the best itinerary with respect to each criteria used in the transit-routing search. For example the itinerary with the lowest cost, fewest transfers, and each unique transit-group (transit-group-priority) is kept, even if the max-limit is exceeded. This is turned off by default for now, until this feature is well tested. | | |
-| `RealtimeResolver` | When routing with ignoreRealtimeUpdates=true, add an extra step which populates results with real-time data | | ✓️ |
-| `ReportApi` | Enable the report API. | | ✓️ |
-| `RestAPIPassInDefaultConfigAsJson` | Enable a default RouteRequest to be passed in as JSON on the REST API - FOR DEBUGGING ONLY! | | |
-| `SandboxAPIGeocoder` | Enable the Geocoder API. | | ✓️ |
-| `SandboxAPIMapboxVectorTilesApi` | Enable Mapbox vector tiles API. | | ✓️ |
-| `SandboxAPIParkAndRideApi` | Enable park-and-ride endpoint. | | ✓️ |
-| `Sorlandsbanen` | Include train Sørlandsbanen in results when searching in south of Norway. Only relevant in Norway. | | ✓️ |
-| `TransferAnalyzer` | Analyze transfers during graph build. | | ✓️ |
+| Feature | Description | Enabled by default | Sandbox |
+|---------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------:|:-------:|
+| `APIBikeRental` | Enable the bike rental endpoint. | ✓️ | |
+| `APIServerInfo` | Enable the server info endpoint. | ✓️ | |
+| `APIUpdaterStatus` | Enable endpoint for graph updaters status. | ✓️ | |
+| `IncludeEmptyRailStopsInTransfers` | Turning this on guarantees that Rail stops without scheduled departures still get included when generating transfers using `ConsiderPatternsForDirectTransfers`. It is common for stops to be assign at real-time for Rail. Turning this on will help to avoid dropping transfers which are needed, when the stop is in use later. Turning this on, if ConsiderPatternsForDirectTransfers is off has no effect. | | |
+| `ConsiderPatternsForDirectTransfers` | Enable limiting transfers so that there is only a single transfer to each pattern. | ✓️ | |
+| `DebugUi` | Enable the debug GraphQL client and web UI and located at the root of the web server as well as the debug map tiles it uses. Be aware that the map tiles are not a stable API and can change without notice. Use the [vector tiles feature if](sandbox/MapboxVectorTilesApi.md) you want a stable map tiles API. | ✓️ | |
+| `ExtraTransferLegOnSameStop` | Should there be a transfer leg when transferring on the very same stop. Note that for in-seat/interlined transfers no transfer leg will be generated. | | |
+| `FloatingBike` | Enable floating bike routing. | ✓️ | |
+| `GtfsGraphQlApi` | Enable the [GTFS GraphQL API](apis/GTFS-GraphQL-API.md). | ✓️ | |
+| `MinimumTransferTimeIsDefinitive` | If the minimum transfer time is a lower bound (default) or the definitive time for the transfer. Set this to `true` if you want to set a transfer time lower than what OTP derives from OSM data. | | |
+| `OptimizeTransfers` | OTP will inspect all itineraries found and optimize where (which stops) the transfer will happen. Waiting time, priority and guaranteed transfers are taken into account. | ✓️ | |
+| `ParallelRouting` | Enable performing parts of the trip planning in parallel. | | |
+| `TransferConstraints` | Enforce transfers to happen according to the _transfers.txt_ (GTFS) and Interchanges (NeTEx). Turning this _off_ will increase the routing performance a little. | ✓️ | |
+| `TransmodelGraphQlApi` | Enable the [Transmodel (NeTEx) GraphQL API](apis/TransmodelApi.md). | ✓️ | ✓️ |
+| `ActuatorAPI` | Endpoint for actuators (service health status). | | ✓️ |
+| `AsyncGraphQLFetchers` | Whether the @async annotation in the GraphQL schema should lead to the fetch being executed asynchronously. This allows batch or alias queries to run in parallel at the cost of consuming extra threads. | | |
+| `WaitForGraphUpdateInPollingUpdaters` | Make all polling updaters wait for graph updates to complete before finishing. If this is not enabled, the updaters will finish after submitting the task to update the graph. | ✓️ | |
+| `Co2Emissions` | Enable the emissions sandbox module. | | ✓️ |
+| `DataOverlay` | Enable usage of data overlay when calculating costs for the street network. | | ✓️ |
+| `FaresV2` | Enable import of GTFS-Fares v2 data. | | ✓️ |
+| `FlexRouting` | Enable FLEX routing. | | ✓️ |
+| `GoogleCloudStorage` | Enable Google Cloud Storage integration. | | ✓️ |
+| `LegacyRestApi` | Enable legacy REST API. This API will be removed in the future. | | ✓️ |
+| `MultiCriteriaGroupMaxFilter` | Keep the best itinerary with respect to each criteria used in the transit-routing search. For example the itinerary with the lowest cost, fewest transfers, and each unique transit-group (transit-group-priority) is kept, even if the max-limit is exceeded. This is turned off by default for now, until this feature is well tested. | | |
+| `RealtimeResolver` | When routing with ignoreRealtimeUpdates=true, add an extra step which populates results with real-time data | | ✓️ |
+| `ReportApi` | Enable the report API. | | ✓️ |
+| `RestAPIPassInDefaultConfigAsJson` | Enable a default RouteRequest to be passed in as JSON on the REST API - FOR DEBUGGING ONLY! | | |
+| `SandboxAPIGeocoder` | Enable the Geocoder API. | | ✓️ |
+| `SandboxAPIMapboxVectorTilesApi` | Enable Mapbox vector tiles API. | | ✓️ |
+| `SandboxAPIParkAndRideApi` | Enable park-and-ride endpoint. | | ✓️ |
+| `Sorlandsbanen` | Include train Sørlandsbanen in results when searching in south of Norway. Only relevant in Norway. | | ✓️ |
+| `TransferAnalyzer` | Analyze transfers during graph build. | | ✓️ |
diff --git a/doc/user/RouterConfiguration.md b/doc/user/RouterConfiguration.md
index 7dae97fd74c..82d14f36392 100644
--- a/doc/user/RouterConfiguration.md
+++ b/doc/user/RouterConfiguration.md
@@ -878,6 +878,17 @@ Used to group requests when monitoring OTP.
"feedId" : "parking",
"sourceType" : "siri-fm",
"url" : "https://transmodel.api.opendatahub.com/siri-lite/fm/parking"
+ },
+ {
+ "type" : "siri-et-lite",
+ "feedId" : "sta",
+ "url" : "https://example.com/siri-lite/estimated-timetable/xml",
+ "fuzzyTripMatching" : true
+ },
+ {
+ "type" : "siri-sx-lite",
+ "feedId" : "sta",
+ "url" : "https://example.com/siri-lite/situation-exchange/xml"
}
],
"rideHailingServices" : [
diff --git a/doc/user/UpdaterConfig.md b/doc/user/UpdaterConfig.md
index f61cce12f54..068b61f112e 100644
--- a/doc/user/UpdaterConfig.md
+++ b/doc/user/UpdaterConfig.md
@@ -427,8 +427,8 @@ This is temporary and will be removed in a future version of OTP. Use this to sp
## Other updaters in sandboxes
- [Vehicle parking](sandbox/VehicleParking.md)
-- [Siri over HTTP](sandbox/siri/SiriUpdater.md)
-- [Siri over Google Cloud PubSub](sandbox/siri/SiriGooglePubSubUpdater.md)
-- [Siri over Azure Message Bus](sandbox/siri/SiriAzureUpdater.md)
+- [SIRI over HTTP](sandbox/siri/SiriUpdater.md)
+- [SIRI over Google Cloud PubSub](sandbox/siri/SiriGooglePubSubUpdater.md)
+- [SIRI over Azure Message Bus](sandbox/siri/SiriAzureUpdater.md)
- [VehicleRentalServiceDirectory](sandbox/VehicleRentalServiceDirectory.md)
diff --git a/doc/user/examples/skanetrafiken/Readme.md b/doc/user/examples/skanetrafiken/Readme.md
index a611c839140..acaf212719a 100644
--- a/doc/user/examples/skanetrafiken/Readme.md
+++ b/doc/user/examples/skanetrafiken/Readme.md
@@ -38,7 +38,7 @@ To reduce graph size, only data for northern part of Denmark is used.
## Real-time
The **Azure Service Bus** is used to propagate SIRI SX and ET real-time messages to OTP.
-This is solved through Siri Azure updaters that Skånetrafiken had implemented in OTP. There are
+This is solved through SIRI Azure updaters that Skånetrafiken had implemented in OTP. There are
separate updaters for SIRI SX and ET.
Those updaters are used to provide data for Swedish traffic (NeTEx). Right now, there is no
connection to any real-time source for danish traffic (GTFS data).
@@ -77,7 +77,7 @@ Those two parameters are used to define time boundaries for the messages.
Both endpoints generate XML response which is an SIRI object containing SX or ET messages. Messages
are
-formatted according to Siri Nordic Profile.
+formatted according to SIRI Nordic Profile.
Since in SIRI ET standard each messages contains all necessary data, Skånetrafikens implementation
of the
endpoint returns only the last message
diff --git a/doc/user/features-explained/Netex-Siri-Compatibility.md b/doc/user/features-explained/Netex-Siri-Compatibility.md
index 731011be8e0..10c64f6a5c0 100644
--- a/doc/user/features-explained/Netex-Siri-Compatibility.md
+++ b/doc/user/features-explained/Netex-Siri-Compatibility.md
@@ -12,7 +12,7 @@ Different countries are currently using different incompatible "profiles" of NeT
underway to converge on a single European standard profile. This is based in large part on the
Nordic profile used by Entur.
-The Nordic profile is the only profile that has been thoroughly tested in production in OTP and is
+The Nordic profile is the only one that has been thoroughly tested in production in OTP and is
used in Norway, Finland and Sweden.
### EPIP
@@ -22,7 +22,7 @@ is an attempt to unify other country profiles and support in OTP is adequate, bu
to tell how much of EPIP is supported since it is a very large profile. The current status
of the support is tracked on [Github](https://github.com/opentripplanner/OpenTripPlanner/issues/3640).
-Sometimes it is difficult to tell if a file conforms to EPIP so to find out, you can run the following
+Sometimes it is not easy to figure out if a file conforms to EPIP so to find out, you can run the following
commands:
```
diff --git a/doc/user/sandbox/StopConsolidation.md b/doc/user/sandbox/StopConsolidation.md
index d0e18a9ce30..547f3200296 100644
--- a/doc/user/sandbox/StopConsolidation.md
+++ b/doc/user/sandbox/StopConsolidation.md
@@ -32,7 +32,7 @@ This has the following consequences
- It makes real-time trip updates referencing a stop id much more complicated and in many cases
impossible to resolve.
- You can only reference a stop by its sequence, which only works in GTFS-RT, not Siri.
+ You can only reference a stop by its sequence, which only works in GTFS-RT, not SIRI.
- Fare calculation and transfers are unlikely to work as expected.
diff --git a/doc/user/sandbox/siri/SiriAzureUpdater.md b/doc/user/sandbox/siri/SiriAzureUpdater.md
index 898e70d7b84..02d602c48d2 100644
--- a/doc/user/sandbox/siri/SiriAzureUpdater.md
+++ b/doc/user/sandbox/siri/SiriAzureUpdater.md
@@ -1,6 +1,6 @@
-# Siri Azure Updater
+# SIRI Azure Updater
-This is a sandbox extension developed by Skånetrafiken that allows OTP to fetch Siri ET & SX messages
+This is a sandbox extension developed by Skånetrafiken that allows OTP to fetch SIRI ET & SX messages
through *Azure Service Bus*.
It also enables OTP to download historical data from en HTTP endpoint on startup.
@@ -17,7 +17,7 @@ Documentation available [here](../../examples/skanetrafiken/Readme.md).
To enable the SIRI updater you need to add it to the updaters section of the `router-config.json`.
-### Siri Azure ET Updater
+### SIRI Azure ET Updater
@@ -105,7 +105,7 @@ Has to be present for authenticationMethod SharedAccessKey. This should be Prima
-### Siri Azure SX Updater
+### SIRI Azure SX Updater
diff --git a/doc/user/sandbox/siri/SiriGooglePubSubUpdater.md b/doc/user/sandbox/siri/SiriGooglePubSubUpdater.md
index 5232696ad9b..ed09522b224 100644
--- a/doc/user/sandbox/siri/SiriGooglePubSubUpdater.md
+++ b/doc/user/sandbox/siri/SiriGooglePubSubUpdater.md
@@ -1,4 +1,4 @@
-# Siri-ET Google PubSub Updater
+# SIRI-ET Google PubSub Updater
Support for consuming SIRI-ET messages over a Google Cloud PubSub subscription.
Similarly to the SIRI-ET HTTP updater, this updater is developed to support the Nordic SIRI profile
@@ -23,7 +23,7 @@ the [Norwegian SIRI profile](https://enturas.atlassian.net/wiki/spaces/PUBLIC/pa
To enable the SIRI-ET Google PubSub updater you need to add it to the updaters section
of the `router-config.json`.
-### Siri-ET via Google PubSub
+### SIRI-ET via Google PubSub
diff --git a/doc/user/sandbox/siri/SiriUpdater.md b/doc/user/sandbox/siri/SiriUpdater.md
index 28f2f9a85db..a6f7781e293 100644
--- a/doc/user/sandbox/siri/SiriUpdater.md
+++ b/doc/user/sandbox/siri/SiriUpdater.md
@@ -1,28 +1,23 @@
-# Siri Updater
+# SIRI Updaters
-Support for consuming SIRI ET and SX messages. The updater is developed to support the Nordic
-SIRI profile which is a subset of the SIRI specification.
+Support for consuming SIRI ET and SX messages via HTTPS. The updaters aim to support the [Nordic
+and EPIP SIRI profiles](../../features-explained/Netex-Siri-Compatibility.md) which
+are subsets of the SIRI specification.
+
+For more documentation about the Norwegian profile and data, go to
+the [Entur Real-Time Data](https://developer.entur.org/pages-real-time-intro) documentation and
+the [Norwegian SIRI profile](https://enturas.atlassian.net/wiki/spaces/PUBLIC/pages/637370420/Norwegian+SIRI+profile).
## Contact Info
- Lasse Tyrihjell, Entur, Norway
-
-## Documentation
-
-This updater consumes SIRI real time information. It is developed by Entur and supports the Nordic
-Profile for SIRI. It should be possible to develop it further to support a broader set of the SIRI
-specification.
-
-For more documentation goto
-the [Entur Real-Time Data](https://developer.entur.org/pages-real-time-intro) documentation and
-the [Norwegian SIRI profile](https://enturas.atlassian.net/wiki/spaces/PUBLIC/pages/637370420/Norwegian+SIRI+profile)
-.
+- Leonard Ehrenfried, Germany
## Configuration
-To enable the SIRI updater you need to add it to the updaters section of the `router-config.json`.
+To enable the SIRI updater you need to add it to the `updaters` section of the `router-config.json`.
-### Siri-ET via HTTPS
+### SIRI-ET Request/Response via HTTPS
@@ -89,7 +84,7 @@ HTTP headers to add to the request. Any header key, value can be inserted.
-### Siri-SX via HTTPS
+### SIRI-SX Request/Response via HTTPS
@@ -166,6 +161,148 @@ HTTP headers to add to the request. Any header key, value can be inserted.
+### SIRI-ET Lite
+
+SIRI Lite is [not very well](https://nextcloud.leonard.io/s/2tdYdmYBGtLQMfi/download?path=&files=Proposition-Profil-SIRI-Lite-initial-v1-3%20en.pdf)
+[specified](https://normes.transport.data.gouv.fr/normes/siri/profil-france/#protocoles-d%C3%A9change-des-donn%C3%A9es-siri),
+but this updater supports the following definition:
+
+Fetching XML-formatted SIRI messages as single GET request rather than the more common request/response
+flow. This means that the XML feed must contain all updates for all trips, just like it is the case
+for GTFS-RT TripUpdates.
+
+
+
+
+| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since |
+|----------------------------|:---------------:|----------------------------------------------------------------------------|:----------:|---------------|:-----:|
+| type = "siri-et-lite" | `enum` | The type of the updater. | *Required* | | 1.5 |
+| feedId | `string` | The ID of the feed to apply the updates to. | *Required* | | 2.7 |
+| frequency | `duration` | How often the updates should be retrieved. | *Optional* | `"PT1M"` | 2.7 |
+| fuzzyTripMatching | `boolean` | If the fuzzy trip matcher should be used to match trips. | *Optional* | `false` | 2.7 |
+| timeout | `duration` | The HTTP timeout to download the updates. | *Optional* | `"PT15S"` | 2.7 |
+| [url](#u__15__url) | `uri` | The URL to send the HTTP requests to. | *Required* | | 2.7 |
+| [headers](#u__15__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.7 |
+
+
+##### Parameter details
+
+
url
+
+**Since version:** `2.7` ∙ **Type:** `uri` ∙ **Cardinality:** `Required`
+**Path:** /updaters/[15]
+
+The URL to send the HTTP requests to.
+
+Use the file protocol to set a directory for reading updates from a directory. The file
+loader will look for xml files: '*.xml' in the configured directory. The files are
+renamed by the loader when processed:
+
+ _a.xml_ ➞ _a.xml.inProgress_ ➞ _a.xml.ok_ or _a.xml.failed_
+
+
+
+
headers
+
+**Since version:** `2.7` ∙ **Type:** `map of string` ∙ **Cardinality:** `Optional`
+**Path:** /updaters/[15]
+
+HTTP headers to add to the request. Any header key, value can be inserted.
+
+
+
+##### Example configuration
+
+```JSON
+// router-config.json
+{
+ "updaters" : [
+ {
+ "type" : "siri-et-lite",
+ "feedId" : "sta",
+ "url" : "https://example.com/siri-lite/estimated-timetable/xml",
+ "fuzzyTripMatching" : true
+ }
+ ]
+}
+```
+
+
+
+### SIRI-SX Lite
+
+This updater follows the same definition of SIRI Lite as the SIRI-ET one: it downloads the entire
+feed in a single HTTP GET request.
+
+
+
+
+| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since |
+|----------------------------------|:---------------:|----------------------------------------------------------------------------|:----------:|---------------|:-----:|
+| type = "siri-sx-lite" | `enum` | The type of the updater. | *Required* | | 1.5 |
+| [earlyStart](#u__16__earlyStart) | `duration` | This value is subtracted from the actual validity defined in the message. | *Optional* | `"PT0S"` | 2.0 |
+| feedId | `string` | The ID of the feed to apply the updates to. | *Required* | | 2.7 |
+| frequency | `duration` | How often the updates should be retrieved. | *Optional* | `"PT1M"` | 2.7 |
+| timeout | `duration` | The HTTP timeout to download the updates. | *Optional* | `"PT15S"` | 2.7 |
+| [url](#u__16__url) | `uri` | The URL to send the HTTP requests to. | *Required* | | 2.7 |
+| [headers](#u__16__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.7 |
+
+
+##### Parameter details
+
+
earlyStart
+
+**Since version:** `2.0` ∙ **Type:** `duration` ∙ **Cardinality:** `Optional` ∙ **Default value:** `"PT0S"`
+**Path:** /updaters/[16]
+
+This value is subtracted from the actual validity defined in the message.
+
+Normally the planned departure time is used, so setting this to 10s will cause the
+SX-message to be included in trip-results 10 seconds before the the planned departure
+time.
+
+
url
+
+**Since version:** `2.7` ∙ **Type:** `uri` ∙ **Cardinality:** `Required`
+**Path:** /updaters/[16]
+
+The URL to send the HTTP requests to.
+
+Use the file protocol to set a directory for reading updates from a directory. The file
+loader will look for xml files: '*.xml' in the configured directory. The files are
+renamed by the loader when processed:
+
+ _a.xml_ ➞ _a.xml.inProgress_ ➞ _a.xml.ok_ or _a.xml.failed_
+
+
+
+
headers
+
+**Since version:** `2.7` ∙ **Type:** `map of string` ∙ **Cardinality:** `Optional`
+**Path:** /updaters/[16]
+
+HTTP headers to add to the request. Any header key, value can be inserted.
+
+
+
+##### Example configuration
+
+```JSON
+// router-config.json
+{
+ "updaters" : [
+ {
+ "type" : "siri-sx-lite",
+ "feedId" : "sta",
+ "url" : "https://example.com/siri-lite/situation-exchange/xml"
+ }
+ ]
+}
+```
+
+
+
+
## Changelog
- Initial version of SIRI updater (October 2019)
diff --git a/gtfs-realtime-protobuf/pom.xml b/gtfs-realtime-protobuf/pom.xml
index e4465a4d366..dd3990207c9 100644
--- a/gtfs-realtime-protobuf/pom.xml
+++ b/gtfs-realtime-protobuf/pom.xml
@@ -11,6 +11,7 @@
gtfs-realtime-protobufOpenTripPlanner - GTFS Realtime (protobuf)
+
com.google.protobuf
@@ -46,7 +47,7 @@
- com.google.protobuf:protoc:3.22.0:exe:${os.detected.classifier}
+ com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}
diff --git a/mkdocs.yml b/mkdocs.yml
index 51245f6c3b8..0ebcb7ddd4d 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -91,7 +91,7 @@ nav:
- "Stop Area Relations": 'StopAreas.md'
- "Street Graph Pruning": 'IslandPruning.md'
- Accessibility: 'Accessibility.md'
- - NeTex and Siri compatibility: 'features-explained/Netex-Siri-Compatibility.md'
+ - NeTEx and SIRI compatibility: 'features-explained/Netex-Siri-Compatibility.md'
- "Travel Time Analysis": 'Analysis.md'
- "Logging": "Logging.md"
- Development:
diff --git a/pom.xml b/pom.xml
index d9af6647be7..e68b6ae48a0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -59,20 +59,24 @@
176
+
32.12.532.18.2
- 3.1.9
+ 4.0.5
+ 3.1.105.11.41.14.15.6.01.5.12
- 9.12.0
- 2.0.16
+ 10.1.0
+ 1.14.12.0.15
- 1.27
- 4.0.5
+ 5.6.0
+ 4.28.3
+ 1.28
+ 2.0.16UTF-8opentripplanner/OpenTripPlanner
@@ -397,14 +401,26 @@
-
+
com.google.cloudlibraries-bom
- 26.48.0
+ 26.51.0pomimport
+
+ com.google.protobuf
+ protobuf-java
+ ${protobuf.version}
+
+
+
+ com.google.guava
+ guava
+ 33.4.0-jre
+
+
org.slf4j
@@ -427,11 +443,6 @@
trove4j3.0.3
-
- com.google.guava
- guava
- 33.3.1-jre
-
diff --git a/renovate.json5 b/renovate.json5
index 557857bf54c..100a91d959a 100644
--- a/renovate.json5
+++ b/renovate.json5
@@ -101,7 +101,8 @@
"com.google.cloud:libraries-bom",
"com.google.guava:guava",
"io.micrometer:micrometer-registry-prometheus",
- "io.micrometer:micrometer-registry-influx"
+ "io.micrometer:micrometer-registry-influx",
+ "com.google.protobuf:protobuf-java"
],
"schedule": "on the 7th through 8th day of the month"
},
@@ -142,6 +143,14 @@
"automerge": true,
"schedule": "on the 4th day of the month"
},
+ {
+ "groupName": "Low-risk dependencies (patch)",
+ "matchUpdateTypes": ["patch"],
+ "schedule": ["on the 27th day of the month"],
+ "matchPackageNames": [
+ "org.glassfish.jersey.{/,}**",
+ ]
+ },
{
"description": "give some projects time to publish a changelog before opening the PR",
"matchPackageNames": [