**Since version:** `2.5` ∙ **Type:** `string` ∙ **Cardinality:** `Optional` ∙ **Default value:** `"0s + 1.00 t"`
**Path:** /routingDefaults
-The relax function for transit-priority-groups
+The relax function for transit-group-priority
-A path is considered optimal if the generalized-cost is less than the
-generalized-cost of another path. If this parameter is set, the comparison is relaxed
-further if they belong to different transit-priority-groups.
+A path is considered optimal if the generalized-cost is less than the generalized-cost of
+another path. If this parameter is set, the comparison is relaxed further if they belong
+to different transit groups.
relaxTransitSearchGeneralizedCostAtDestination
@@ -812,22 +812,20 @@ This enables the transfer wait time optimization.
If not enabled generalizedCost function is used to pick the optimal transfer point.
-
transitPriorityGroups
+
transitGroupPriority
**Since version:** `2.5` ∙ **Type:** `object` ∙ **Cardinality:** `Optional`
**Path:** /routingDefaults
-Transit priority groups configuration
+Group transit patterns and give each group a mutual advantage in the Raptor search.
Use this to separate transit patterns into groups. Each group will be given a group-id. A
path (multiple legs) will then have a set of group-ids based on the group-id from each leg.
Hence, two paths with a different set of group-ids will BOTH be optimal unless the cost is
-worse than the relaxation specified in the `relaxTransitPriorityGroup` parameter. This is
+worse than the relaxation specified in the `relaxTransitGroupPriority` parameter. This is
only available in the TransmodelAPI for now.
-Unmatched patterns are put in the BASE priority-group (group id: 0). This group is special.
-If a path only have legs in the base group, then that path dominates other paths, but other
-paths must be better to make it.
+Unmatched patterns are put in the BASE priority-group.
**THIS IS STILL AN EXPERIMENTAL FEATURE - IT MAY CHANGE WITHOUT ANY NOTICE!**
diff --git a/docs/RouterConfiguration.md b/docs/RouterConfiguration.md
index 65f50260ee5..5ca87a2aefa 100644
--- a/docs/RouterConfiguration.md
+++ b/docs/RouterConfiguration.md
@@ -727,6 +727,13 @@ Used to group requests when monitoring OTP.
"Authorization" : "A-Token"
}
},
+ {
+ "type" : "mqtt-gtfs-rt-updater",
+ "url" : "tcp://pred.rt.hsl.fi",
+ "topic" : "gtfsrt/v2/fi/hsl/tu",
+ "feedId" : "HSL",
+ "fuzzyTripMatching" : true
+ },
{
"type" : "vehicle-positions",
"url" : "https://s3.amazonaws.com/kcm-alerts-realtime-prod/vehiclepositions.pb",
@@ -740,10 +747,6 @@ Used to group requests when monitoring OTP.
"position"
]
},
- {
- "type" : "websocket-gtfs-rt-updater",
- "feedId" : "ov"
- },
{
"type" : "siri-et-updater",
"url" : "https://example.com/some/path",
diff --git a/docs/UpdaterConfig.md b/docs/UpdaterConfig.md
index 6b744794642..a819a898240 100644
--- a/docs/UpdaterConfig.md
+++ b/docs/UpdaterConfig.md
@@ -8,8 +8,8 @@
# Updater configuration
-This section covers all options that can be set in the *router-config.json* in the
-[updaters](RouterConfiguration.md) section.
+This section covers options that can be set in the updaters section of `router-config.json`.
+See the parameter summary and examples in the router configuration documentation
Real-time data are those that are not added to OTP during the graph build phase but during runtime.
@@ -164,37 +164,51 @@ HTTP headers to add to the request. Any header key, value can be inserted.
+### Streaming TripUpdates via MQTT
-### TripUpdates via WebSocket
+This updater connects to an MQTT broker and processes TripUpdates in a streaming fashion. This means
+that they will be applied individually in near-realtime rather than in batches at a certain interval.
-This updater doesn't poll a data source but opens a persistent connection to the GTFS-RT provider,
-which then sends incremental updates immediately as they become available.
+This system powers the realtime updates in Helsinki and more information can be found
+[on Github](https://github.com/HSLdevcom/transitdata).
-The [OneBusAway GTFS-realtime exporter project](https://github.com/OneBusAway/onebusaway-gtfs-realtime-exporter)
-provides this kind of streaming, incremental updates over a websocket rather than a single large
-file.
-
-
+
-| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since |
-|-----------------------------------------------------------------------|:---------:|--------------------------|:----------:|----------------------|:-----:|
-| type = "websocket-gtfs-rt-updater" | `enum` | The type of the updater. | *Required* | | 1.5 |
-| [backwardsDelayPropagationType](#u__7__backwardsDelayPropagationType) | `enum` | TODO | *Optional* | `"required-no-data"` | 1.5 |
-| feedId | `string` | TODO | *Required* | | 1.5 |
-| reconnectPeriodSec | `integer` | TODO | *Optional* | `60` | 1.5 |
-| url | `string` | TODO | *Optional* | | 1.5 |
+| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since |
+|-----------------------------------------------------------------------|:---------:|----------------------------------------------|:----------:|----------------------|:-----:|
+| type = "mqtt-gtfs-rt-updater" | `enum` | The type of the updater. | *Required* | | 1.5 |
+| [backwardsDelayPropagationType](#u__6__backwardsDelayPropagationType) | `enum` | How backwards propagation should be handled. | *Optional* | `"required-no-data"` | 2.2 |
+| feedId | `string` | The feed id to apply the updates to. | *Required* | | 2.0 |
+| fuzzyTripMatching | `boolean` | Whether to match trips fuzzily. | *Optional* | `false` | 2.0 |
+| qos | `integer` | QOS level. | *Optional* | `0` | 2.0 |
+| topic | `string` | The topic to subscribe to. | *Required* | | 2.0 |
+| url | `string` | URL of the MQTT broker. | *Required* | | 2.0 |
##### Parameter details
-
backwardsDelayPropagationType
+
backwardsDelayPropagationType
-**Since version:** `1.5` ∙ **Type:** `enum` ∙ **Cardinality:** `Optional` ∙ **Default value:** `"required-no-data"`
-**Path:** /updaters/[7]
+**Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Optional` ∙ **Default value:** `"required-no-data"`
+**Path:** /updaters/[6]
**Enum values:** `required-no-data` | `required` | `always`
-TODO
+How backwards propagation should be handled.
+
+ REQUIRED_NO_DATA:
+ Default value. Only propagates delays backwards when it is required to ensure that the times
+ are increasing, and it sets the NO_DATA flag on the stops so these automatically updated times
+ are not exposed through APIs.
+
+ REQUIRED:
+ Only propagates delays backwards when it is required to ensure that the times are increasing.
+ The updated times are exposed through APIs.
+
+ ALWAYS:
+ Propagates delays backwards on stops with no estimates regardless if it's required or not.
+ The updated times are exposed through APIs.
+
@@ -205,15 +219,17 @@ TODO
{
"updaters" : [
{
- "type" : "websocket-gtfs-rt-updater",
- "feedId" : "ov"
+ "type" : "mqtt-gtfs-rt-updater",
+ "url" : "tcp://pred.rt.hsl.fi",
+ "topic" : "gtfsrt/v2/fi/hsl/tu",
+ "feedId" : "HSL",
+ "fuzzyTripMatching" : true
}
]
}
```
-
-
+
### Vehicle Positions
@@ -231,24 +247,24 @@ The information is downloaded in a single HTTP request and polled regularly.
| frequency | `duration` | How often the positions should be updated. | *Optional* | `"PT1M"` | 2.2 |
| fuzzyTripMatching | `boolean` | Whether to match trips fuzzily. | *Optional* | `false` | 2.5 |
| url | `uri` | The URL of GTFS-RT protobuf HTTP resource to download the positions from. | *Required* | | 2.2 |
-| [features](#u__6__features) | `enum set` | Which features of GTFS RT vehicle positions should be loaded into OTP. | *Optional* | | 2.5 |
-| [headers](#u__6__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 |
+| [features](#u__7__features) | `enum set` | Which features of GTFS RT vehicle positions should be loaded into OTP. | *Optional* | | 2.5 |
+| [headers](#u__7__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 |
##### Parameter details
-
features
+
features
**Since version:** `2.5` ∙ **Type:** `enum set` ∙ **Cardinality:** `Optional`
-**Path:** /updaters/[6]
+**Path:** /updaters/[7]
**Enum values:** `position` | `stop-position` | `occupancy`
Which features of GTFS RT vehicle positions should be loaded into OTP.
-
headers
+
headers
**Since version:** `2.3` ∙ **Type:** `map of string` ∙ **Cardinality:** `Optional`
-**Path:** /updaters/[6]
+**Path:** /updaters/[7]
HTTP headers to add to the request. Any header key, value can be inserted.
diff --git a/pom.xml b/pom.xml
index d2fd4a0515c..e5f86fe5b66 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,7 +56,7 @@
- 135
+ 13630.12.50
@@ -282,7 +282,6 @@
--add-opens java.base/jdk.internal.loader=ALL-UNNAMED
--add-opens java.base/jdk.internal.ref=ALL-UNNAMED
--add-opens java.base/jdk.internal.util=ALL-UNNAMED
- --add-opens java.base/jdk.internal.util.jar=ALL-UNNAMED
--add-opens java.base/jdk.internal.module=ALL-UNNAMED
--add-opens java.base/sun.net.www.protocol.http=ALL-UNNAMED
--add-opens java.base/sun.net.www.protocol.jar=ALL-UNNAMED
@@ -551,20 +550,6 @@
import
-
-
- io.netty
- netty-bom
- 4.1.100.Final
- pom
- import
-
-
@@ -728,7 +713,7 @@
org.mockitomockito-core
- 5.8.0
+ 5.9.0test
@@ -842,13 +827,6 @@
protobuf-java
-
-
-
- org.asynchttpclient
- async-http-client
- 2.12.3
- org.onebusaway
diff --git a/src/client/debug-client-preview/index.html b/src/client/debug-client-preview/index.html
index dfb4915efcc..5f77418dbe6 100644
--- a/src/client/debug-client-preview/index.html
+++ b/src/client/debug-client-preview/index.html
@@ -5,8 +5,8 @@
OTP Debug Client
-
-
+
+
diff --git a/src/test/java/org/opentripplanner/api/mapping/EnumMapperTest.java b/src/ext-test/java/org/opentripplanner/ext/restapi/mapping/EnumMapperTest.java
similarity index 91%
rename from src/test/java/org/opentripplanner/api/mapping/EnumMapperTest.java
rename to src/ext-test/java/org/opentripplanner/ext/restapi/mapping/EnumMapperTest.java
index 184e6b7e6d7..35cc368fec4 100644
--- a/src/test/java/org/opentripplanner/api/mapping/EnumMapperTest.java
+++ b/src/ext-test/java/org/opentripplanner/ext/restapi/mapping/EnumMapperTest.java
@@ -1,4 +1,4 @@
-package org.opentripplanner.api.mapping;
+package org.opentripplanner.ext.restapi.mapping;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -8,9 +8,9 @@
import java.util.Map;
import java.util.function.Function;
import org.junit.jupiter.api.Test;
-import org.opentripplanner.api.model.ApiAbsoluteDirection;
-import org.opentripplanner.api.model.ApiRelativeDirection;
-import org.opentripplanner.api.model.ApiVertexType;
+import org.opentripplanner.ext.restapi.model.ApiAbsoluteDirection;
+import org.opentripplanner.ext.restapi.model.ApiRelativeDirection;
+import org.opentripplanner.ext.restapi.model.ApiVertexType;
import org.opentripplanner.model.plan.AbsoluteDirection;
import org.opentripplanner.model.plan.RelativeDirection;
import org.opentripplanner.model.plan.VertexType;
diff --git a/src/test/java/org/opentripplanner/api/mapping/FareMapperTest.java b/src/ext-test/java/org/opentripplanner/ext/restapi/mapping/FareMapperTest.java
similarity index 95%
rename from src/test/java/org/opentripplanner/api/mapping/FareMapperTest.java
rename to src/ext-test/java/org/opentripplanner/ext/restapi/mapping/FareMapperTest.java
index 44fb360efd2..bd1bd07aa43 100644
--- a/src/test/java/org/opentripplanner/api/mapping/FareMapperTest.java
+++ b/src/ext-test/java/org/opentripplanner/ext/restapi/mapping/FareMapperTest.java
@@ -1,4 +1,4 @@
-package org.opentripplanner.api.mapping;
+package org.opentripplanner.ext.restapi.mapping;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.opentripplanner.model.plan.TestItineraryBuilder.newItinerary;
diff --git a/src/test/java/org/opentripplanner/api/model/ApiApiTravelOptionsMakerTest.java b/src/ext-test/java/org/opentripplanner/ext/restapi/model/ApiTravelOptionsMakerTest.java
similarity index 98%
rename from src/test/java/org/opentripplanner/api/model/ApiApiTravelOptionsMakerTest.java
rename to src/ext-test/java/org/opentripplanner/ext/restapi/model/ApiTravelOptionsMakerTest.java
index 9429151a422..fdcd0a7fe20 100644
--- a/src/test/java/org/opentripplanner/api/model/ApiApiTravelOptionsMakerTest.java
+++ b/src/ext-test/java/org/opentripplanner/ext/restapi/model/ApiTravelOptionsMakerTest.java
@@ -1,4 +1,4 @@
-package org.opentripplanner.api.model;
+package org.opentripplanner.ext.restapi.model;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -11,7 +11,7 @@
/**
* Created by mabu on 28.7.2015.
*/
-public class ApiApiTravelOptionsMakerTest {
+public class ApiTravelOptionsMakerTest {
@Test
public void testMakeOptions() throws Exception {
diff --git a/src/test/java/org/opentripplanner/api/model/ApiWalkStepTest.java b/src/ext-test/java/org/opentripplanner/ext/restapi/model/ApiWalkStepTest.java
similarity index 93%
rename from src/test/java/org/opentripplanner/api/model/ApiWalkStepTest.java
rename to src/ext-test/java/org/opentripplanner/ext/restapi/model/ApiWalkStepTest.java
index 44be1348eee..7f6909bfc2c 100644
--- a/src/test/java/org/opentripplanner/api/model/ApiWalkStepTest.java
+++ b/src/ext-test/java/org/opentripplanner/ext/restapi/model/ApiWalkStepTest.java
@@ -1,8 +1,7 @@
-package org.opentripplanner.api.model;
+package org.opentripplanner.ext.restapi.model;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/org/opentripplanner/api/parameter/ApiRequestModeTest.java b/src/ext-test/java/org/opentripplanner/ext/restapi/parameter/ApiRequestModeTest.java
similarity index 75%
rename from src/test/java/org/opentripplanner/api/parameter/ApiRequestModeTest.java
rename to src/ext-test/java/org/opentripplanner/ext/restapi/parameter/ApiRequestModeTest.java
index caf26510b2a..29cd6b5715c 100644
--- a/src/test/java/org/opentripplanner/api/parameter/ApiRequestModeTest.java
+++ b/src/ext-test/java/org/opentripplanner/ext/restapi/parameter/ApiRequestModeTest.java
@@ -1,10 +1,11 @@
-package org.opentripplanner.api.parameter;
+package org.opentripplanner.ext.restapi.parameter;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.opentripplanner.transit.model.basic.TransitMode.CARPOOL;
import java.util.List;
import org.junit.jupiter.api.Test;
+import org.opentripplanner.api.parameter.ApiRequestMode;
class ApiRequestModeTest {
diff --git a/src/test/java/org/opentripplanner/api/parameter/QualifiedModeSetTest.java b/src/ext-test/java/org/opentripplanner/ext/restapi/parameter/QualifiedModeSetTest.java
similarity index 97%
rename from src/test/java/org/opentripplanner/api/parameter/QualifiedModeSetTest.java
rename to src/ext-test/java/org/opentripplanner/ext/restapi/parameter/QualifiedModeSetTest.java
index ba5a39abe89..ad344713a74 100644
--- a/src/test/java/org/opentripplanner/api/parameter/QualifiedModeSetTest.java
+++ b/src/ext-test/java/org/opentripplanner/ext/restapi/parameter/QualifiedModeSetTest.java
@@ -1,4 +1,4 @@
-package org.opentripplanner.api.parameter;
+package org.opentripplanner.ext.restapi.parameter;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -26,6 +26,8 @@
import jakarta.ws.rs.BadRequestException;
import java.util.Set;
import org.junit.jupiter.api.Test;
+import org.opentripplanner.api.parameter.QualifiedMode;
+import org.opentripplanner.api.parameter.QualifiedModeSet;
import org.opentripplanner.routing.api.request.RequestModes;
import org.opentripplanner.transit.model.basic.TransitMode;
diff --git a/src/test/java/org/opentripplanner/api/parameter/QualifiedModeTest.java b/src/ext-test/java/org/opentripplanner/ext/restapi/parameter/QualifiedModeTest.java
similarity index 82%
rename from src/test/java/org/opentripplanner/api/parameter/QualifiedModeTest.java
rename to src/ext-test/java/org/opentripplanner/ext/restapi/parameter/QualifiedModeTest.java
index e4c4c9448fc..3a682ba40c9 100644
--- a/src/test/java/org/opentripplanner/api/parameter/QualifiedModeTest.java
+++ b/src/ext-test/java/org/opentripplanner/ext/restapi/parameter/QualifiedModeTest.java
@@ -1,4 +1,4 @@
-package org.opentripplanner.api.parameter;
+package org.opentripplanner.ext.restapi.parameter;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -6,6 +6,9 @@
import java.util.Set;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
+import org.opentripplanner.api.parameter.ApiRequestMode;
+import org.opentripplanner.api.parameter.QualifiedMode;
+import org.opentripplanner.api.parameter.Qualifier;
public class QualifiedModeTest {
diff --git a/src/ext/java/org/opentripplanner/ext/geocoder/GeocoderResource.java b/src/ext/java/org/opentripplanner/ext/geocoder/GeocoderResource.java
index d2eafc91e5c..39ed6da297c 100644
--- a/src/ext/java/org/opentripplanner/ext/geocoder/GeocoderResource.java
+++ b/src/ext/java/org/opentripplanner/ext/geocoder/GeocoderResource.java
@@ -14,7 +14,7 @@
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
-import org.opentripplanner.api.mapping.FeedScopedIdMapper;
+import org.opentripplanner.ext.restapi.mapping.FeedScopedIdMapper;
import org.opentripplanner.standalone.api.OtpServerRequestContext;
import org.opentripplanner.transit.model.site.StopLocation;
diff --git a/src/ext/java/org/opentripplanner/ext/interactivelauncher/InteractiveOtpMain.java b/src/ext/java/org/opentripplanner/ext/interactivelauncher/InteractiveOtpMain.java
index 1f9227b3be6..43061ee2b62 100644
--- a/src/ext/java/org/opentripplanner/ext/interactivelauncher/InteractiveOtpMain.java
+++ b/src/ext/java/org/opentripplanner/ext/interactivelauncher/InteractiveOtpMain.java
@@ -1,19 +1,20 @@
package org.opentripplanner.ext.interactivelauncher;
-import static org.opentripplanner.ext.interactivelauncher.DebugLoggingSupport.configureDebugLogging;
-
-import org.opentripplanner.ext.interactivelauncher.views.MainView;
+import org.opentripplanner.ext.interactivelauncher.configuration.InteractiveLauncherModule;
+import org.opentripplanner.ext.interactivelauncher.debug.OtpDebugController;
+import org.opentripplanner.ext.interactivelauncher.startup.MainView;
import org.opentripplanner.standalone.OTPMain;
/**
- * This class provide a main method to start a GUI which can start OTPMain.
+ * This class provides a main method to start a GUI which can start OTPMain.
*
- * The UI allow the user to select a OTP configuration data set. The list of data location is
- * created by searching the a root data source directory.
+ * The UI allows the user to select the OTP configuration dataset. The list of data locations is
+ * created by searching the root data source directory.
*
- * The user then select what he/she want OTP to do. The settings are stored in the
- * .interactive_otp_main.json file in the folder InteractiveOtpMain is started. The
- * settings from the last run is loaded next time InteractiveOtpMain is started.
+ * The user then selects what he/she wants OTP to do.
+ * The settings are stored in the
+ * .interactive_otp_main.json file in the folder InteractiveOtpMain is started.
+ * The settings from the last run are loaded the next time InteractiveOtpMain is started.
*/
public class InteractiveOtpMain {
@@ -25,16 +26,19 @@ public static void main(String[] args) {
private void run() {
this.model = Model.load();
- MainView frame = new MainView(new Thread(this::startOtp)::start, model);
+ MainView frame = new MainView(new Thread(this::startOtp)::start, model.getStartupModel());
frame.start();
}
private void startOtp() {
- model.save();
-
- configureDebugLogging(model.getDebugLogging());
+ startDebugControllerAndSetupRequestInterceptor();
System.out.println("Start OTP: " + model + "\n");
- OTPMain.main(model.asOtpArgs());
+ OTPMain.main(model.getStartupModel().asOtpArgs());
+ }
+
+ private void startDebugControllerAndSetupRequestInterceptor() {
+ new OtpDebugController(model).start();
+ InteractiveLauncherModule.setRequestInterceptor(model.getRaptorDebugModel());
}
}
diff --git a/src/ext/java/org/opentripplanner/ext/interactivelauncher/Model.java b/src/ext/java/org/opentripplanner/ext/interactivelauncher/Model.java
index ee2dde3e684..59682082b90 100644
--- a/src/ext/java/org/opentripplanner/ext/interactivelauncher/Model.java
+++ b/src/ext/java/org/opentripplanner/ext/interactivelauncher/Model.java
@@ -1,245 +1,81 @@
package org.opentripplanner.ext.interactivelauncher;
-import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.function.Consumer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.opentripplanner.ext.interactivelauncher.debug.logging.LogModel;
+import org.opentripplanner.ext.interactivelauncher.debug.raptor.RaptorDebugModel;
+import org.opentripplanner.ext.interactivelauncher.startup.StartupModel;
public class Model implements Serializable {
- private static final Logger LOG = LoggerFactory.getLogger(Model.class);
-
private static final File MODEL_FILE = new File("interactive_otp_main.json");
- private final Map debugLogging = new HashMap<>();
-
- @JsonIgnore
- private transient Consumer commandLineChange;
+ private StartupModel startupModel;
+ private LogModel logModel;
+ private RaptorDebugModel raptorDebugModel;
- private String rootDirectory = null;
- private String dataSource = null;
- private boolean buildStreet = false;
- private boolean buildTransit = true;
- private boolean saveGraph = false;
- private boolean serveGraph = true;
- private boolean visualizer = false;
-
- public Model() {
- setupListOfDebugLoggers();
- }
+ public Model() {}
public static Model load() {
- return MODEL_FILE.exists() ? readFromFile() : new Model();
- }
-
- public void subscribeCmdLineUpdates(Consumer commandLineChange) {
- this.commandLineChange = commandLineChange;
- }
-
- @SuppressWarnings("AccessOfSystemProperties")
- public String getRootDirectory() {
- return rootDirectory == null ? System.getProperty("user.dir") : rootDirectory;
- }
-
- public void setRootDirectory(String rootDirectory) {
- // If the persisted JSON do not contain the rootDirectory, then avoid setting it
- if (rootDirectory != null) {
- this.rootDirectory = rootDirectory;
- }
- notifyChangeListener();
- }
-
- public String getDataSource() {
- return dataSource;
- }
-
- public void setDataSource(String dataSource) {
- this.dataSource = dataSource;
- notifyChangeListener();
- }
-
- @JsonIgnore
- public List getDataSourceOptions() {
- List dataSourceOptions = new ArrayList<>();
- File rootDir = new File(getRootDirectory());
- List dirs = SearchForOtpConfig.search(rootDir);
- // Add 1 char for the path-separator-character
- int length = rootDir.getAbsolutePath().length() + 1;
-
- for (File dir : dirs) {
- var path = dir.getAbsolutePath();
- if (path.length() <= length) {
- LOG.warn(
- "The root directory contains a config file, choose " +
- "the parent directory or delete the config file."
- );
- continue;
- }
- dataSourceOptions.add(path.substring(length));
- }
- return dataSourceOptions;
- }
-
- public boolean isBuildStreet() {
- return buildStreet;
- }
-
- public void setBuildStreet(boolean buildStreet) {
- this.buildStreet = buildStreet;
- notifyChangeListener();
- }
-
- public boolean isBuildTransit() {
- return buildTransit;
- }
-
- public void setBuildTransit(boolean buildTransit) {
- this.buildTransit = buildTransit;
- notifyChangeListener();
- }
-
- public boolean isSaveGraph() {
- return saveGraph;
- }
-
- public void setSaveGraph(boolean saveGraph) {
- this.saveGraph = saveGraph;
- notifyChangeListener();
- }
-
- public boolean isServeGraph() {
- return serveGraph;
- }
-
- public void setServeGraph(boolean serveGraph) {
- this.serveGraph = serveGraph;
- notifyChangeListener();
- }
-
- public boolean isVisualizer() {
- return visualizer;
+ return MODEL_FILE.exists() ? readFromFile() : createNew();
}
- public void setVisualizer(boolean visualizer) {
- this.visualizer = visualizer;
- notifyChangeListener();
+ public StartupModel getStartupModel() {
+ return startupModel;
}
- public Map getDebugLogging() {
- return debugLogging;
+ public LogModel getLogModel() {
+ return logModel;
}
- public void setDebugLogging(Map map) {
- for (Entry e : map.entrySet()) {
- // Only keep entries that exist in the log config
- if (debugLogging.containsKey(e.getKey())) {
- debugLogging.put(e.getKey(), e.getValue());
- }
- }
- }
-
- @Override
- public String toString() {
- return (
- "(" +
- "data-source-dir: " +
- getDataSourceDirectory() +
- (buildStreet ? ", buildStreet" : "") +
- (buildTransit ? ", buildTransit" : "") +
- (saveGraph ? ", saveGraph" : "") +
- (serveGraph ? ", serveGraph" : "") +
- (visualizer ? ", visualizer" : "") +
- ')'
- );
- }
-
- public String toCliString() {
- return String.join(" ", asOtpArgs());
- }
-
- public void save() {
- try {
- new ObjectMapper().writeValue(MODEL_FILE, this);
- } catch (IOException e) {
- throw new RuntimeException(e.getMessage(), e);
- }
- }
-
- @JsonIgnore
- String getDataSourceDirectory() {
- if (dataSource == null) {
- return "DATA_SOURCE_NOT_SET";
- }
- return rootDirectory + File.separatorChar + dataSource;
+ public RaptorDebugModel getRaptorDebugModel() {
+ return raptorDebugModel;
}
- String[] asOtpArgs() {
- List args = new ArrayList<>();
-
- if (buildAll()) {
- args.add("--build");
- } else if (buildStreet) {
- args.add("--buildStreet");
- } else if (buildTransit) {
- args.add("--loadStreet");
- } else {
- args.add("--load");
- }
-
- if (saveGraph && (buildTransit || buildStreet)) {
- args.add("--save");
- }
- if (serveGraph && !buildStreetOnly()) {
- args.add("--serve");
- }
- if (serveGraph && !buildStreetOnly() && visualizer) {
- args.add("--visualize");
- }
-
- args.add(getDataSourceDirectory());
-
- return args.toArray(new String[0]);
+ private static Model createNew() {
+ return new Model().initSubModels();
}
private static Model readFromFile() {
try {
- return new ObjectMapper().readValue(MODEL_FILE, Model.class);
+ var mapper = new ObjectMapper()
+ .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ return mapper.readValue(MODEL_FILE, Model.class).initSubModels();
} catch (IOException e) {
System.err.println(
"Unable to read the InteractiveOtpMain state cache. If the model changed this " +
"is expected, and it will work next time. Cause: " +
e.getMessage()
);
- return new Model();
+ return createNew();
}
}
- private void notifyChangeListener() {
- if (commandLineChange != null) {
- commandLineChange.accept(toCliString());
+ private void save() {
+ try {
+ var mapper = new ObjectMapper().configure(SerializationFeature.INDENT_OUTPUT, true);
+ mapper.writeValue(MODEL_FILE, this);
+ } catch (IOException e) {
+ throw new RuntimeException(e.getMessage(), e);
}
}
- private boolean buildAll() {
- return buildStreet && buildTransit;
- }
-
- private boolean buildStreetOnly() {
- return buildStreet && !buildTransit;
- }
-
- private void setupListOfDebugLoggers() {
- for (String log : DebugLoggingSupport.getLogs()) {
- debugLogging.put(log, Boolean.FALSE);
+ private Model initSubModels() {
+ if (startupModel == null) {
+ startupModel = new StartupModel();
+ }
+ if (logModel == null) {
+ logModel = LogModel.createFromConfig();
+ }
+ if (raptorDebugModel == null) {
+ raptorDebugModel = new RaptorDebugModel();
}
+ logModel.init(this::save);
+ raptorDebugModel.init(this::save);
+ return this;
}
}
diff --git a/src/ext/java/org/opentripplanner/ext/interactivelauncher/SetupResult.java b/src/ext/java/org/opentripplanner/ext/interactivelauncher/SetupResult.java
deleted file mode 100644
index a6ecf5e7229..00000000000
--- a/src/ext/java/org/opentripplanner/ext/interactivelauncher/SetupResult.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package org.opentripplanner.ext.interactivelauncher;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-public class SetupResult {
-
- private final File configDataDir;
- private final boolean buildStreet;
- private final boolean buildTransit;
- private final boolean saveGraph;
- private final boolean serveGraph;
-
- public SetupResult(
- File configDataDir,
- boolean buildStreet,
- boolean buildTransit,
- boolean saveGraph,
- boolean serveGraph
- ) {
- this.configDataDir = configDataDir;
- this.buildStreet = buildStreet;
- this.buildTransit = buildTransit;
- this.saveGraph = saveGraph;
- this.serveGraph = serveGraph;
- }
-
- @Override
- public String toString() {
- return (
- "SetupResult{" +
- "configDataDir=" +
- configDataDir.getAbsolutePath() +
- (buildStreet ? ", buildStreet" : "") +
- (buildTransit ? ", buildTransit" : "") +
- (saveGraph ? ", saveGraph" : "") +
- (serveGraph ? ", serveGraph" : "") +
- '}'
- );
- }
-
- public String toCliString() {
- return String.join(" ", asOtpArgs());
- }
-
- File configDataDir() {
- return configDataDir;
- }
-
- boolean buildStreet() {
- return buildStreet;
- }
-
- boolean buildTransit() {
- return buildTransit;
- }
-
- boolean buildAll() {
- return buildStreet && buildTransit;
- }
-
- boolean buildStreetOnly() {
- return buildStreet && !buildTransit;
- }
-
- boolean saveGraph() {
- return saveGraph;
- }
-
- boolean serveGraph() {
- return serveGraph;
- }
-
- String[] asOtpArgs() {
- List args = new ArrayList<>();
-
- if (buildAll()) {
- args.add("--build");
- } else if (buildStreet) {
- args.add("--buildStreet");
- } else if (buildTransit) {
- args.add("--loadStreet");
- } else {
- args.add("--load");
- }
-
- if (saveGraph && (buildTransit || buildStreet)) {
- args.add("--save");
- }
- if (serveGraph && !buildStreetOnly()) {
- args.add("--serve");
- }
-
- args.add(configDataDir.getAbsolutePath());
-
- return args.toArray(new String[0]);
- }
-}
diff --git a/src/ext/java/org/opentripplanner/ext/interactivelauncher/api/LauncherRequestDecorator.java b/src/ext/java/org/opentripplanner/ext/interactivelauncher/api/LauncherRequestDecorator.java
new file mode 100644
index 00000000000..99c28bad260
--- /dev/null
+++ b/src/ext/java/org/opentripplanner/ext/interactivelauncher/api/LauncherRequestDecorator.java
@@ -0,0 +1,15 @@
+package org.opentripplanner.ext.interactivelauncher.api;
+
+import org.opentripplanner.routing.api.request.RouteRequest;
+
+/**
+ * Allow the interactive launcher intercept planing requests.
+ */
+public interface LauncherRequestDecorator {
+ /**
+ * The launcher may use this method to change the default plan request. Note! It is the DEFAULT
+ * request witch is passed in here, then the request-specific values are applied on top
+ * of that.
+ */
+ RouteRequest intercept(RouteRequest defaultRequest);
+}
diff --git a/src/ext/java/org/opentripplanner/ext/interactivelauncher/configuration/InteractiveLauncherModule.java b/src/ext/java/org/opentripplanner/ext/interactivelauncher/configuration/InteractiveLauncherModule.java
new file mode 100644
index 00000000000..9acd0298122
--- /dev/null
+++ b/src/ext/java/org/opentripplanner/ext/interactivelauncher/configuration/InteractiveLauncherModule.java
@@ -0,0 +1,20 @@
+package org.opentripplanner.ext.interactivelauncher.configuration;
+
+import dagger.Module;
+import dagger.Provides;
+import org.opentripplanner.ext.interactivelauncher.api.LauncherRequestDecorator;
+
+@Module
+public class InteractiveLauncherModule {
+
+ static LauncherRequestDecorator decorator = request -> request;
+
+ public static void setRequestInterceptor(LauncherRequestDecorator decorator) {
+ InteractiveLauncherModule.decorator = decorator;
+ }
+
+ @Provides
+ LauncherRequestDecorator requestDecorator() {
+ return decorator;
+ }
+}
diff --git a/src/ext/java/org/opentripplanner/ext/interactivelauncher/debug/OtpDebugController.java b/src/ext/java/org/opentripplanner/ext/interactivelauncher/debug/OtpDebugController.java
new file mode 100644
index 00000000000..9e41fe3412d
--- /dev/null
+++ b/src/ext/java/org/opentripplanner/ext/interactivelauncher/debug/OtpDebugController.java
@@ -0,0 +1,37 @@
+package org.opentripplanner.ext.interactivelauncher.debug;
+
+import static org.opentripplanner.ext.interactivelauncher.support.ViewUtils.BACKGROUND;
+
+import javax.swing.JFrame;
+import javax.swing.JTabbedPane;
+import org.opentripplanner.ext.interactivelauncher.Model;
+import org.opentripplanner.ext.interactivelauncher.debug.logging.LogView;
+import org.opentripplanner.ext.interactivelauncher.debug.raptor.RaptorDebugView;
+
+/**
+ * This controller/UI allows changing the debug loggers and setting the raptor
+ * debug parameters for incoming rute requests.
+ */
+public class OtpDebugController {
+
+ private final JFrame debugFrame = new JFrame("OTP Debug Controller");
+
+ public OtpDebugController(Model model) {
+ debugFrame.add(createTabbedPane(model));
+ debugFrame.getContentPane().setBackground(BACKGROUND);
+ }
+
+ public void start() {
+ debugFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+ debugFrame.pack();
+ debugFrame.setLocationRelativeTo(null);
+ debugFrame.setVisible(true);
+ }
+
+ private static JTabbedPane createTabbedPane(Model model) {
+ var tabPanel = new JTabbedPane();
+ tabPanel.addTab("Logging", new LogView(model.getLogModel()).panel());
+ tabPanel.addTab("Raptor", new RaptorDebugView(model.getRaptorDebugModel()).panel());
+ return tabPanel;
+ }
+}
diff --git a/src/ext/java/org/opentripplanner/ext/interactivelauncher/debug/logging/DebugLoggers.java b/src/ext/java/org/opentripplanner/ext/interactivelauncher/debug/logging/DebugLoggers.java
new file mode 100644
index 00000000000..48f87abf2ab
--- /dev/null
+++ b/src/ext/java/org/opentripplanner/ext/interactivelauncher/debug/logging/DebugLoggers.java
@@ -0,0 +1,26 @@
+package org.opentripplanner.ext.interactivelauncher.debug.logging;
+
+import java.util.List;
+
+class DebugLoggers {
+
+ static List list() {
+ return List.of(
+ of("Data import issues", "DATA_IMPORT_ISSUES"),
+ of("All OTP debuggers", "org.opentripplanner"),
+ of("OTP request/response", "org.opentripplanner.routing.service.DefaultRoutingService"),
+ of("Raptor request/response", "org.opentripplanner.raptor.RaptorService"),
+ of("Transfer Optimization", "org.opentripplanner.routing.algorithm.transferoptimization")
+ );
+ }
+
+ static List listLoggers() {
+ return list().stream().map(Entry::logger).toList();
+ }
+
+ private static Entry of(String label, String logger) {
+ return new Entry(label, logger);
+ }
+
+ record Entry(String label, String logger) {}
+}
diff --git a/src/ext/java/org/opentripplanner/ext/interactivelauncher/DebugLoggingSupport.java b/src/ext/java/org/opentripplanner/ext/interactivelauncher/debug/logging/DebugLoggingSupport.java
similarity index 60%
rename from src/ext/java/org/opentripplanner/ext/interactivelauncher/DebugLoggingSupport.java
rename to src/ext/java/org/opentripplanner/ext/interactivelauncher/debug/logging/DebugLoggingSupport.java
index e0b07a8c79e..09eddcfdf78 100644
--- a/src/ext/java/org/opentripplanner/ext/interactivelauncher/DebugLoggingSupport.java
+++ b/src/ext/java/org/opentripplanner/ext/interactivelauncher/debug/logging/DebugLoggingSupport.java
@@ -1,22 +1,21 @@
-package org.opentripplanner.ext.interactivelauncher;
+package org.opentripplanner.ext.interactivelauncher.debug.logging;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
import java.util.regex.Pattern;
import org.slf4j.LoggerFactory;
/**
- * Responsible for integration with the OTP Debug log configuraton, reading loggers from the slf4j
+ * Responsible for integration with the OTP Debug log configuration, reading loggers from the slf4j
* context and setting DEBUG level on selected loggers back.
*
- * The log names are transformed to be more human readable:
+ * The log names are transformed to be more human-readable:
*
+ * Maplibre uses these to render vector maps in the browser.
+ */
+public final class StyleSpec {
+
+ private final String name;
+ private final List sources;
+ private final List layers;
+
+ public StyleSpec(String name, List sources, List layers) {
+ this.name = name;
+ this.sources = sources;
+ this.layers = layers.stream().map(LayerStyleBuilder::toJson).toList();
+ }
+
+ @JsonSerialize
+ public int version() {
+ return 8;
+ }
+
+ @JsonSerialize
+ public String name() {
+ return name;
+ }
+
+ @JsonSerialize
+ public Map sources() {
+ var output = new HashMap();
+ sources.forEach(s -> output.put(s.id(), s));
+ return output;
+ }
+
+ @JsonSerialize
+ public List layers() {
+ return layers;
+ }
+}
diff --git a/src/main/java/org/opentripplanner/apis/vectortiles/model/TileSource.java b/src/main/java/org/opentripplanner/apis/vectortiles/model/TileSource.java
new file mode 100644
index 00000000000..06af294a4f0
--- /dev/null
+++ b/src/main/java/org/opentripplanner/apis/vectortiles/model/TileSource.java
@@ -0,0 +1,36 @@
+package org.opentripplanner.apis.vectortiles.model;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import java.util.List;
+
+/**
+ * Represent a data source where Maplibre can fetch data for rendering directly in the browser.
+ */
+public sealed interface TileSource {
+ @JsonSerialize
+ String type();
+
+ String id();
+
+ /**
+ * Represents a vector tile source which is rendered into a map in the browser.
+ */
+ record VectorSource(String id, String url) implements TileSource {
+ @Override
+ public String type() {
+ return "vector";
+ }
+ }
+
+ /**
+ * Represents a raster-based source for map tiles. These are used mainly for background
+ * map layers with vector data being rendered on top of it.
+ */
+ record RasterSource(String id, List tiles, int tileSize, String attribution)
+ implements TileSource {
+ @Override
+ public String type() {
+ return "raster";
+ }
+ }
+}
diff --git a/src/main/java/org/opentripplanner/astar/model/BinHeap.java b/src/main/java/org/opentripplanner/astar/model/BinHeap.java
index 9bc2b0762a8..1e9b540a77a 100644
--- a/src/main/java/org/opentripplanner/astar/model/BinHeap.java
+++ b/src/main/java/org/opentripplanner/astar/model/BinHeap.java
@@ -79,14 +79,6 @@ public void rekey(T e, double p) {
prio[i] = p;
}
- public void dump() {
- for (int i = 0; i <= capacity; i++) {
- String topMarker = (i > size) ? "(UNUSED)" : "";
- System.out.printf("%d\t%f\t%s\t%s\n", i, prio[i], elem[i], topMarker);
- }
- System.out.printf("-----------------------\n");
- }
-
public void reset() {
// empties the queue in one operation
size = 0;
@@ -135,8 +127,4 @@ public void resize(int capacity) {
prio = Arrays.copyOf(prio, capacity + 1);
elem = Arrays.copyOf(elem, capacity + 1);
}
-
- public int getCapacity() {
- return capacity;
- }
}
diff --git a/src/main/java/org/opentripplanner/astar/model/ShortestPathTree.java b/src/main/java/org/opentripplanner/astar/model/ShortestPathTree.java
index e373f9c785e..a6d7123cdfe 100644
--- a/src/main/java/org/opentripplanner/astar/model/ShortestPathTree.java
+++ b/src/main/java/org/opentripplanner/astar/model/ShortestPathTree.java
@@ -244,10 +244,6 @@ public void setAborted() {
aborted = true;
}
- public boolean isAborted() {
- return aborted;
- }
-
public String toString() {
return "ShortestPathTree(" + this.stateSets.size() + " vertices)";
}
diff --git a/src/main/java/org/opentripplanner/astar/strategy/MaxCountSkipEdgeStrategy.java b/src/main/java/org/opentripplanner/astar/strategy/MaxCountSkipEdgeStrategy.java
index bcae9dcdb86..0369e3e29db 100644
--- a/src/main/java/org/opentripplanner/astar/strategy/MaxCountSkipEdgeStrategy.java
+++ b/src/main/java/org/opentripplanner/astar/strategy/MaxCountSkipEdgeStrategy.java
@@ -1,12 +1,12 @@
package org.opentripplanner.astar.strategy;
-import java.util.function.Function;
+import java.util.function.Predicate;
import org.opentripplanner.astar.spi.AStarEdge;
import org.opentripplanner.astar.spi.AStarState;
import org.opentripplanner.astar.spi.SkipEdgeStrategy;
/**
- * Skips edges when the specified number of desired vertices have been visited
+ * Skips edges when the specified number of desired vertices have been visited.
*/
public class MaxCountSkipEdgeStrategy<
State extends AStarState, Edge extends AStarEdge
@@ -14,11 +14,11 @@ public class MaxCountSkipEdgeStrategy<
implements SkipEdgeStrategy {
private final int maxCount;
- private final Function shouldIncreaseCount;
+ private final Predicate shouldIncreaseCount;
private int visited;
- public MaxCountSkipEdgeStrategy(int count, Function shouldIncreaseCount) {
+ public MaxCountSkipEdgeStrategy(int count, Predicate shouldIncreaseCount) {
this.maxCount = count;
this.shouldIncreaseCount = shouldIncreaseCount;
this.visited = 0;
@@ -26,7 +26,7 @@ public MaxCountSkipEdgeStrategy(int count, Function shouldIncrea
@Override
public boolean shouldSkipEdge(State current, Edge edge) {
- if (this.shouldIncreaseCount.apply(current)) {
+ if (shouldIncreaseCount.test(current)) {
visited++;
}
return visited > maxCount;
diff --git a/src/main/java/org/opentripplanner/framework/application/OTPFeature.java b/src/main/java/org/opentripplanner/framework/application/OTPFeature.java
index 05d1284a883..4847b204077 100644
--- a/src/main/java/org/opentripplanner/framework/application/OTPFeature.java
+++ b/src/main/java/org/opentripplanner/framework/application/OTPFeature.java
@@ -16,20 +16,23 @@
public enum OTPFeature {
APIBikeRental(true, false, "Enable the bike rental endpoint."),
APIServerInfo(true, false, "Enable the server info endpoint."),
- APIGraphInspectorTile(
- true,
- false,
- "Enable the inspector endpoint for graph information for inspection/debugging purpose."
- ),
APIUpdaterStatus(true, false, "Enable endpoint for graph updaters status."),
ConsiderPatternsForDirectTransfers(
true,
false,
"Enable limiting transfers so that there is only a single transfer to each pattern."
),
- DebugClient(true, false, "Enable the debug web client located at the root of the web server."),
+ DebugUi(
+ true,
+ false,
+ """
+ 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.
+ """
+ ),
FloatingBike(true, false, "Enable floating bike routing."),
- GtfsGraphQlApi(true, false, "Enable GTFS GraphQL API."),
+ GtfsGraphQlApi(true, false, "Enable the [GTFS GraphQL API](apis/GTFS-GraphQL-API.md)."),
GtfsGraphQlApiRentalStationFuzzyMatching(
false,
false,
@@ -63,7 +66,11 @@ public enum OTPFeature {
false,
"Enforce transfers to happen according to the _transfers.txt_ (GTFS) and Interchanges (NeTEx). Turning this _off_ will increase the routing performance a little."
),
- TransmodelGraphQlApi(true, true, "Enable Transmodel (NeTEx) GraphQL API."),
+ TransmodelGraphQlApi(
+ true,
+ true,
+ "Enable the [Transmodel (NeTEx) GraphQL API](apis/TransmodelApi.md)."
+ ),
/* Sandbox extension features - Must be turned OFF by default */
@@ -82,6 +89,7 @@ public enum OTPFeature {
FaresV2(false, true, "Enable import of GTFS-Fares v2 data."),
FlexRouting(false, true, "Enable FLEX routing."),
GoogleCloudStorage(false, true, "Enable Google Cloud Storage integration."),
+ LegacyRestApi(true, true, "Enable legacy REST API. This API will be removed in the future."),
RealtimeResolver(
false,
true,
diff --git a/src/main/java/org/opentripplanner/api/json/GraphQLResponseSerializer.java b/src/main/java/org/opentripplanner/framework/graphql/GraphQLResponseSerializer.java
similarity index 94%
rename from src/main/java/org/opentripplanner/api/json/GraphQLResponseSerializer.java
rename to src/main/java/org/opentripplanner/framework/graphql/GraphQLResponseSerializer.java
index caba621294c..cb3b146a113 100644
--- a/src/main/java/org/opentripplanner/api/json/GraphQLResponseSerializer.java
+++ b/src/main/java/org/opentripplanner/framework/graphql/GraphQLResponseSerializer.java
@@ -1,4 +1,4 @@
-package org.opentripplanner.api.json;
+package org.opentripplanner.framework.graphql;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -10,6 +10,7 @@
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+import org.opentripplanner.ext.restapi.serialization.JSONObjectMapperProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/org/opentripplanner/framework/graphql/scalar/CostScalarFactory.java b/src/main/java/org/opentripplanner/framework/graphql/scalar/CostScalarFactory.java
new file mode 100644
index 00000000000..6f710328174
--- /dev/null
+++ b/src/main/java/org/opentripplanner/framework/graphql/scalar/CostScalarFactory.java
@@ -0,0 +1,83 @@
+package org.opentripplanner.framework.graphql.scalar;
+
+import graphql.GraphQLContext;
+import graphql.execution.CoercedVariables;
+import graphql.language.StringValue;
+import graphql.language.Value;
+import graphql.schema.Coercing;
+import graphql.schema.CoercingParseLiteralException;
+import graphql.schema.CoercingParseValueException;
+import graphql.schema.GraphQLScalarType;
+import java.util.Locale;
+import java.util.NoSuchElementException;
+import javax.annotation.Nonnull;
+import org.opentripplanner.framework.model.Cost;
+import org.opentripplanner.framework.time.DurationUtils;
+
+public class CostScalarFactory {
+
+ private static final String TYPENAME = "Cost";
+
+ private static final String DOCUMENTATION =
+ "A cost value, normally a value of 1 is equivalent to riding transit for 1 second, " +
+ "but it might not depending on the use-case. Format: 3665 = DT1h1m5s = 1h1m5s";
+
+ private static final GraphQLScalarType SCALAR_INSTANCE = createCostScalar();
+
+ private CostScalarFactory() {}
+
+ public static GraphQLScalarType costScalar() {
+ return SCALAR_INSTANCE;
+ }
+
+ private static GraphQLScalarType createCostScalar() {
+ return GraphQLScalarType
+ .newScalar()
+ .name(TYPENAME)
+ .description(DOCUMENTATION)
+ .coercing(createCoercing())
+ .build();
+ }
+
+ private static String serializeCost(Cost cost) {
+ return cost.asDuration().toString();
+ }
+
+ private static Cost parseCost(String input) throws CoercingParseValueException {
+ try {
+ return Cost.fromDuration(DurationUtils.parseSecondsOrDuration(input).orElseThrow());
+ } catch (IllegalArgumentException | NoSuchElementException e) {
+ throw new CoercingParseValueException(e.getMessage(), e);
+ }
+ }
+
+ private static Coercing createCoercing() {
+ return new Coercing<>() {
+ @Override
+ public String serialize(@Nonnull Object result, GraphQLContext c, Locale l) {
+ return serializeCost((Cost) result);
+ }
+
+ @Override
+ public Cost parseValue(Object input, GraphQLContext c, Locale l)
+ throws CoercingParseValueException {
+ return parseCost((String) input);
+ }
+
+ @Override
+ public Cost parseLiteral(Value> input, CoercedVariables v, GraphQLContext c, Locale l)
+ throws CoercingParseLiteralException {
+ if (input instanceof StringValue stringValue) {
+ return parseCost(stringValue.getValue());
+ }
+ return null;
+ }
+
+ @Override
+ @Nonnull
+ public Value> valueToLiteral(Object input, GraphQLContext c, Locale l) {
+ return StringValue.of((String) input);
+ }
+ };
+ }
+}
diff --git a/src/main/java/org/opentripplanner/api/mapping/I18NStringMapper.java b/src/main/java/org/opentripplanner/framework/i18n/I18NStringMapper.java
similarity index 77%
rename from src/main/java/org/opentripplanner/api/mapping/I18NStringMapper.java
rename to src/main/java/org/opentripplanner/framework/i18n/I18NStringMapper.java
index 6b40a07b953..acdb30b301f 100644
--- a/src/main/java/org/opentripplanner/api/mapping/I18NStringMapper.java
+++ b/src/main/java/org/opentripplanner/framework/i18n/I18NStringMapper.java
@@ -1,9 +1,8 @@
-package org.opentripplanner.api.mapping;
+package org.opentripplanner.framework.i18n;
import java.util.Locale;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import org.opentripplanner.framework.i18n.I18NString;
public class I18NStringMapper {
@@ -24,7 +23,7 @@ public String mapNonnullToApi(I18NString string) {
}
@Nullable
- static String mapToApi(I18NString string, Locale locale) {
+ public static String mapToApi(I18NString string, Locale locale) {
return string == null ? null : string.toString(locale);
}
}
diff --git a/src/main/java/org/opentripplanner/framework/io/HttpUtils.java b/src/main/java/org/opentripplanner/framework/io/HttpUtils.java
index 3450cf0786c..4981a8ab91b 100644
--- a/src/main/java/org/opentripplanner/framework/io/HttpUtils.java
+++ b/src/main/java/org/opentripplanner/framework/io/HttpUtils.java
@@ -24,16 +24,16 @@ private HttpUtils() {}
public static String getBaseAddress(UriInfo uri, HttpHeaders headers) {
String protocol;
if (headers.getRequestHeader(HEADER_X_FORWARDED_PROTO) != null) {
- protocol = headers.getRequestHeader(HEADER_X_FORWARDED_PROTO).get(0);
+ protocol = headers.getRequestHeader(HEADER_X_FORWARDED_PROTO).getFirst();
} else {
protocol = uri.getRequestUri().getScheme();
}
String host;
if (headers.getRequestHeader(HEADER_X_FORWARDED_HOST) != null) {
- host = headers.getRequestHeader(HEADER_X_FORWARDED_HOST).get(0);
+ host = headers.getRequestHeader(HEADER_X_FORWARDED_HOST).getFirst();
} else if (headers.getRequestHeader(HEADER_HOST) != null) {
- host = headers.getRequestHeader(HEADER_HOST).get(0);
+ host = headers.getRequestHeader(HEADER_HOST).getFirst();
} else {
host = uri.getBaseUri().getHost() + ":" + uri.getBaseUri().getPort();
}
diff --git a/src/main/java/org/opentripplanner/graph_builder/module/NearbyStopFinder.java b/src/main/java/org/opentripplanner/graph_builder/module/NearbyStopFinder.java
index ba776ac5243..360cdaee363 100644
--- a/src/main/java/org/opentripplanner/graph_builder/module/NearbyStopFinder.java
+++ b/src/main/java/org/opentripplanner/graph_builder/module/NearbyStopFinder.java
@@ -47,14 +47,8 @@
import org.opentripplanner.transit.service.TransitService;
/**
- * These library functions are used by the streetless and streetful stop linkers, and in profile
- * transfer generation.
- * TODO OTP2 Fold these into org.opentripplanner.routing.graphfinder.StreetGraphFinder
- * These are not library functions, this is instantiated as an object. Define lifecycle of the object (reuse?).
- * Because AStar instances should only be used once, NearbyStopFinder should only be used once.
- * Ideally they could also be used in long distance mode and profile routing for the street segments.
- * For each stop, it finds the closest stops on all other patterns. This reduces the number of transfer edges
- * significantly compared to simple radius-constrained all-to-all stop linkage.
+ * This class contains code for finding nearby stops from a given vertex. It is being used by access
+ * and egress searches as well as transfer generation.
*/
public class NearbyStopFinder {
@@ -100,6 +94,8 @@ public NearbyStopFinder(
* that the result will include the origin vertex if it is an instance of StopVertex. This is
* intentional: we don't want to return the next stop down the line for trip patterns that pass
* through the origin vertex.
+ * Taking the patterns into account reduces the number of transfers significantly compared to
+ * simple traverse-duration-constrained all-to-all stop linkage.
*/
public Set findNearbyStopsConsideringPatterns(
Vertex vertex,
@@ -227,15 +223,12 @@ public List findNearbyStopsViaStreets(
for (State state : spt.getAllStates()) {
Vertex targetVertex = state.getVertex();
if (originVertices.contains(targetVertex)) continue;
- if (targetVertex instanceof TransitStopVertex && state.isFinal()) {
- stopsFound.add(
- NearbyStop.nearbyStopForState(state, ((TransitStopVertex) targetVertex).getStop())
- );
+ if (targetVertex instanceof TransitStopVertex tsv && state.isFinal()) {
+ stopsFound.add(NearbyStop.nearbyStopForState(state, tsv.getStop()));
}
if (
OTPFeature.FlexRouting.isOn() &&
- targetVertex instanceof StreetVertex &&
- !((StreetVertex) targetVertex).areaStops().isEmpty()
+ targetVertex instanceof StreetVertex streetVertex && !streetVertex.areaStops().isEmpty()
) {
for (AreaStop areaStop : ((StreetVertex) targetVertex).areaStops()) {
// This is for a simplification, so that we only return one vertex from each
@@ -314,7 +307,7 @@ private SkipEdgeStrategy getSkipEdgeStrategy(
if (maxStopCount > 0) {
var strategy = new MaxCountSkipEdgeStrategy<>(
maxStopCount,
- NearbyStopFinder::isTransitVertex
+ NearbyStopFinder::hasReachedStop
);
return new ComposingSkipEdgeStrategy<>(strategy, durationSkipEdgeStrategy);
}
@@ -360,15 +353,23 @@ private boolean canBoardFlex(State state, boolean reverse) {
return edges
.stream()
- .anyMatch(e ->
- e instanceof StreetEdge && ((StreetEdge) e).getPermission().allows(TraverseMode.CAR)
- );
+ .anyMatch(e -> e instanceof StreetEdge se && se.getPermission().allows(TraverseMode.CAR));
}
/**
- * Checks if the {@code state} as at a transit vertex.
+ * Checks if the {@code state} is at a transit vertex and if it's final, which means that the state
+ * can actually board a vehicle.
+ *
+ * This is important because there can be cases where states that cannot actually board the vehicle
+ * can dominate those that can thereby leading to zero found stops when this predicate is used with
+ * the {@link MaxCountSkipEdgeStrategy}.
+ *
+ * An example of this would be an egress/reverse search with a very high walk reluctance where
+ * the states that speculatively rent a vehicle move the walk states down the A* priority queue
+ * until the required number of stops are reached to abort the search, leading to zero egress
+ * results.
*/
- public static boolean isTransitVertex(State state) {
- return state.getVertex() instanceof TransitStopVertex;
+ public static boolean hasReachedStop(State state) {
+ return state.getVertex() instanceof TransitStopVertex && state.isFinal();
}
}
diff --git a/src/main/java/org/opentripplanner/inspector/vector/AreaStopsLayerBuilder.java b/src/main/java/org/opentripplanner/inspector/vector/AreaStopsLayerBuilder.java
deleted file mode 100644
index 1604cf7d8d1..00000000000
--- a/src/main/java/org/opentripplanner/inspector/vector/AreaStopsLayerBuilder.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.opentripplanner.inspector.vector;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.function.Function;
-import org.locationtech.jts.geom.Envelope;
-import org.locationtech.jts.geom.Geometry;
-import org.opentripplanner.api.mapping.PropertyMapper;
-import org.opentripplanner.transit.model.site.AreaStop;
-import org.opentripplanner.transit.service.TransitService;
-
-/**
- * A vector tile layer containing all {@link AreaStop}s inside the vector tile bounds.
- */
-public class AreaStopsLayerBuilder extends LayerBuilder {
-
- private static final Map mappers = Map.of(
- MapperType.DebugClient,
- DebugClientAreaStopPropertyMapper::create
- );
- private final Function> findAreaStops;
-
- public AreaStopsLayerBuilder(
- TransitService transitService,
- LayerParameters layerParameters,
- Locale locale
- ) {
- super(
- mappers.get(MapperType.valueOf(layerParameters.mapper())).build(transitService, locale),
- layerParameters.name(),
- layerParameters.expansionFactor()
- );
- this.findAreaStops = transitService::findAreaStops;
- }
-
- @Override
- protected List getGeometries(Envelope query) {
- return findAreaStops
- .apply(query)
- .stream()
- .map(areaStop -> {
- Geometry geometry = areaStop.getGeometry().copy();
-
- geometry.setUserData(areaStop);
-
- return geometry;
- })
- .toList();
- }
-
- enum MapperType {
- DebugClient,
- }
-
- @FunctionalInterface
- private interface MapperFactory {
- PropertyMapper build(TransitService transitService, Locale locale);
- }
-}
diff --git a/src/main/java/org/opentripplanner/inspector/vector/DebugClientAreaStopPropertyMapper.java b/src/main/java/org/opentripplanner/inspector/vector/DebugClientAreaStopPropertyMapper.java
deleted file mode 100644
index 88f7a17385b..00000000000
--- a/src/main/java/org/opentripplanner/inspector/vector/DebugClientAreaStopPropertyMapper.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.opentripplanner.inspector.vector;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Locale;
-import org.opentripplanner.api.mapping.I18NStringMapper;
-import org.opentripplanner.api.mapping.PropertyMapper;
-import org.opentripplanner.transit.model.site.AreaStop;
-import org.opentripplanner.transit.service.TransitService;
-
-/**
- * A {@link PropertyMapper} for the {@link AreaStopsLayerBuilder} for the OTP debug client.
- */
-public class DebugClientAreaStopPropertyMapper extends PropertyMapper {
-
- private final I18NStringMapper i18NStringMapper;
-
- public DebugClientAreaStopPropertyMapper(TransitService transitService, Locale locale) {
- this.i18NStringMapper = new I18NStringMapper(locale);
- }
-
- public static PropertyMapper create(TransitService transitService, Locale locale) {
- return new DebugClientAreaStopPropertyMapper(transitService, locale);
- }
-
- @Override
- protected Collection map(AreaStop input) {
- return List.of(
- new KeyValue("id", input.getId().toString()),
- new KeyValue("name", i18NStringMapper.mapNonnullToApi(input.getName()))
- );
- }
-}
diff --git a/src/main/java/org/opentripplanner/inspector/vector/KeyValue.java b/src/main/java/org/opentripplanner/inspector/vector/KeyValue.java
index d57afd3429e..6c8b0f3aa4e 100644
--- a/src/main/java/org/opentripplanner/inspector/vector/KeyValue.java
+++ b/src/main/java/org/opentripplanner/inspector/vector/KeyValue.java
@@ -1,3 +1,7 @@
package org.opentripplanner.inspector.vector;
-public record KeyValue(String key, Object value) {}
+public record KeyValue(String key, Object value) {
+ public static KeyValue kv(String key, Object value) {
+ return new KeyValue(key, value);
+ }
+}
diff --git a/src/main/java/org/opentripplanner/inspector/vector/LayerBuilder.java b/src/main/java/org/opentripplanner/inspector/vector/LayerBuilder.java
index 3e796487271..949bbef0a94 100644
--- a/src/main/java/org/opentripplanner/inspector/vector/LayerBuilder.java
+++ b/src/main/java/org/opentripplanner/inspector/vector/LayerBuilder.java
@@ -10,7 +10,7 @@
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
-import org.opentripplanner.api.mapping.PropertyMapper;
+import org.opentripplanner.apis.support.mapping.PropertyMapper;
import org.opentripplanner.framework.geometry.GeometryUtils;
/**
diff --git a/src/main/java/org/opentripplanner/inspector/vector/LayerParameters.java b/src/main/java/org/opentripplanner/inspector/vector/LayerParameters.java
index 2718c649797..ca4a6a64c76 100644
--- a/src/main/java/org/opentripplanner/inspector/vector/LayerParameters.java
+++ b/src/main/java/org/opentripplanner/inspector/vector/LayerParameters.java
@@ -1,6 +1,6 @@
package org.opentripplanner.inspector.vector;
-import org.opentripplanner.api.mapping.PropertyMapper;
+import org.opentripplanner.apis.support.mapping.PropertyMapper;
/**
* Configuration options for a single vector tile layer.
diff --git a/src/main/java/org/opentripplanner/inspector/vector/geofencing/GeofencingZonesLayerBuilder.java b/src/main/java/org/opentripplanner/inspector/vector/geofencing/GeofencingZonesLayerBuilder.java
index 8a77b8502ea..24be8d202a8 100644
--- a/src/main/java/org/opentripplanner/inspector/vector/geofencing/GeofencingZonesLayerBuilder.java
+++ b/src/main/java/org/opentripplanner/inspector/vector/geofencing/GeofencingZonesLayerBuilder.java
@@ -1,10 +1,8 @@
package org.opentripplanner.inspector.vector.geofencing;
import java.util.List;
-import java.util.Map;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
-import org.opentripplanner.api.mapping.PropertyMapper;
import org.opentripplanner.framework.geometry.GeometryUtils;
import org.opentripplanner.inspector.vector.LayerBuilder;
import org.opentripplanner.inspector.vector.LayerParameters;
@@ -19,15 +17,11 @@
*/
public class GeofencingZonesLayerBuilder extends LayerBuilder {
- private static final Map mappers = Map.of(
- MapperType.DebugClient,
- transitService -> new GeofencingZonesPropertyMapper()
- );
private final StreetIndex streetIndex;
public GeofencingZonesLayerBuilder(Graph graph, LayerParameters layerParameters) {
super(
- mappers.get(MapperType.valueOf(layerParameters.mapper())).build(graph),
+ new GeofencingZonesPropertyMapper(),
layerParameters.name(),
layerParameters.expansionFactor()
);
@@ -47,13 +41,4 @@ protected List getGeometries(Envelope query) {
})
.toList();
}
-
- enum MapperType {
- DebugClient,
- }
-
- @FunctionalInterface
- private interface MapperFactory {
- PropertyMapper build(Graph transitService);
- }
}
diff --git a/src/main/java/org/opentripplanner/inspector/vector/geofencing/GeofencingZonesPropertyMapper.java b/src/main/java/org/opentripplanner/inspector/vector/geofencing/GeofencingZonesPropertyMapper.java
index 0d0f7b44fe9..98c9cf23eca 100644
--- a/src/main/java/org/opentripplanner/inspector/vector/geofencing/GeofencingZonesPropertyMapper.java
+++ b/src/main/java/org/opentripplanner/inspector/vector/geofencing/GeofencingZonesPropertyMapper.java
@@ -6,7 +6,7 @@
import java.util.Collection;
import java.util.List;
-import org.opentripplanner.api.mapping.PropertyMapper;
+import org.opentripplanner.apis.support.mapping.PropertyMapper;
import org.opentripplanner.inspector.vector.KeyValue;
import org.opentripplanner.street.model.vertex.Vertex;
diff --git a/src/main/java/org/opentripplanner/inspector/vector/stop/StopLayerBuilder.java b/src/main/java/org/opentripplanner/inspector/vector/stop/StopLayerBuilder.java
new file mode 100644
index 00000000000..70ce6a58735
--- /dev/null
+++ b/src/main/java/org/opentripplanner/inspector/vector/stop/StopLayerBuilder.java
@@ -0,0 +1,49 @@
+package org.opentripplanner.inspector.vector.stop;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.function.Function;
+import org.locationtech.jts.geom.Envelope;
+import org.locationtech.jts.geom.Geometry;
+import org.opentripplanner.inspector.vector.LayerBuilder;
+import org.opentripplanner.inspector.vector.LayerParameters;
+import org.opentripplanner.transit.model.site.AreaStop;
+import org.opentripplanner.transit.model.site.RegularStop;
+import org.opentripplanner.transit.model.site.StopLocation;
+
+/**
+ * A vector tile layer for {@link StopLocation}s inside the vector tile bounds. These can be further
+ * filtered to get only a subset of stop implementations like {@link RegularStop}
+ * or {@link AreaStop}.
+ */
+public class StopLayerBuilder extends LayerBuilder {
+
+ private final Function> findStops;
+
+ public StopLayerBuilder(
+ LayerParameters layerParameters,
+ Locale locale,
+ Function> findStops
+ ) {
+ super(
+ new StopLocationPropertyMapper(locale),
+ layerParameters.name(),
+ layerParameters.expansionFactor()
+ );
+ this.findStops = findStops;
+ }
+
+ @Override
+ protected List getGeometries(Envelope query) {
+ return findStops
+ .apply(query)
+ .stream()
+ .map(stop -> {
+ Geometry geometry = stop.getGeometry().copy();
+ geometry.setUserData(stop);
+ return geometry;
+ })
+ .toList();
+ }
+}
diff --git a/src/main/java/org/opentripplanner/inspector/vector/stop/StopLocationPropertyMapper.java b/src/main/java/org/opentripplanner/inspector/vector/stop/StopLocationPropertyMapper.java
new file mode 100644
index 00000000000..ab9685dd0f6
--- /dev/null
+++ b/src/main/java/org/opentripplanner/inspector/vector/stop/StopLocationPropertyMapper.java
@@ -0,0 +1,32 @@
+package org.opentripplanner.inspector.vector.stop;
+
+import static org.opentripplanner.inspector.vector.KeyValue.kv;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import org.opentripplanner.apis.support.mapping.PropertyMapper;
+import org.opentripplanner.framework.i18n.I18NStringMapper;
+import org.opentripplanner.inspector.vector.KeyValue;
+import org.opentripplanner.transit.model.site.StopLocation;
+
+/**
+ * A {@link PropertyMapper} for the {@link StopLocationPropertyMapper} for the OTP debug client.
+ */
+public class StopLocationPropertyMapper extends PropertyMapper {
+
+ private final I18NStringMapper i18NStringMapper;
+
+ public StopLocationPropertyMapper(Locale locale) {
+ this.i18NStringMapper = new I18NStringMapper(locale);
+ }
+
+ @Override
+ protected Collection map(StopLocation stop) {
+ return List.of(
+ kv("name", i18NStringMapper.mapToApi(stop.getName())),
+ kv("id", stop.getId().toString()),
+ kv("parentId", stop.isPartOfStation() ? stop.getParentStation().getId().toString() : null)
+ );
+ }
+}
diff --git a/src/main/java/org/opentripplanner/netex/mapping/NetexMapper.java b/src/main/java/org/opentripplanner/netex/mapping/NetexMapper.java
index 8fc30ae166a..30bd04eea73 100644
--- a/src/main/java/org/opentripplanner/netex/mapping/NetexMapper.java
+++ b/src/main/java/org/opentripplanner/netex/mapping/NetexMapper.java
@@ -11,7 +11,6 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import java.util.stream.Collectors;
import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore;
import org.opentripplanner.model.StopTime;
import org.opentripplanner.model.calendar.ServiceCalendar;
diff --git a/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapper.java b/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapper.java
index f0d06b8871d..765a9b5c47f 100644
--- a/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapper.java
+++ b/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapper.java
@@ -26,7 +26,6 @@
import org.opentripplanner.transit.model.framework.ImmutableEntityById;
import org.opentripplanner.transit.model.network.StopPattern;
import org.opentripplanner.transit.model.network.TripPattern;
-import org.opentripplanner.transit.model.network.TripPatternBuilder;
import org.opentripplanner.transit.model.organization.Operator;
import org.opentripplanner.transit.model.site.AreaStop;
import org.opentripplanner.transit.model.site.GroupStop;
diff --git a/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapperResult.java b/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapperResult.java
index f2f75cd2561..370c24a7a41 100644
--- a/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapperResult.java
+++ b/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapperResult.java
@@ -1,13 +1,10 @@
package org.opentripplanner.netex.mapping;
import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Multimap;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.opentripplanner.model.StopTime;
-import org.opentripplanner.transit.model.network.StopPattern;
import org.opentripplanner.transit.model.network.TripPattern;
import org.opentripplanner.transit.model.timetable.Trip;
import org.opentripplanner.transit.model.timetable.TripOnServiceDate;
diff --git a/src/main/java/org/opentripplanner/raptor/api/model/RaptorTripPattern.java b/src/main/java/org/opentripplanner/raptor/api/model/RaptorTripPattern.java
index 98a2533486b..e5be1cab0d5 100644
--- a/src/main/java/org/opentripplanner/raptor/api/model/RaptorTripPattern.java
+++ b/src/main/java/org/opentripplanner/raptor/api/model/RaptorTripPattern.java
@@ -46,7 +46,7 @@ public interface RaptorTripPattern {
int slackIndex();
/**
- * A pattern may belong to a transit-priority-group. Each group is given an advantage during
+ * A pattern may belong to a transit-group-priority. Each group is given an advantage during
* the multi-criteria search, so the best alternative for each group is found.
*/
int priorityGroupId();
diff --git a/src/main/java/org/opentripplanner/raptor/api/request/MultiCriteriaRequest.java b/src/main/java/org/opentripplanner/raptor/api/request/MultiCriteriaRequest.java
index 64cd9dae1a5..368b4660922 100644
--- a/src/main/java/org/opentripplanner/raptor/api/request/MultiCriteriaRequest.java
+++ b/src/main/java/org/opentripplanner/raptor/api/request/MultiCriteriaRequest.java
@@ -18,7 +18,7 @@ public class MultiCriteriaRequest {
private final RelaxFunction relaxC1;
@Nullable
- private final RaptorTransitPriorityGroupCalculator transitPriorityCalculator;
+ private final RaptorTransitGroupCalculator transitPriorityCalculator;
private final List passThroughPoints;
@@ -63,7 +63,7 @@ public RelaxFunction relaxC1() {
return relaxC1;
}
- public Optional transitPriorityCalculator() {
+ public Optional transitPriorityCalculator() {
return Optional.ofNullable(transitPriorityCalculator);
}
@@ -140,7 +140,7 @@ public static class Builder {
private final MultiCriteriaRequest original;
private RelaxFunction relaxC1;
- private RaptorTransitPriorityGroupCalculator transitPriorityCalculator;
+ private RaptorTransitGroupCalculator transitPriorityCalculator;
private List passThroughPoints;
private Double relaxCostAtDestination;
@@ -163,11 +163,11 @@ public Builder withRelaxC1(RelaxFunction relaxC1) {
}
@Nullable
- public RaptorTransitPriorityGroupCalculator transitPriorityCalculator() {
+ public RaptorTransitGroupCalculator transitPriorityCalculator() {
return transitPriorityCalculator;
}
- public Builder withTransitPriorityCalculator(RaptorTransitPriorityGroupCalculator value) {
+ public Builder withTransitPriorityCalculator(RaptorTransitGroupCalculator value) {
transitPriorityCalculator = value;
return this;
}
diff --git a/src/main/java/org/opentripplanner/raptor/api/request/RaptorTransitPriorityGroupCalculator.java b/src/main/java/org/opentripplanner/raptor/api/request/RaptorTransitGroupCalculator.java
similarity index 71%
rename from src/main/java/org/opentripplanner/raptor/api/request/RaptorTransitPriorityGroupCalculator.java
rename to src/main/java/org/opentripplanner/raptor/api/request/RaptorTransitGroupCalculator.java
index c3890fa47b3..b5f0598415e 100644
--- a/src/main/java/org/opentripplanner/raptor/api/request/RaptorTransitPriorityGroupCalculator.java
+++ b/src/main/java/org/opentripplanner/raptor/api/request/RaptorTransitGroupCalculator.java
@@ -2,19 +2,19 @@
import org.opentripplanner.raptor.api.model.DominanceFunction;
-public interface RaptorTransitPriorityGroupCalculator {
+public interface RaptorTransitGroupCalculator {
/**
- * Merge in the trip transit priority group id with an existing set. Note! Both the set
+ * Merge in the transit group id with an existing set. Note! Both the set
* and the group id type is {@code int}.
*
* @param currentGroupIds the set of groupIds for all legs in a path.
* @param boardingGroupId the transit group id to add to the given set.
* @return the new computed set of groupIds
*/
- int mergeTransitPriorityGroupIds(int currentGroupIds, int boardingGroupId);
+ int mergeGroupIds(int currentGroupIds, int boardingGroupId);
/**
- * This is the dominance function to use for comparing transit-priority-groupIds.
+ * This is the dominance function to use for comparing transit-groups.
* It is critical that the implementation is "static" so it can be inlined, since it
* is run in the innermost loop of Raptor.
*/
diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/SystemErrDebugLogger.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/SystemErrDebugLogger.java
index 060d3a2e018..951721f81a7 100644
--- a/src/main/java/org/opentripplanner/raptor/rangeraptor/SystemErrDebugLogger.java
+++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/SystemErrDebugLogger.java
@@ -43,14 +43,14 @@ public class SystemErrDebugLogger implements DebugLogger {
private final Table arrivalTable = Table
.of()
.withAlights(Center, Center, Right, Right, Right, Right, Left, Left)
- .withHeaders("ARRIVAL", "LEG", "RND", "STOP", "ARRIVE", "COST", "TRIP", "DETAILS")
+ .withHeaders("ARRIVAL", "LEG", "RND", "STOP", "ARRIVE", "C₁", "TRIP", "DETAILS")
.withMinWidths(9, 7, 3, 5, 8, 9, 24, 0)
.build();
private final Table pathTable = Table
.of()
.withAlights(Center, Center, Right, Right, Right, Right, Right, Right, Left)
- .withHeaders(">>> PATH", "TR", "FROM", "TO", "START", "END", "DURATION", "COST", "DETAILS")
- .withMinWidths(9, 2, 5, 5, 8, 8, 8, 6, 0)
+ .withHeaders(">>> PATH", "TR", "FROM", "TO", "START", "END", "DURATION", "C₁", "DETAILS")
+ .withMinWidths(9, 2, 5, 5, 8, 8, 8, 9, 0)
.build();
private boolean forwardSearch = true;
private int lastIterationTime = NOT_SET;
@@ -112,6 +112,7 @@ public void pathFilteringListener(DebugEvent> e) {
RaptorPath> p = e.element();
var aLeg = p.accessLeg();
var eLeg = p.egressLeg();
+
println(
pathTable.rowAsText(
e.action().toString(),
diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/PassThroughPointsService.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/PassThroughPointsService.java
index 69899b55688..4932d9c46fe 100644
--- a/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/PassThroughPointsService.java
+++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/PassThroughPointsService.java
@@ -54,7 +54,7 @@ default boolean isNoop() {
void updateC2Value(int currentPathC2, IntConsumer update);
/**
- * This is the dominance function to use for comparing transit-priority-groupIds.
+ * This is the dominance function to use for comparing transit-group-priorityIds.
* It is critical that the implementation is "static" so it can be inlined, since it
* is run in the innermost loop of Raptor.
*/
diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/configure/McRangeRaptorConfig.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/configure/McRangeRaptorConfig.java
index e7aa07fb914..8eef90950dd 100644
--- a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/configure/McRangeRaptorConfig.java
+++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/configure/McRangeRaptorConfig.java
@@ -6,7 +6,7 @@
import org.opentripplanner.raptor.api.model.DominanceFunction;
import org.opentripplanner.raptor.api.model.RaptorTripSchedule;
import org.opentripplanner.raptor.api.request.MultiCriteriaRequest;
-import org.opentripplanner.raptor.api.request.RaptorTransitPriorityGroupCalculator;
+import org.opentripplanner.raptor.api.request.RaptorTransitGroupCalculator;
import org.opentripplanner.raptor.rangeraptor.context.SearchContext;
import org.opentripplanner.raptor.rangeraptor.internalapi.Heuristics;
import org.opentripplanner.raptor.rangeraptor.internalapi.ParetoSetCost;
@@ -29,7 +29,7 @@
import org.opentripplanner.raptor.rangeraptor.multicriteria.ride.c1.PatternRideC1;
import org.opentripplanner.raptor.rangeraptor.multicriteria.ride.c2.PassThroughRideFactory;
import org.opentripplanner.raptor.rangeraptor.multicriteria.ride.c2.PatternRideC2;
-import org.opentripplanner.raptor.rangeraptor.multicriteria.ride.c2.TransitPriorityGroupRideFactory;
+import org.opentripplanner.raptor.rangeraptor.multicriteria.ride.c2.TransitGroupPriorityRideFactory;
import org.opentripplanner.raptor.rangeraptor.path.DestinationArrivalPaths;
import org.opentripplanner.raptor.rangeraptor.path.configure.PathConfig;
import org.opentripplanner.raptor.util.paretoset.ParetoComparator;
@@ -173,7 +173,8 @@ private MultiCriteriaRequest mcRequest() {
}
/**
- * Currently "transit-priority-groups" is the only feature using two multi-criteria(c2).
+ * Use c2 in the search, this is use-case specific. For example the pass-through or
+ * transit-group-priority features uses the c2 value.
*/
private boolean includeC2() {
return mcRequest().includeC2();
@@ -184,7 +185,7 @@ private PatternRideFactory> createPatternRideC2Factory() {
return new PassThroughRideFactory<>(passThroughPointsService);
}
if (isTransitPriority()) {
- return new TransitPriorityGroupRideFactory<>(getTransitPriorityGroupCalculator());
+ return new TransitGroupPriorityRideFactory<>(getTransitGroupPriorityCalculator());
}
throw new IllegalStateException("Only pass-through and transit-priority uses c2.");
}
@@ -195,12 +196,12 @@ private DominanceFunction dominanceFunctionC2() {
return passThroughPointsService.dominanceFunction();
}
if (isTransitPriority()) {
- return getTransitPriorityGroupCalculator().dominanceFunction();
+ return getTransitGroupPriorityCalculator().dominanceFunction();
}
return null;
}
- private RaptorTransitPriorityGroupCalculator getTransitPriorityGroupCalculator() {
+ private RaptorTransitGroupCalculator getTransitGroupPriorityCalculator() {
return mcRequest().transitPriorityCalculator().orElseThrow();
}
diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/ride/c2/TransitPriorityGroupRideFactory.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/ride/c2/TransitGroupPriorityRideFactory.java
similarity index 67%
rename from src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/ride/c2/TransitPriorityGroupRideFactory.java
rename to src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/ride/c2/TransitGroupPriorityRideFactory.java
index eca049233b9..5d65c40d021 100644
--- a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/ride/c2/TransitPriorityGroupRideFactory.java
+++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/ride/c2/TransitGroupPriorityRideFactory.java
@@ -2,25 +2,25 @@
import org.opentripplanner.raptor.api.model.RaptorTripPattern;
import org.opentripplanner.raptor.api.model.RaptorTripSchedule;
-import org.opentripplanner.raptor.api.request.RaptorTransitPriorityGroupCalculator;
+import org.opentripplanner.raptor.api.request.RaptorTransitGroupCalculator;
import org.opentripplanner.raptor.rangeraptor.multicriteria.arrivals.McStopArrival;
import org.opentripplanner.raptor.rangeraptor.multicriteria.ride.PatternRide;
import org.opentripplanner.raptor.rangeraptor.multicriteria.ride.PatternRideFactory;
/**
- * This factory creates new {@link PatternRide}s and merge in transit-priority-group ids
+ * This factory creates new {@link PatternRide}s and merge in transit-group-priority ids
* into c2.
*/
-public class TransitPriorityGroupRideFactory
+public class TransitGroupPriorityRideFactory
implements PatternRideFactory> {
private int currentPatternGroupPriority;
- private final RaptorTransitPriorityGroupCalculator transitPriorityGroupCalculator;
+ private final RaptorTransitGroupCalculator transitGroupPriorityCalculator;
- public TransitPriorityGroupRideFactory(
- RaptorTransitPriorityGroupCalculator transitPriorityGroupCalculator
+ public TransitGroupPriorityRideFactory(
+ RaptorTransitGroupCalculator transitGroupPriorityCalculator
) {
- this.transitPriorityGroupCalculator = transitPriorityGroupCalculator;
+ this.transitGroupPriorityCalculator = transitGroupPriorityCalculator;
}
@Override
@@ -52,12 +52,9 @@ public void prepareForTransitWith(RaptorTripPattern pattern) {
}
/**
- * Currently transit-priority-group is the only usage of c2
+ * Currently transit-group-priority is the only usage of c2
*/
private int calculateC2(int c2) {
- return transitPriorityGroupCalculator.mergeTransitPriorityGroupIds(
- c2,
- currentPatternGroupPriority
- );
+ return transitGroupPriorityCalculator.mergeGroupIds(c2, currentPatternGroupPriority);
}
}
diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessEgressFunctions.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessEgressFunctions.java
index 5059be84312..1ab737ae907 100644
--- a/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessEgressFunctions.java
+++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessEgressFunctions.java
@@ -5,12 +5,15 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Objects;
import java.util.function.Predicate;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;
import org.opentripplanner.raptor.api.model.RaptorAccessEgress;
import org.opentripplanner.raptor.util.paretoset.ParetoComparator;
import org.opentripplanner.raptor.util.paretoset.ParetoSet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* This class contains functions used by the {@link AccessPaths} and {@link EgressPaths} classes.
@@ -23,8 +26,10 @@
*/
public final class AccessEgressFunctions {
+ private static final Logger LOG = LoggerFactory.getLogger(AccessEgressFunctions.class);
+
/**
- * Filter standard(not multi-criteria) Raptor access and egress paths. A path is pareto optimal
+ * Filter standard (not multi-criteria) Raptor access and egress paths. A path is pareto optimal
* for a given stop if
*
*
@@ -47,32 +52,57 @@ public final class AccessEgressFunctions {
*
*/
private static final ParetoComparator STANDARD_COMPARATOR = (l, r) ->
- (l.stopReachedOnBoard() && !r.stopReachedOnBoard()) ||
- r.hasOpeningHours() ||
- (l.numberOfRides() < r.numberOfRides()) ||
- (l.durationInSeconds() < r.durationInSeconds());
+ (
+ (l.stopReachedOnBoard() && !r.stopReachedOnBoard()) ||
+ r.hasOpeningHours() ||
+ l.numberOfRides() < r.numberOfRides() ||
+ l.durationInSeconds() < r.durationInSeconds()
+ );
+
+ /**
+ * Filter Multi-criteria Raptor access and egress paths. This can be used to wash
+ * access/egress paths - paths that are not optimal using this should not be passed into
+ * Raptor - it is a bug.
+ */
+ private static final ParetoComparator MC_COMPARATOR = (l, r) ->
+ STANDARD_COMPARATOR.leftDominanceExist(l, r) || l.c1() < r.c1();
/** private constructor to prevent instantiation of utils class. */
private AccessEgressFunctions() {}
- static Collection removeNoneOptimalPathsForStandardRaptor(
+ /**
+ * Filter non-optimal paths away for the standard search. This method does not
+ * look at the c1 value.
+ */
+ static Collection removeNonOptimalPathsForStandardRaptor(
Collection paths
) {
- // To avoid too many items in the pareto set we first group the paths by stop,
- // for each stop we filter it down to the optimal pareto set. We could do this
- // for multi-criteria as well, but it is likely not so important. The focus for
- // the mc-set should be that the list of access/egress created in OTP should not
- // contain to many non-optimal paths.
- var mapByStop = groupByStop(paths);
- var set = new ParetoSet<>(STANDARD_COMPARATOR);
- Collection result = new ArrayList<>();
+ return removeNonOptimalPaths(paths, STANDARD_COMPARATOR);
+ }
- mapByStop.forEachValue(list -> {
- set.clear();
- set.addAll(list);
- result.addAll(set);
- return true;
- });
+ /**
+ * Filter non-optimal paths away for the multi-criteria search. This method should in theory
+ * not remove any paths since the caller should not pass in duplicates, but it turns out that
+ * this happens, so we do it.
+ */
+ static Collection removeNonOptimalPathsForMcRaptor(
+ Collection paths
+ ) {
+ var result = removeNonOptimalPaths(paths, MC_COMPARATOR);
+ if (LOG.isDebugEnabled() && result.size() < paths.size()) {
+ var duplicates = new ArrayList<>(paths);
+ duplicates.removeAll(result);
+ // Note! This does not provide enough information to solve/debug this problem, but this is
+ // not a problem in Raptor, so we do not want to add more specific logging here - this does
+ // however document that the problem exist. Turn on debug logging and move the start/end
+ // coordinate around until you see this message.
+ //
+ // See https://github.com/opentripplanner/OpenTripPlanner/issues/5601
+ LOG.warn(
+ "Duplicate access/egress paths passed into raptor:\n\t" +
+ duplicates.stream().map(Objects::toString).collect(Collectors.joining("\n\t"))
+ );
+ }
return result;
}
@@ -96,6 +126,27 @@ static TIntObjectMap> groupByStop(Collection removeNonOptimalPaths(
+ Collection paths,
+ ParetoComparator comparator
+ ) {
+ var mapByStop = groupByStop(paths);
+ var set = new ParetoSet<>(comparator);
+ var result = new ArrayList();
+
+ for (int stop : mapByStop.keys()) {
+ var list = mapByStop.get(stop);
+ set.clear();
+ set.addAll(list);
+ result.addAll(set);
+ }
+ return result;
+ }
+
private static List getOrCreate(
int key,
TIntObjectMap> map
diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java
index 940937f82db..5c26a10db23 100644
--- a/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java
+++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java
@@ -1,7 +1,8 @@
package org.opentripplanner.raptor.rangeraptor.transit;
import static org.opentripplanner.raptor.rangeraptor.transit.AccessEgressFunctions.groupByRound;
-import static org.opentripplanner.raptor.rangeraptor.transit.AccessEgressFunctions.removeNoneOptimalPathsForStandardRaptor;
+import static org.opentripplanner.raptor.rangeraptor.transit.AccessEgressFunctions.removeNonOptimalPathsForMcRaptor;
+import static org.opentripplanner.raptor.rangeraptor.transit.AccessEgressFunctions.removeNonOptimalPathsForStandardRaptor;
import gnu.trove.map.TIntObjectMap;
import java.util.Arrays;
@@ -57,8 +58,10 @@ public int calculateMaxNumberOfRides() {
* This method is static and package local to enable unit-testing.
*/
public static AccessPaths create(Collection paths, RaptorProfile profile) {
- if (!profile.is(RaptorProfile.MULTI_CRITERIA)) {
- paths = removeNoneOptimalPathsForStandardRaptor(paths);
+ if (profile.is(RaptorProfile.MULTI_CRITERIA)) {
+ paths = removeNonOptimalPathsForMcRaptor(paths);
+ } else {
+ paths = removeNonOptimalPathsForStandardRaptor(paths);
}
return new AccessPaths(
groupByRound(paths, RaptorAccessEgress::stopReachedByWalking),
diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/EgressPaths.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/EgressPaths.java
index 2038ab543df..374fc050782 100644
--- a/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/EgressPaths.java
+++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/EgressPaths.java
@@ -2,7 +2,8 @@
import static org.opentripplanner.raptor.api.request.RaptorProfile.MULTI_CRITERIA;
import static org.opentripplanner.raptor.rangeraptor.transit.AccessEgressFunctions.groupByStop;
-import static org.opentripplanner.raptor.rangeraptor.transit.AccessEgressFunctions.removeNoneOptimalPathsForStandardRaptor;
+import static org.opentripplanner.raptor.rangeraptor.transit.AccessEgressFunctions.removeNonOptimalPathsForMcRaptor;
+import static org.opentripplanner.raptor.rangeraptor.transit.AccessEgressFunctions.removeNonOptimalPathsForStandardRaptor;
import gnu.trove.map.TIntObjectMap;
import java.util.Collection;
@@ -31,8 +32,10 @@ private EgressPaths(TIntObjectMap> pathsByStop) {
* This method is static and package local to enable unit-testing.
*/
public static EgressPaths create(Collection paths, RaptorProfile profile) {
- if (!MULTI_CRITERIA.is(profile)) {
- paths = removeNoneOptimalPathsForStandardRaptor(paths);
+ if (MULTI_CRITERIA.is(profile)) {
+ paths = removeNonOptimalPathsForMcRaptor(paths);
+ } else {
+ paths = removeNonOptimalPathsForStandardRaptor(paths);
}
return new EgressPaths(groupByStop(paths));
}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/grouppriority/TransitPriorityGroup32n.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/grouppriority/TransitGroupPriority32n.java
similarity index 76%
rename from src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/grouppriority/TransitPriorityGroup32n.java
rename to src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/grouppriority/TransitGroupPriority32n.java
index 9b744932b8b..feb3f6f7b3a 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/grouppriority/TransitPriorityGroup32n.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/grouppriority/TransitGroupPriority32n.java
@@ -1,33 +1,33 @@
package org.opentripplanner.routing.algorithm.raptoradapter.transit.cost.grouppriority;
import org.opentripplanner.raptor.api.model.DominanceFunction;
-import org.opentripplanner.raptor.api.request.RaptorTransitPriorityGroupCalculator;
+import org.opentripplanner.raptor.api.request.RaptorTransitGroupCalculator;
/**
* This is a "BitSet" implementation for groupId. It can store upto 32 groups,
* a set with few elements does NOT dominate a set with more elements.
*/
-public class TransitPriorityGroup32n {
+public class TransitGroupPriority32n {
private static final int GROUP_ZERO = 0;
private static final int MIN_SEQ_NO = 0;
private static final int MAX_SEQ_NO = 32;
- public static RaptorTransitPriorityGroupCalculator priorityCalculator() {
- return new RaptorTransitPriorityGroupCalculator() {
+ public static RaptorTransitGroupCalculator priorityCalculator() {
+ return new RaptorTransitGroupCalculator() {
@Override
- public int mergeTransitPriorityGroupIds(int currentGroupIds, int boardingGroupId) {
+ public int mergeGroupIds(int currentGroupIds, int boardingGroupId) {
return mergeInGroupId(currentGroupIds, boardingGroupId);
}
@Override
public DominanceFunction dominanceFunction() {
- return TransitPriorityGroup32n::dominate;
+ return TransitGroupPriority32n::dominate;
}
@Override
public String toString() {
- return "TransitPriorityGroup32nCalculator{}";
+ return "TransitGroupPriority32nCalculator{}";
}
};
}
@@ -42,7 +42,7 @@ public static boolean dominate(int left, int right) {
@Override
public String toString() {
- return "TransitPriorityGroup32n{}";
+ return "TransitGroupPriority32n{}";
}
/**
@@ -64,12 +64,12 @@ public static int mergeInGroupId(final int currentSetOfGroupIds, final int newGr
private static void assertValidGroupSeqNo(int priorityGroupIndex) {
if (priorityGroupIndex < MIN_SEQ_NO) {
throw new IllegalArgumentException(
- "Transit priority group can not be a negative number: " + priorityGroupIndex
+ "Transit group priority can not be a negative number: " + priorityGroupIndex
);
}
if (priorityGroupIndex > MAX_SEQ_NO) {
throw new IllegalArgumentException(
- "Transit priority group exceeds max number of groups: " +
+ "Transit group priority exceeds max number of groups: " +
priorityGroupIndex +
" (MAX=" +
MAX_SEQ_NO +
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java
index 75c1bcf7214..5f3b4b13746 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java
@@ -13,6 +13,7 @@
import org.opentripplanner.raptor.api.model.RaptorAccessEgress;
import org.opentripplanner.raptor.api.model.RaptorConstants;
import org.opentripplanner.raptor.api.model.RelaxFunction;
+import org.opentripplanner.raptor.api.request.DebugRequestBuilder;
import org.opentripplanner.raptor.api.request.Optimization;
import org.opentripplanner.raptor.api.request.PassThroughPoint;
import org.opentripplanner.raptor.api.request.RaptorRequest;
@@ -21,7 +22,8 @@
import org.opentripplanner.routing.algorithm.raptoradapter.router.performance.PerformanceTimersForRaptor;
import org.opentripplanner.routing.algorithm.raptoradapter.transit.TripSchedule;
import org.opentripplanner.routing.algorithm.raptoradapter.transit.cost.RaptorCostConverter;
-import org.opentripplanner.routing.algorithm.raptoradapter.transit.cost.grouppriority.TransitPriorityGroup32n;
+import org.opentripplanner.routing.algorithm.raptoradapter.transit.cost.grouppriority.TransitGroupPriority32n;
+import org.opentripplanner.routing.api.request.DebugEventType;
import org.opentripplanner.routing.api.request.RouteRequest;
import org.opentripplanner.routing.api.request.framework.CostLinearFunction;
import org.opentripplanner.transit.model.site.StopLocation;
@@ -117,9 +119,9 @@ private RaptorRequest doMap() {
builder.withMultiCriteria(mcBuilder -> {
var pt = preferences.transit();
var r = pt.raptor();
- if (!pt.relaxTransitPriorityGroup().isNormal()) {
- mcBuilder.withTransitPriorityCalculator(TransitPriorityGroup32n.priorityCalculator());
- mcBuilder.withRelaxC1(mapRelaxCost(pt.relaxTransitPriorityGroup()));
+ if (!pt.relaxTransitGroupPriority().isNormal()) {
+ mcBuilder.withTransitPriorityCalculator(TransitGroupPriority32n.priorityCalculator());
+ mcBuilder.withRelaxC1(mapRelaxCost(pt.relaxTransitGroupPriority()));
} else {
mcBuilder.withPassThroughPoints(mapPassThroughPoints());
r.relaxGeneralizedCostAtDestination().ifPresent(mcBuilder::withRelaxCostAtDestination);
@@ -156,10 +158,11 @@ private RaptorRequest doMap() {
.addStops(raptorDebugging.stops())
.setPath(raptorDebugging.path())
.debugPathFromStopIndex(raptorDebugging.debugPathFromStopIndex())
- .stopArrivalListener(debugLogger::stopArrivalLister)
- .patternRideDebugListener(debugLogger::patternRideLister)
- .pathFilteringListener(debugLogger::pathFilteringListener)
.logger(debugLogger);
+
+ for (var type : raptorDebugging.eventTypes()) {
+ addLogListenerForEachEventTypeRequested(debug, type, debugLogger);
+ }
}
if (!request.timetableView() && request.arriveBy()) {
@@ -209,4 +212,16 @@ private int relativeTime(Instant time) {
}
return (int) (time.getEpochSecond() - transitSearchTimeZeroEpocSecond);
}
+
+ private static void addLogListenerForEachEventTypeRequested(
+ DebugRequestBuilder target,
+ DebugEventType type,
+ SystemErrDebugLogger logger
+ ) {
+ switch (type) {
+ case STOP_ARRIVALS -> target.stopArrivalListener(logger::stopArrivalLister);
+ case PATTERN_RIDES -> target.patternRideDebugListener(logger::patternRideLister);
+ case DESTINATION_ARRIVALS -> target.pathFilteringListener(logger::pathFilteringListener);
+ }
+ }
}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfigurator.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfigurator.java
index 25006af49d8..826b9c09a13 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfigurator.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfigurator.java
@@ -8,14 +8,14 @@
import java.util.List;
import java.util.stream.Stream;
import org.opentripplanner.framework.lang.ArrayUtils;
-import org.opentripplanner.routing.algorithm.raptoradapter.transit.cost.grouppriority.TransitPriorityGroup32n;
-import org.opentripplanner.routing.api.request.request.filter.TransitPriorityGroupSelect;
+import org.opentripplanner.routing.algorithm.raptoradapter.transit.cost.grouppriority.TransitGroupPriority32n;
+import org.opentripplanner.routing.api.request.request.filter.TransitGroupSelect;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.transit.model.network.RoutingTripPattern;
/**
* This class dynamically builds an index of transit-group-ids from the
- * provided {@link TransitPriorityGroupSelect}s while serving the caller with
+ * provided {@link TransitGroupSelect}s while serving the caller with
* group-ids for each requested pattern. It is made for optimal
* performance, since it is used in request scope.
*
@@ -44,7 +44,7 @@ public class PriorityGroupConfigurator {
*/
private static final int GROUP_INDEX_COUNTER_START = 1;
- private final int baseGroupId = TransitPriorityGroup32n.groupId(GROUP_INDEX_COUNTER_START);
+ private final int baseGroupId = TransitGroupPriority32n.groupId(GROUP_INDEX_COUNTER_START);
private int groupIndexCounter = GROUP_INDEX_COUNTER_START;
private final boolean enabled;
private final PriorityGroupMatcher[] agencyMatchers;
@@ -63,8 +63,8 @@ private PriorityGroupConfigurator() {
}
private PriorityGroupConfigurator(
- Collection byAgency,
- Collection global
+ Collection byAgency,
+ Collection global
) {
this.agencyMatchers = PriorityGroupMatcher.of(byAgency);
this.globalMatchers = PriorityGroupMatcher.of(global);
@@ -80,8 +80,8 @@ public static PriorityGroupConfigurator empty() {
}
public static PriorityGroupConfigurator of(
- Collection byAgency,
- Collection global
+ Collection byAgency,
+ Collection global
) {
if (Stream.of(byAgency, global).allMatch(Collection::isEmpty)) {
return empty();
@@ -94,7 +94,7 @@ public static PriorityGroupConfigurator of(
*