From 4a0b03b73bfeb8493e13faf2af997359a79c3b6a Mon Sep 17 00:00:00 2001 From: bartosz Date: Mon, 12 Feb 2024 15:39:22 +0100 Subject: [PATCH] Add configuration switch for Service Bus authentication with Federated Identity --- doc-templates/UpdaterConfig.md | 4 +- .../sandbox/siri}/SiriAzureUpdater.md | 27 ++- .../{ => sandbox/siri}/SiriUpdater.md | 0 docs/RouterConfiguration.md | 14 ++ docs/UpdaterConfig.md | 4 +- docs/examples/skanetrafiken/Readme.md | 3 + .../examples/skanetrafiken/router-config.json | 3 +- docs/sandbox/siri/SiriAzureUpdater.md | 197 ++++++++++++++++++ docs/sandbox/{ => siri}/SiriUpdater.md | 0 mkdocs.yml | 4 +- pom.xml | 11 +- .../azure/AbstractAzureSiriUpdater.java | 20 +- .../updater/azure/AuthenticationType.java | 6 + .../azure/SiriAzureUpdaterParameters.java | 18 ++ .../azure/SiriAzureETUpdaterConfig.java | 24 ++- .../azure/SiriAzureSXUpdaterConfig.java | 31 ++- .../azure/SiriAzureUpdaterConfig.java | 58 +++++- .../generate/doc/SiriAzureConfigDocTest.java | 98 +++++++++ .../generate/doc/SiriConfigDocTest.java | 4 +- .../generate/doc/UpdaterConfigDocTest.java | 1 + .../standalone/config/router-config.json | 15 ++ 21 files changed, 495 insertions(+), 47 deletions(-) rename {docs/sandbox => doc-templates/sandbox/siri}/SiriAzureUpdater.md (60%) rename doc-templates/{ => sandbox/siri}/SiriUpdater.md (100%) create mode 100644 docs/sandbox/siri/SiriAzureUpdater.md rename docs/sandbox/{ => siri}/SiriUpdater.md (100%) create mode 100644 src/ext/java/org/opentripplanner/ext/siri/updater/azure/AuthenticationType.java create mode 100644 src/test/java/org/opentripplanner/generate/doc/SiriAzureConfigDocTest.java diff --git a/doc-templates/UpdaterConfig.md b/doc-templates/UpdaterConfig.md index 57152671ec7..b0444f038af 100644 --- a/doc-templates/UpdaterConfig.md +++ b/doc-templates/UpdaterConfig.md @@ -82,7 +82,7 @@ GBFS form factors: ## Other updaters in sandboxes - [Vehicle parking](sandbox/VehicleParking.md) -- [Siri over HTTP](sandbox/SiriUpdater.md) -- [Siri over Azure Message Bus](sandbox/SiriAzureUpdater.md) +- [Siri over HTTP](sandbox/siri/SiriUpdater.md) +- [Siri over Azure Message Bus](sandbox/siri/SiriAzureUpdater.md) - [VehicleRentalServiceDirectory](sandbox/VehicleRentalServiceDirectory.md) diff --git a/docs/sandbox/SiriAzureUpdater.md b/doc-templates/sandbox/siri/SiriAzureUpdater.md similarity index 60% rename from docs/sandbox/SiriAzureUpdater.md rename to doc-templates/sandbox/siri/SiriAzureUpdater.md index 3af3b7ee854..eb092ddd08d 100644 --- a/docs/sandbox/SiriAzureUpdater.md +++ b/doc-templates/sandbox/siri/SiriAzureUpdater.md @@ -8,17 +8,26 @@ IT also OTP to download historical data from en HTTP endpoint on startup. Skånetrafiken, Sweden developer.otp@skanetrafiken.se +## Documentation + +Documentation available [here](../../examples/skanetrafiken/Readme.md). + +## Configuration + +To enable the SIRI updater you need to add it to the updaters section of the `router-config.json`. + +### Siri Azure ET Updater + + + +### Siri Azure SX Updater + + + ## Changelog -- Added configuration for turning off stop arrival time match feature. +- Added configuration for turning off stop arrival time match feature. - Initial version (April 2022) - Minor changes in logging (November 2022) - Retry fetch from history endpoint if it failed (February 2023) - Solve a bug in SiriAzureETUpdater and improve error logging (March 2023) - -## Documentation - -Documentation available [here](../examples/skanetrafiken/Readme.md). - -### Configuration - -See example configuration in `examples/skanetrafiken/router-config.json`. \ No newline at end of file +- Add support with federated identity authentication (February 2024) \ No newline at end of file diff --git a/doc-templates/SiriUpdater.md b/doc-templates/sandbox/siri/SiriUpdater.md similarity index 100% rename from doc-templates/SiriUpdater.md rename to doc-templates/sandbox/siri/SiriUpdater.md diff --git a/docs/RouterConfiguration.md b/docs/RouterConfiguration.md index 73998f06278..34e9aa2c8d6 100644 --- a/docs/RouterConfiguration.md +++ b/docs/RouterConfiguration.md @@ -817,6 +817,20 @@ Used to group requests when monitoring OTP. "toDateTime" : "P1D", "timeout" : 300000 } + }, + { + "type" : "siri-azure-et-updater", + "topic" : "some_topic", + "authenticationType" : "SharedAccessKey", + "fullyQualifiedNamespace" : "fully_qualified_namespace", + "servicebus-url" : "service_bus_url", + "feedId" : "feed_id", + "customMidnight" : 4, + "history" : { + "url" : "endpoint_url", + "fromDateTime" : "-P1D", + "timeout" : 300000 + } } ], "rideHailingServices" : [ diff --git a/docs/UpdaterConfig.md b/docs/UpdaterConfig.md index a819a898240..973874be66a 100644 --- a/docs/UpdaterConfig.md +++ b/docs/UpdaterConfig.md @@ -414,7 +414,7 @@ HTTP headers to add to the request. Any header key, value can be inserted. ## Other updaters in sandboxes - [Vehicle parking](sandbox/VehicleParking.md) -- [Siri over HTTP](sandbox/SiriUpdater.md) -- [Siri over Azure Message Bus](sandbox/SiriAzureUpdater.md) +- [Siri over HTTP](sandbox/siri/SiriUpdater.md) +- [Siri over Azure Message Bus](sandbox/siri/SiriAzureUpdater.md) - [VehicleRentalServiceDirectory](sandbox/VehicleRentalServiceDirectory.md) diff --git a/docs/examples/skanetrafiken/Readme.md b/docs/examples/skanetrafiken/Readme.md index fc342f4192b..a611c839140 100644 --- a/docs/examples/skanetrafiken/Readme.md +++ b/docs/examples/skanetrafiken/Readme.md @@ -93,6 +93,9 @@ id from the message. In case OTP was not able to find corresponding trip additio performed based on arrival-times/stop-patterns from the ET message. This feature turned off by default but can be activated by adding *fuzzyTripMatching* property to updater configuration. +### FederatedIdentity +It is also possible to connect to Service Bus through FederatedIdentity. Change **authenticationType** to +**FederatedIdentity** and provide **fullyQualifiedNamespace** in router-config. diff --git a/docs/examples/skanetrafiken/router-config.json b/docs/examples/skanetrafiken/router-config.json index d65604aaa00..74042d68e31 100644 --- a/docs/examples/skanetrafiken/router-config.json +++ b/docs/examples/skanetrafiken/router-config.json @@ -44,7 +44,8 @@ "type": "siri-azure-sx-updater", "topic": "", "feedId": "", - "servicebus-url": "", + "authenticationType": "FederatedIdentity", + "fullyQualifiedNamespace": "", "customMidnight": 4, "history": { "url": "", diff --git a/docs/sandbox/siri/SiriAzureUpdater.md b/docs/sandbox/siri/SiriAzureUpdater.md new file mode 100644 index 00000000000..75aa58897ec --- /dev/null +++ b/docs/sandbox/siri/SiriAzureUpdater.md @@ -0,0 +1,197 @@ +# Siri Azure Updater + +It is sandbox extension developed by Skånetrafiken that allows OTP to fetch Siri ET & SX messages through *Azure Service Bus*. +IT also OTP to download historical data from en HTTP endpoint on startup. + +## Contact Info + +Skånetrafiken, Sweden +developer.otp@skanetrafiken.se + +## Documentation + +Documentation available [here](../../examples/skanetrafiken/Readme.md). + +## Configuration + +To enable the SIRI updater you need to add it to the updaters section of the `router-config.json`. + +### Siri Azure ET Updater + + + + +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|------------------------------------------------------------|:---------:|----------------------------------------------------------------|:----------:|---------------------|:-----:| +| type = "siri-azure-et-updater" | `enum` | The type of the updater. | *Required* | | 1.5 | +| [authenticationType](#u__11__authenticationType) | `enum` | Which authentication type to use | *Optional* | `"sharedaccesskey"` | 2.5 | +| [customMidnight](#u__11__customMidnight) | `integer` | Time on which time breaks into new day. | *Optional* | `0` | 2.2 | +| feedId | `string` | The ID of the feed to apply the updates to. | *Optional* | | 2.2 | +| [fullyQualifiedNamespace](#u__11__fullyQualifiedNamespace) | `string` | Service Bus fully qualified namespace used for authentication. | *Optional* | | 2.5 | +| fuzzyTripMatching | `boolean` | Whether to apply fuzzyTripMatching on the updates | *Optional* | `false` | 2.2 | +| [servicebus-url](#u__11__servicebus_url) | `string` | Service Bus connection used for authentication. | *Optional* | | 2.2 | +| topic | `string` | Service Bus topic to connect to. | *Optional* | | 2.2 | +| history | `object` | Configuration for fetching historical data on startup | *Optional* | | 2.2 | +|    fromDateTime | `string` | Datetime boundary for historical data | *Optional* | `"-P1D"` | 2.2 | +|    timeout | `integer` | Timeout in milliseconds | *Optional* | `300000` | na | +|    url | `string` | Endpoint to fetch from | *Optional* | | na | + + +##### Parameter details + +

authenticationType

+ +**Since version:** `2.5` ∙ **Type:** `enum` ∙ **Cardinality:** `Optional` ∙ **Default value:** `"sharedaccesskey"` +**Path:** /updaters/[11] +**Enum values:** `sharedaccesskey` | `federatedidentity` + +Which authentication type to use + +

customMidnight

+ +**Since version:** `2.2` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0` +**Path:** /updaters/[11] + +Time on which time breaks into new day. + +It is common that operating day date breaks a little bit later than midnight so that the switch happens when traffic is at the lowest point. Parameter uses 24-hour format. If the switch happens on 4 am then set this field to 4. + +

fullyQualifiedNamespace

+ +**Since version:** `2.5` ∙ **Type:** `string` ∙ **Cardinality:** `Optional` +**Path:** /updaters/[11] + +Service Bus fully qualified namespace used for authentication. + +Has to be present for authenticationMethod FederatedIdentity. + +

servicebus-url

+ +**Since version:** `2.2` ∙ **Type:** `string` ∙ **Cardinality:** `Optional` +**Path:** /updaters/[11] + +Service Bus connection used for authentication. + +Has to be present for authenticationMethod SharedAccessKey. This should be Primary/Secondary connection string from service bus. + + + +##### Example configuration + +```JSON +// router-config.json +{ + "updaters" : [ + { + "type" : "siri-azure-et-updater", + "topic" : "some_topic", + "authenticationType" : "SharedAccessKey", + "fullyQualifiedNamespace" : "fully_qualified_namespace", + "servicebus-url" : "service_bus_url", + "feedId" : "feed_id", + "customMidnight" : 4, + "history" : { + "url" : "endpoint_url", + "fromDateTime" : "-P1D", + "timeout" : 300000 + } + } + ] +} +``` + + + +### Siri Azure SX Updater + + + + +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|------------------------------------------------------------|:---------:|----------------------------------------------------------------|:----------:|---------------------|:-----:| +| type = "siri-azure-sx-updater" | `enum` | The type of the updater. | *Required* | | 1.5 | +| [authenticationType](#u__10__authenticationType) | `enum` | Which authentication type to use | *Optional* | `"sharedaccesskey"` | 2.5 | +| [customMidnight](#u__10__customMidnight) | `integer` | Time on which time breaks into new day. | *Optional* | `0` | 2.2 | +| feedId | `string` | The ID of the feed to apply the updates to. | *Optional* | | 2.2 | +| [fullyQualifiedNamespace](#u__10__fullyQualifiedNamespace) | `string` | Service Bus fully qualified namespace used for authentication. | *Optional* | | 2.5 | +| fuzzyTripMatching | `boolean` | Whether to apply fuzzyTripMatching on the updates | *Optional* | `false` | 2.2 | +| [servicebus-url](#u__10__servicebus_url) | `string` | Service Bus connection used for authentication. | *Optional* | | 2.2 | +| topic | `string` | Service Bus topic to connect to. | *Optional* | | 2.2 | +| history | `object` | Configuration for fetching historical data on startup | *Optional* | | 2.2 | +|    fromDateTime | `string` | Datetime boundary for historical data. | *Optional* | `"-P1D"` | 2.2 | +|    timeout | `integer` | Timeout in milliseconds | *Optional* | `300000` | na | +|    toDateTime | `string` | Datetime boundary for historical data. | *Optional* | `"P1D"` | 2.2 | +|    url | `string` | Endpoint to fetch from | *Optional* | | na | + + +##### Parameter details + +

authenticationType

+ +**Since version:** `2.5` ∙ **Type:** `enum` ∙ **Cardinality:** `Optional` ∙ **Default value:** `"sharedaccesskey"` +**Path:** /updaters/[10] +**Enum values:** `sharedaccesskey` | `federatedidentity` + +Which authentication type to use + +

customMidnight

+ +**Since version:** `2.2` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0` +**Path:** /updaters/[10] + +Time on which time breaks into new day. + +It is common that operating day date breaks a little bit later than midnight so that the switch happens when traffic is at the lowest point. Parameter uses 24-hour format. If the switch happens on 4 am then set this field to 4. + +

fullyQualifiedNamespace

+ +**Since version:** `2.5` ∙ **Type:** `string` ∙ **Cardinality:** `Optional` +**Path:** /updaters/[10] + +Service Bus fully qualified namespace used for authentication. + +Has to be present for authenticationMethod FederatedIdentity. + +

servicebus-url

+ +**Since version:** `2.2` ∙ **Type:** `string` ∙ **Cardinality:** `Optional` +**Path:** /updaters/[10] + +Service Bus connection used for authentication. + +Has to be present for authenticationMethod SharedAccessKey. This should be Primary/Secondary connection string from service bus. + + + +##### Example configuration + +```JSON +// router-config.json +{ + "updaters" : [ + { + "type" : "siri-azure-sx-updater", + "topic" : "some_topic", + "servicebus-url" : "service_bus_url", + "feedId" : "feed_id", + "customMidnight" : 4, + "history" : { + "url" : "endpoint_url", + "fromDateTime" : "-P1D", + "toDateTime" : "P1D", + "timeout" : 300000 + } + } + ] +} +``` + + + +## Changelog +- Added configuration for turning off stop arrival time match feature. +- Initial version (April 2022) +- Minor changes in logging (November 2022) +- Retry fetch from history endpoint if it failed (February 2023) +- Solve a bug in SiriAzureETUpdater and improve error logging (March 2023) +- Add support with federated identity authentication (February 2024) \ No newline at end of file diff --git a/docs/sandbox/SiriUpdater.md b/docs/sandbox/siri/SiriUpdater.md similarity index 100% rename from docs/sandbox/SiriUpdater.md rename to docs/sandbox/siri/SiriUpdater.md diff --git a/mkdocs.yml b/mkdocs.yml index c4717d4d2e0..dd24a6e2dd4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -95,8 +95,8 @@ nav: - Actuator API: 'sandbox/ActuatorAPI.md' - Direct Transfer Analyzer: 'sandbox/transferanalyzer.md' - Google Cloud Storage: 'sandbox/GoogleCloudStorage.md' - - SIRI Updaters: 'sandbox/SiriUpdater.md' - - SIRI Updater (Azure): 'sandbox/SiriAzureUpdater.md' + - SIRI Updaters: 'sandbox/siri/SiriUpdater.md' + - SIRI Updater (Azure): 'sandbox/siri/SiriAzureUpdater.md' - Vehicle Rental Service Directory API support: 'sandbox/VehicleRentalServiceDirectory.md' - Smoove Bike Rental Updator Support: 'sandbox/SmooveBikeRental.md' - Mapbox Vector Tiles API: 'sandbox/MapboxVectorTilesApi.md' diff --git a/pom.xml b/pom.xml index 03d408a4b2e..faee696b5cb 100644 --- a/pom.xml +++ b/pom.xml @@ -907,17 +907,18 @@ com.azure azure-core - 1.45.0 + 1.46.0 com.azure azure-messaging-servicebus - 7.14.5 + 7.15.0 - com.azure.resourcemanager - azure-resourcemanager-servicebus - 2.32.0 + com.azure + azure-identity + 1.11.2 + compile ch.poole diff --git a/src/ext/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdater.java b/src/ext/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdater.java index 0d36233f22b..f96941c7370 100644 --- a/src/ext/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdater.java +++ b/src/ext/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdater.java @@ -1,5 +1,6 @@ package org.opentripplanner.ext.siri.updater.azure; +import com.azure.identity.DefaultAzureCredentialBuilder; import com.azure.messaging.servicebus.ServiceBusClientBuilder; import com.azure.messaging.servicebus.ServiceBusErrorContext; import com.azure.messaging.servicebus.ServiceBusException; @@ -36,6 +37,8 @@ public abstract class AbstractAzureSiriUpdater implements GraphUpdater { private final Logger LOG = LoggerFactory.getLogger(getClass()); + private final AuthenticationType authenticationType; + private final String fullyQualifiedNamespace; private final String configRef; private final String serviceBusUrl; private final SiriFuzzyTripMatcher fuzzyTripMatcher; @@ -63,6 +66,8 @@ public abstract class AbstractAzureSiriUpdater implements GraphUpdater { public AbstractAzureSiriUpdater(SiriAzureUpdaterParameters config, TransitModel transitModel) { this.configRef = config.configRef(); + this.authenticationType = config.getAuthenticationType(); + this.fullyQualifiedNamespace = config.getFullyQualifiedNamespace(); this.serviceBusUrl = config.getServiceBusUrl(); this.topicName = config.getTopicName(); this.dataInitializationUrl = config.getDataInitializationUrl(); @@ -105,10 +110,17 @@ public void run() { } // Client with permissions to create subscription - serviceBusAdmin = - new ServiceBusAdministrationClientBuilder() - .connectionString(serviceBusUrl) - .buildAsyncClient(); + if (authenticationType == AuthenticationType.FederatedIdentity) { + serviceBusAdmin = + new ServiceBusAdministrationClientBuilder() + .credential(fullyQualifiedNamespace, new DefaultAzureCredentialBuilder().build()) + .buildAsyncClient(); + } else if (authenticationType == AuthenticationType.SharedAccessKey) { + serviceBusAdmin = + new ServiceBusAdministrationClientBuilder() + .connectionString(serviceBusUrl) + .buildAsyncClient(); + } // If Idle more then one day, then delete subscription so we don't have old obsolete subscriptions on Azure Service Bus var options = new CreateSubscriptionOptions(); diff --git a/src/ext/java/org/opentripplanner/ext/siri/updater/azure/AuthenticationType.java b/src/ext/java/org/opentripplanner/ext/siri/updater/azure/AuthenticationType.java new file mode 100644 index 00000000000..65cf8caac93 --- /dev/null +++ b/src/ext/java/org/opentripplanner/ext/siri/updater/azure/AuthenticationType.java @@ -0,0 +1,6 @@ +package org.opentripplanner.ext.siri.updater.azure; + +public enum AuthenticationType { + SharedAccessKey, + FederatedIdentity, +} diff --git a/src/ext/java/org/opentripplanner/ext/siri/updater/azure/SiriAzureUpdaterParameters.java b/src/ext/java/org/opentripplanner/ext/siri/updater/azure/SiriAzureUpdaterParameters.java index 93e9a6bded8..0d207d27efe 100644 --- a/src/ext/java/org/opentripplanner/ext/siri/updater/azure/SiriAzureUpdaterParameters.java +++ b/src/ext/java/org/opentripplanner/ext/siri/updater/azure/SiriAzureUpdaterParameters.java @@ -4,6 +4,8 @@ public abstract class SiriAzureUpdaterParameters { private String configRef; private String type; + private AuthenticationType authenticationType; + private String fullyQualifiedNamespace; private String serviceBusUrl; private String topicName; private String dataInitializationUrl; @@ -28,6 +30,22 @@ public String getType() { return type; } + public AuthenticationType getAuthenticationType() { + return authenticationType; + } + + public void setAuthenticationType(AuthenticationType authenticationType) { + this.authenticationType = authenticationType; + } + + public String getFullyQualifiedNamespace() { + return fullyQualifiedNamespace; + } + + public void setFullyQualifiedNamespace(String fullyQualifiedNamespace) { + this.fullyQualifiedNamespace = fullyQualifiedNamespace; + } + public String getServiceBusUrl() { return serviceBusUrl; } diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureETUpdaterConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureETUpdaterConfig.java index 80615acb9b2..791f9a9dadc 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureETUpdaterConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureETUpdaterConfig.java @@ -1,6 +1,7 @@ package org.opentripplanner.standalone.config.routerconfig.updaters.azure; import static org.opentripplanner.standalone.config.framework.json.OtpVersion.NA; +import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_2; import org.opentripplanner.ext.siri.updater.azure.SiriAzureETUpdaterParameters; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; @@ -14,13 +15,26 @@ public static SiriAzureETUpdaterParameters create(String configRef, NodeAdapter if (c.exist("history")) { NodeAdapter history = c .of("history") - .since(NA) - .summary("TODO") - .description(/*TODO DOC*/"TODO") + .since(V2_2) + .summary("Configuration for fetching historical data on startup") .asObject(); - String fromDateTime = history.of("fromDateTime").since(NA).summary("TODO").asString("-P1D"); - int customMidnight = c.of("customMidnight").since(NA).summary("TODO").asInt(0); + String fromDateTime = history + .of("fromDateTime") + .since(V2_2) + .summary("Datetime boundary for historical data") + .asString("-P1D"); + + int customMidnight = c + .of("customMidnight") + .since(V2_2) + .summary("Time on which time breaks into new day.") + .description( + "It is common that operating day date breaks a little bit later than midnight so " + + "that the switch happens when traffic is at the lowest point. Parameter uses 24-hour format. " + + "If the switch happens on 4 am then set this field to 4." + ) + .asInt(0); parameters.setFromDateTime(asDateOrRelativePeriod(fromDateTime, customMidnight)); } diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureSXUpdaterConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureSXUpdaterConfig.java index 7d63657caf8..cf5dacb5976 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureSXUpdaterConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureSXUpdaterConfig.java @@ -1,6 +1,7 @@ package org.opentripplanner.standalone.config.routerconfig.updaters.azure; import static org.opentripplanner.standalone.config.framework.json.OtpVersion.NA; +import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_2; import org.opentripplanner.ext.siri.updater.azure.SiriAzureSXUpdaterParameters; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; @@ -14,14 +15,32 @@ public static SiriAzureSXUpdaterParameters create(String configRef, NodeAdapter if (c.exist("history")) { NodeAdapter history = c .of("history") - .since(NA) - .summary("TODO") - .description(/*TODO DOC*/"TODO") + .since(V2_2) + .summary("Configuration for fetching historical data on startup.") .asObject(); - String fromDateTime = history.of("fromDateTime").since(NA).summary("TODO").asString("-P1D"); - String toDateTime = history.of("toDateTime").since(NA).summary("TODO").asString("P1D"); - int customMidnight = c.of("customMidnight").since(NA).summary("TODO").asInt(0); + String fromDateTime = history + .of("fromDateTime") + .since(V2_2) + .summary("Datetime boundary for historical data.") + .asString("-P1D"); + + String toDateTime = history + .of("toDateTime") + .since(V2_2) + .summary("Datetime boundary for historical data.") + .asString("P1D"); + + int customMidnight = c + .of("customMidnight") + .since(V2_2) + .summary("Time on which time breaks into new day.") + .description( + "It is common that operating day date breaks a little bit later than midnight so " + + "that the switch happens when traffic is at the lowest point. Parameter uses 24-hour format. " + + "If the switch happens on 4 am then set this field to 4." + ) + .asInt(0); parameters.setFromDateTime(asDateOrRelativePeriod(fromDateTime, customMidnight)); parameters.setToDateTime(asDateOrRelativePeriod(toDateTime, customMidnight)); diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureUpdaterConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureUpdaterConfig.java index 319b2d45001..35da716337e 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureUpdaterConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureUpdaterConfig.java @@ -1,12 +1,15 @@ package org.opentripplanner.standalone.config.routerconfig.updaters.azure; import static org.opentripplanner.standalone.config.framework.json.OtpVersion.NA; +import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_2; +import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_5; import java.time.LocalDate; import java.time.Period; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeParseException; +import org.opentripplanner.ext.siri.updater.azure.AuthenticationType; import org.opentripplanner.ext.siri.updater.azure.SiriAzureUpdaterParameters; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; @@ -18,24 +21,61 @@ public static void populateConfig( NodeAdapter c ) { parameters.setConfigRef(configRef); - parameters.setServiceBusUrl(c.of("servicebus-url").since(NA).summary("TODO").asString(null)); - parameters.setTopicName(c.of("topic").since(NA).summary("TODO").asString(null)); - parameters.setFeedId(c.of("feedId").since(NA).summary("TODO").asString(null)); + parameters.setServiceBusUrl( + c + .of("servicebus-url") + .since(V2_2) + .summary("Service Bus connection used for authentication.") + .description( + "Has to be present for authenticationMethod SharedAccessKey. This should be Primary/Secondary connection string from service bus." + ) + .asString(null) + ); + parameters.setTopicName( + c.of("topic").since(V2_2).summary("Service Bus topic to connect to.").asString(null) + ); + parameters.setFeedId( + c + .of("feedId") + .since(V2_2) + .summary("The ID of the feed to apply the updates to.") + .asString(null) + ); parameters.setFuzzyTripMatching( - c.of("fuzzyTripMatching").since(NA).summary("TODO").asBoolean(false) + c + .of("fuzzyTripMatching") + .since(V2_2) + .summary("Whether to apply fuzzyTripMatching on the updates") + .asBoolean(false) + ); + parameters.setFullyQualifiedNamespace( + c + .of("fullyQualifiedNamespace") + .since(V2_5) + .summary("Service Bus fully qualified namespace used for authentication.") + .description("Has to be present for authenticationMethod FederatedIdentity.") + .asString(null) + ); + parameters.setAuthenticationType( + c + .of("authenticationType") + .since(V2_5) + .summary("Which authentication type to use") + .asEnum(AuthenticationType.SharedAccessKey) ); if (c.exist("history")) { NodeAdapter history = c .of("history") - .since(NA) - .summary("TODO") - .description(/*TODO DOC*/"TODO") + .since(V2_2) + .summary("Configuration for fetching historical data on startup") .asObject(); parameters.setDataInitializationUrl( - history.of("url").since(NA).summary("TODO").asString(null) + history.of("url").since(NA).summary("Endpoint to fetch from").asString(null) + ); + parameters.setTimeout( + history.of("timeout").since(NA).summary("Timeout in milliseconds").asInt(300000) ); - parameters.setTimeout(history.of("timeout").since(NA).summary("TODO").asInt(300000)); } } diff --git a/src/test/java/org/opentripplanner/generate/doc/SiriAzureConfigDocTest.java b/src/test/java/org/opentripplanner/generate/doc/SiriAzureConfigDocTest.java new file mode 100644 index 00000000000..374ac2b4bbb --- /dev/null +++ b/src/test/java/org/opentripplanner/generate/doc/SiriAzureConfigDocTest.java @@ -0,0 +1,98 @@ +package org.opentripplanner.generate.doc; + +import static org.opentripplanner.framework.application.OtpFileNames.ROUTER_CONFIG_FILENAME; +import static org.opentripplanner.framework.io.FileUtils.assertFileEquals; +import static org.opentripplanner.framework.io.FileUtils.readFile; +import static org.opentripplanner.framework.io.FileUtils.writeFile; +import static org.opentripplanner.framework.text.MarkdownFormatter.HEADER_4; +import static org.opentripplanner.generate.doc.framework.DocsTestConstants.DOCS_ROOT; +import static org.opentripplanner.generate.doc.framework.DocsTestConstants.TEMPLATE_ROOT; +import static org.opentripplanner.generate.doc.framework.TemplateUtil.replaceSection; +import static org.opentripplanner.standalone.config.framework.json.JsonSupport.jsonNodeFromResource; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.File; +import java.util.Set; +import org.junit.jupiter.api.Test; +import org.opentripplanner.generate.doc.framework.DocBuilder; +import org.opentripplanner.generate.doc.framework.GeneratesDocumentation; +import org.opentripplanner.generate.doc.framework.ParameterDetailsList; +import org.opentripplanner.generate.doc.framework.ParameterSummaryTable; +import org.opentripplanner.generate.doc.framework.SkipNodes; +import org.opentripplanner.standalone.config.RouterConfig; +import org.opentripplanner.standalone.config.framework.json.NodeAdapter; + +@GeneratesDocumentation +public class SiriAzureConfigDocTest { + + private static final File TEMPLATE = new File(TEMPLATE_ROOT, "sandbox/siri/SiriAzureUpdater.md"); + private static final File OUT_FILE = new File(DOCS_ROOT, "sandbox/siri/SiriAzureUpdater.md"); + + private static final String ROUTER_CONFIG_PATH = "standalone/config/" + ROUTER_CONFIG_FILENAME; + private static final Set INCLUDE_UPDATERS = Set.of( + "siri-azure-et-updater", + "siri-azure-sx-updater" + ); + private static final SkipNodes SKIP_NODES = SkipNodes.of().build(); + public static final ObjectMapper mapper = new ObjectMapper(); + + /** + * NOTE! This test updates the {@code docs/sandbox/SiriUpdater.md} document based on the latest + * version of the code. + */ + @Test + public void updateSiriDoc() { + NodeAdapter node = readUpdaterConfig(); + + // Read and close input file (same as output file) + String template = readFile(TEMPLATE); + String original = readFile(OUT_FILE); + + for (String childName : node.listChildrenByName()) { + var child = node.child(childName); + var type = child.typeQualifier(); + + if (INCLUDE_UPDATERS.contains(type)) { + template = replaceSection(template, type, updaterDoc(child)); + } + } + + writeFile(OUT_FILE, template); + assertFileEquals(original, OUT_FILE); + } + + private NodeAdapter readUpdaterConfig() { + var json = jsonNodeFromResource(ROUTER_CONFIG_PATH); + var conf = new RouterConfig(json, ROUTER_CONFIG_PATH, false); + return conf.asNodeAdapter().child("updaters"); + } + + private String updaterDoc(NodeAdapter node) { + DocBuilder buf = new DocBuilder(); + addParameterSummaryTable(buf, node); + addDetailsSection(buf, node); + addExample(buf, node); + return buf.toString(); + } + + private void addParameterSummaryTable(DocBuilder buf, NodeAdapter node) { + buf.addSection(new ParameterSummaryTable(SKIP_NODES).createTable(node).toMarkdownTable()); + } + + private void addDetailsSection(DocBuilder buf, NodeAdapter node) { + String details = getParameterDetailsTable(node); + + if (!details.isBlank()) { + buf.header(5, "Parameter details", null).addSection(details); + } + } + + private String getParameterDetailsTable(NodeAdapter node) { + return ParameterDetailsList.listParametersWithDetails(node, SKIP_NODES, HEADER_4); + } + + private void addExample(DocBuilder buf, NodeAdapter node) { + buf.addSection("##### Example configuration"); + buf.addUpdaterExample(ROUTER_CONFIG_FILENAME, node.rawNode()); + } +} diff --git a/src/test/java/org/opentripplanner/generate/doc/SiriConfigDocTest.java b/src/test/java/org/opentripplanner/generate/doc/SiriConfigDocTest.java index 1ceb0ab092c..2474f37c402 100644 --- a/src/test/java/org/opentripplanner/generate/doc/SiriConfigDocTest.java +++ b/src/test/java/org/opentripplanner/generate/doc/SiriConfigDocTest.java @@ -25,8 +25,8 @@ @GeneratesDocumentation public class SiriConfigDocTest { - private static final File TEMPLATE = new File(TEMPLATE_ROOT, "SiriUpdater.md"); - private static final File OUT_FILE = new File(DOCS_ROOT, "sandbox/SiriUpdater.md"); + private static final File TEMPLATE = new File(TEMPLATE_ROOT, "sandbox/siri/SiriUpdater.md"); + private static final File OUT_FILE = new File(DOCS_ROOT, "sandbox/siri/SiriUpdater.md"); private static final String ROUTER_CONFIG_PATH = "standalone/config/" + ROUTER_CONFIG_FILENAME; private static final Set INCLUDE_UPDATERS = Set.of("siri-et-updater", "siri-sx-updater"); diff --git a/src/test/java/org/opentripplanner/generate/doc/UpdaterConfigDocTest.java b/src/test/java/org/opentripplanner/generate/doc/UpdaterConfigDocTest.java index fa5abca7814..4bdfe782615 100644 --- a/src/test/java/org/opentripplanner/generate/doc/UpdaterConfigDocTest.java +++ b/src/test/java/org/opentripplanner/generate/doc/UpdaterConfigDocTest.java @@ -31,6 +31,7 @@ public class UpdaterConfigDocTest { private static final String ROUTER_CONFIG_PATH = "standalone/config/" + ROUTER_CONFIG_FILENAME; private static final Set SKIP_UPDATERS = Set.of( "siri-azure-sx-updater", + "siri-azure-et-updater", "vehicle-parking", "siri-et-updater", "siri-sx-updater" diff --git a/src/test/resources/standalone/config/router-config.json b/src/test/resources/standalone/config/router-config.json index 2b2449a7415..1a270929947 100644 --- a/src/test/resources/standalone/config/router-config.json +++ b/src/test/resources/standalone/config/router-config.json @@ -392,6 +392,21 @@ "toDateTime": "P1D", "timeout": 300000 } + }, + // SIRI ET updater for Azure Service Bus + { + "type": "siri-azure-et-updater", + "topic": "some_topic", + "authenticationType": "SharedAccessKey", + "fullyQualifiedNamespace": "fully_qualified_namespace", + "servicebus-url": "service_bus_url", + "feedId": "feed_id", + "customMidnight": 4, + "history": { + "url": "endpoint_url", + "fromDateTime": "-P1D", + "timeout": 300000 + } } ], "rideHailingServices": [