From 42b2896b935317d2043f2a348c59996f3293c9e9 Mon Sep 17 00:00:00 2001 From: Robin Beer Date: Thu, 10 Oct 2024 09:01:42 +0100 Subject: [PATCH 1/5] refactor(Updated to load plan query from resource URI): Now downloads the query from a public repo o --- configurations/default/env.yml.tmp | 5 +- configurations/test/env.yml | 5 +- .../middleware/utils/GraphQLUtils.java | 68 +++-- src/main/resources/queries/planQuery.graphql | 254 ------------------ 4 files changed, 50 insertions(+), 282 deletions(-) delete mode 100644 src/main/resources/queries/planQuery.graphql diff --git a/configurations/default/env.yml.tmp b/configurations/default/env.yml.tmp index f9eae14f3..072e99887 100644 --- a/configurations/default/env.yml.tmp +++ b/configurations/default/env.yml.tmp @@ -93,4 +93,7 @@ TRIP_INSTRUCTION_UPCOMING_RADIUS: 10 US_RIDE_GWINNETT_BUS_OPERATOR_NOTIFIER_API_URL: https://bus.notifier.example.com US_RIDE_GWINNETT_BUS_OPERATOR_NOTIFIER_API_KEY: your-key -US_RIDE_GWINNETT_BUS_OPERATOR_NOTIFIER_QUALIFYING_ROUTES: agency_id:route_id \ No newline at end of file +US_RIDE_GWINNETT_BUS_OPERATOR_NOTIFIER_QUALIFYING_ROUTES: agency_id:route_id + +# The location for an OTP plan query request. +PLAN_QUERY_RESOURCE_URI: https://plan.resource.com \ No newline at end of file diff --git a/configurations/test/env.yml b/configurations/test/env.yml index dd8a4ea20..15cde11fb 100644 --- a/configurations/test/env.yml +++ b/configurations/test/env.yml @@ -62,4 +62,7 @@ TRIP_TRACKING_RAIL_BOUNDARY: 200 TRIP_INSTRUCTION_IMMEDIATE_PREFIX_DISTANCE: 2 TRIP_INSTRUCTION_UPCOMING_PREFIX_DISTANCE: 10 -VALIDATE_ENVIRONMENT_CONFIG: false \ No newline at end of file +VALIDATE_ENVIRONMENT_CONFIG: false + +# The location for an OTP plan query request. +PLAN_QUERY_RESOURCE_URI: https://raw.githubusercontent.com/ibi-group/open-source-configurations/main/atlanta/arc/planQuery.graphql \ No newline at end of file diff --git a/src/main/java/org/opentripplanner/middleware/utils/GraphQLUtils.java b/src/main/java/org/opentripplanner/middleware/utils/GraphQLUtils.java index fce26e44d..9f5694890 100644 --- a/src/main/java/org/opentripplanner/middleware/utils/GraphQLUtils.java +++ b/src/main/java/org/opentripplanner/middleware/utils/GraphQLUtils.java @@ -1,52 +1,68 @@ package org.opentripplanner.middleware.utils; +import org.eclipse.jetty.http.HttpMethod; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.BufferedReader; -import java.io.InputStreamReader; +import java.net.URI; + +import static org.opentripplanner.middleware.utils.ConfigUtils.getConfigPropertyAsText; public class GraphQLUtils { + + private GraphQLUtils() { + throw new IllegalStateException("Utility class."); + } + private static final Logger LOG = LoggerFactory.getLogger(GraphQLUtils.class); // Lazily-initialized in getPlanQueryTemplate() private static String planQueryTemplate = null; /** - * Location of the GraphQL plan query template file, as Java resource. + * Location of the GraphQL plan query template file, as URI resource. */ - public static final String PLAN_QUERY_RESOURCE = "queries/planQuery.graphql"; + private static final String PLAN_QUERY_RESOURCE_URI = + getConfigPropertyAsText("PLAN_QUERY_RESOURCE_URI", null); + /** - * Return the full GraphQL plan file planQueryTemplate in Java string format, with {@code "} as {@code \"} + * Return the full GraphQL plan file planQueryTemplate. */ public static String getPlanQueryTemplate() { if (GraphQLUtils.planQueryTemplate == null) { - GraphQLUtils.planQueryTemplate = planQueryTemplateAsString(PLAN_QUERY_RESOURCE); - } + GraphQLUtils.planQueryTemplate = planQueryTemplateAsString(); + } return GraphQLUtils.planQueryTemplate; } /** - * Return a GraphQL planQueryTemplate in Java string format, with {@code "} as {@code \"} - * @param resource the plan file or any GraphQL file + * Return a GraphQL planQueryTemplate in Java string format, with {@code "} as {@code \"}. + */ + static String planQueryTemplateAsString() { + String rawPlanQuery = getPlanQueryFromResource(); + if (rawPlanQuery == null) { + LOG.error("Unable to retrieve plan query from resource: {}.", GraphQLUtils.PLAN_QUERY_RESOURCE_URI); + return null; + } + return rawPlanQuery.replace("\"", "\\\""); + } + + /** + * Download the plan query from resource URI. */ - static String planQueryTemplateAsString(String resource) { - StringBuilder builder = new StringBuilder(); - try (var reader = new BufferedReader(new InputStreamReader( - GraphQLUtils.class.getClassLoader().getResourceAsStream(resource) - ))) { - int value; - // All this low-level stuff is just to put a \ in front of " in the string. - while ((value = reader.read()) != -1) { - char c = (char)value; - if (c == '\n') builder.append("\\n"); - else if (c == '"') builder.append("\\\""); - else builder.append(c); - } - } catch (Exception e) { - LOG.error("Can't find \"{}\" resource.", resource, e); + static String getPlanQueryFromResource() { + if (GraphQLUtils.PLAN_QUERY_RESOURCE_URI == null) { + LOG.error("The plan query resource URI parameter \"PLAN_QUERY_RESOURCE_URI\" is undefined."); + return null; } - return builder.toString(); + HttpResponseValues httpResponseValues = HttpUtils.httpRequestRawResponse( + URI.create(GraphQLUtils.PLAN_QUERY_RESOURCE_URI), + 10, + HttpMethod.GET, + null, + null + ); + return httpResponseValues != null ? httpResponseValues.responseBody : null; } -} +} \ No newline at end of file diff --git a/src/main/resources/queries/planQuery.graphql b/src/main/resources/queries/planQuery.graphql deleted file mode 100644 index 665596777..000000000 --- a/src/main/resources/queries/planQuery.graphql +++ /dev/null @@ -1,254 +0,0 @@ -query Plan( - $arriveBy: Boolean - $banned: InputBanned - $bikeReluctance: Float - $carReluctance: Float - $date: String - $fromPlace: String! - $modes: [TransportMode] - $numItineraries: Int - $preferred: InputPreferred - $time: String - $toPlace: String! - $unpreferred: InputUnpreferred - $walkReluctance: Float - $walkSpeed: Float - $wheelchair: Boolean -) { - plan( - arriveBy: $arriveBy - banned: $banned - bikeReluctance: $bikeReluctance - carReluctance: $carReluctance - date: $date - fromPlace: $fromPlace - # Currently only supporting EN locale, used for times and text - locale: "en" - numItineraries: $numItineraries - preferred: $preferred - time: $time - toPlace: $toPlace - transportModes: $modes - unpreferred: $unpreferred - walkReluctance: $walkReluctance - walkSpeed: $walkSpeed - wheelchair: $wheelchair - ) { - itineraries { - accessibilityScore - duration - endTime - legs { - accessibilityScore - agency { - alerts { - alertDescriptionText - alertHeaderText - alertUrl - effectiveStartDate - id - } - gtfsId - id: gtfsId - name - timezone - url - } - alerts { - alertDescriptionText - alertHeaderText - alertUrl - effectiveStartDate - id - } - arrivalDelay - departureDelay - distance - dropoffType - duration - endTime - fareProducts { - id - product { - __typename - id - medium { - id - name - } - name - riderCategory { - id - name - } - ... on DefaultFareProduct { - price { - amount - currency { - code - digits - } - } - } - } - } - from { - lat - lon - name - rentalVehicle { - id - network - } - stop { - alerts { - alertDescriptionText - alertHeaderText - alertUrl - effectiveStartDate - id - } - code - gtfsId - id - lat - lon - } - vertexType - } - headsign - interlineWithPreviousLeg - intermediateStops { - lat - locationType - lon - name - stopCode: code - stopId: id - } - legGeometry { - length - points - } - mode - pickupBookingInfo { - earliestBookingTime { - daysPrior - } - } - pickupType - realTime - realtimeState - rentedBike - rideHailingEstimate { - arrival - maxPrice { - amount - currency { - code - } - } - minPrice { - amount - currency { - code - } - } - provider { - id - } - } - route { - alerts { - alertDescriptionText - alertHeaderText - alertUrl - effectiveStartDate - id - } - color - gtfsId - id: gtfsId - longName - shortName - textColor - type - } - startTime - steps { - absoluteDirection - alerts { - alertDescriptionText - alertHeaderText - alertUrl - effectiveStartDate - id - } - area - distance - elevationProfile { - distance - elevation - } - lat - lon - relativeDirection - stayOn - streetName - } - to { - lat - lon - name - rentalVehicle { - id - network - } - stop { - alerts { - alertDescriptionText - alertHeaderText - alertUrl - effectiveStartDate - id - } - code - gtfsId - id - lat - lon - } - vertexType - } - transitLeg - trip { - arrivalStoptime { - stop { - gtfsId - id - } - stopPosition - } - departureStoptime { - stop { - gtfsId - id - } - stopPosition - } - gtfsId - id - } - } - startTime - transfers: numberOfTransfers - waitingTime - walkTime - } - routingErrors { - code - description - inputField - } - } -} From edceb9e107d63417d09f574f177310dc27904d28 Mon Sep 17 00:00:00 2001 From: Robin Beer Date: Fri, 11 Oct 2024 09:09:36 +0100 Subject: [PATCH 2/5] refactor(GraphQLUtils.java): Now includes a default plan query URI --- .../org/opentripplanner/middleware/utils/GraphQLUtils.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/opentripplanner/middleware/utils/GraphQLUtils.java b/src/main/java/org/opentripplanner/middleware/utils/GraphQLUtils.java index 9f5694890..6ba229d5a 100644 --- a/src/main/java/org/opentripplanner/middleware/utils/GraphQLUtils.java +++ b/src/main/java/org/opentripplanner/middleware/utils/GraphQLUtils.java @@ -23,7 +23,10 @@ private GraphQLUtils() { * Location of the GraphQL plan query template file, as URI resource. */ private static final String PLAN_QUERY_RESOURCE_URI = - getConfigPropertyAsText("PLAN_QUERY_RESOURCE_URI", null); + getConfigPropertyAsText( + "PLAN_QUERY_RESOURCE_URI", + "https://raw.githubusercontent.com/ibi-group/open-source-configurations/main/atlanta/arc/planQuery.graphql" + ); /** From 695947a38032c6217feaa629bcd7c39ccb538485 Mon Sep 17 00:00:00 2001 From: Robin Beer Date: Fri, 11 Oct 2024 15:27:51 +0100 Subject: [PATCH 3/5] refactor(GraphQLUtils.java): Now referencing the correct default plan query resource --- .../java/org/opentripplanner/middleware/utils/GraphQLUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/opentripplanner/middleware/utils/GraphQLUtils.java b/src/main/java/org/opentripplanner/middleware/utils/GraphQLUtils.java index 6ba229d5a..d22a447b4 100644 --- a/src/main/java/org/opentripplanner/middleware/utils/GraphQLUtils.java +++ b/src/main/java/org/opentripplanner/middleware/utils/GraphQLUtils.java @@ -25,7 +25,7 @@ private GraphQLUtils() { private static final String PLAN_QUERY_RESOURCE_URI = getConfigPropertyAsText( "PLAN_QUERY_RESOURCE_URI", - "https://raw.githubusercontent.com/ibi-group/open-source-configurations/main/atlanta/arc/planQuery.graphql" + "https://raw.githubusercontent.com/opentripplanner/otp-ui/refs/heads/master/packages/core-utils/src/planQuery.graphql" ); From 4539fc0123af8deee15cdd5ac87a6acc0c050a72 Mon Sep 17 00:00:00 2001 From: Robin Beer Date: Mon, 14 Oct 2024 11:23:33 +0100 Subject: [PATCH 4/5] refactor(Various updates to address PR feedback): --- README.md | 1 + .../middleware/utils/GraphQLUtils.java | 18 +++++++++++------- src/main/resources/env.schema.json | 5 +++++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ef320ab1e..aec6c1ff1 100644 --- a/README.md +++ b/README.md @@ -280,6 +280,7 @@ The special E2E client settings should be defined in `env.yml`: | OTP_TIMEZONE | string | Required | America/Los_Angeles | The timezone identifier that OTP is using to parse dates and times. OTP will use the timezone identifier that it finds in the first available agency to parse dates and times. | | OTP_UI_NAME | string | Optional | Trip Planner | Config setting for linking to the OTP UI (trip planner). | | OTP_UI_URL | string | Optional | https://plan.example.com | Config setting for linking to the OTP UI (trip planner). | +| PLAN_QUERY_RESOURCE_URI | string | Optional | https://plan.resource.com | Resource location of bespoke plan query. | | PUSH_API_KEY | string | Optional | your-api-key | Key for Mobile Team push notifications internal API. | | PUSH_API_URL | string | Optional | https://example.com/api/otp_push/sound_transit | URL for Mobile Team push notifications internal API. | | SERVICE_DAY_START_HOUR | integer | Optional | 3 | Optional parameter for the hour (local time, 24-hr format) at which a service day starts. To make the service day change at 2am, enter 2. The default is 3am. | diff --git a/src/main/java/org/opentripplanner/middleware/utils/GraphQLUtils.java b/src/main/java/org/opentripplanner/middleware/utils/GraphQLUtils.java index d22a447b4..bcc726ed4 100644 --- a/src/main/java/org/opentripplanner/middleware/utils/GraphQLUtils.java +++ b/src/main/java/org/opentripplanner/middleware/utils/GraphQLUtils.java @@ -1,6 +1,7 @@ package org.opentripplanner.middleware.utils; import org.eclipse.jetty.http.HttpMethod; +import org.opentripplanner.middleware.bugsnag.BugsnagReporter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,13 +20,19 @@ private GraphQLUtils() { // Lazily-initialized in getPlanQueryTemplate() private static String planQueryTemplate = null; + /** + * Location of the GraphQL default plan query template file, as URI resource. + */ + private static final String DEFAULT_PLAN_QUERY_RESOURCE_URI = + "https://raw.githubusercontent.com/opentripplanner/otp-ui/refs/heads/master/packages/core-utils/src/planQuery.graphql"; + /** * Location of the GraphQL plan query template file, as URI resource. */ private static final String PLAN_QUERY_RESOURCE_URI = getConfigPropertyAsText( "PLAN_QUERY_RESOURCE_URI", - "https://raw.githubusercontent.com/opentripplanner/otp-ui/refs/heads/master/packages/core-utils/src/planQuery.graphql" + DEFAULT_PLAN_QUERY_RESOURCE_URI ); @@ -45,8 +52,9 @@ public static String getPlanQueryTemplate() { static String planQueryTemplateAsString() { String rawPlanQuery = getPlanQueryFromResource(); if (rawPlanQuery == null) { - LOG.error("Unable to retrieve plan query from resource: {}.", GraphQLUtils.PLAN_QUERY_RESOURCE_URI); - return null; + String message = String.format("Unable to retrieve plan query from resource: %s.", GraphQLUtils.PLAN_QUERY_RESOURCE_URI); + LOG.error(message); + throw new IllegalStateException(message); } return rawPlanQuery.replace("\"", "\\\""); } @@ -55,10 +63,6 @@ static String planQueryTemplateAsString() { * Download the plan query from resource URI. */ static String getPlanQueryFromResource() { - if (GraphQLUtils.PLAN_QUERY_RESOURCE_URI == null) { - LOG.error("The plan query resource URI parameter \"PLAN_QUERY_RESOURCE_URI\" is undefined."); - return null; - } HttpResponseValues httpResponseValues = HttpUtils.httpRequestRawResponse( URI.create(GraphQLUtils.PLAN_QUERY_RESOURCE_URI), 10, diff --git a/src/main/resources/env.schema.json b/src/main/resources/env.schema.json index e70d7654d..250ec492e 100644 --- a/src/main/resources/env.schema.json +++ b/src/main/resources/env.schema.json @@ -197,6 +197,11 @@ "examples": ["https://plan.example.com"], "description": "Config setting for linking to the OTP UI (trip planner)." }, + "PLAN_QUERY_RESOURCE_URI": { + "type": "string", + "examples": ["https://plan.resource.com"], + "description": "Resource location of bespoke plan query." + }, "PUSH_API_KEY": { "type": "string", "examples": ["your-api-key"], From e203492294f2fc48eeb66197c292d0ff97eb40c7 Mon Sep 17 00:00:00 2001 From: Robin Beer Date: Wed, 16 Oct 2024 10:59:31 +0100 Subject: [PATCH 5/5] refactor(Addressed PR feedback): Mobility profile now available as part of the itinerary checks --- .../org/opentripplanner/middleware/models/MobilityProfile.java | 2 -- .../org/opentripplanner/middleware/otp/OtpGraphQLVariables.java | 1 + .../opentripplanner/middleware/utils/ItineraryUtilsTest.java | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/opentripplanner/middleware/models/MobilityProfile.java b/src/main/java/org/opentripplanner/middleware/models/MobilityProfile.java index c9e02644c..b8310e5b7 100644 --- a/src/main/java/org/opentripplanner/middleware/models/MobilityProfile.java +++ b/src/main/java/org/opentripplanner/middleware/models/MobilityProfile.java @@ -1,6 +1,5 @@ package org.opentripplanner.middleware.models; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import java.io.Serializable; @@ -53,7 +52,6 @@ public enum VisionLimitation { * the Georgia Tech Mobility Profile Configuration / Logical Flow document, * so that the mode is constructed based on specific strings in a specific * order. The device strings are expected to change on occasion. - * @param mobilityProfile consulted to construct and update mobility mode */ public void updateMobilityMode() { // Variable names and the strings we parse are from Georgia Tech document, to facilitate syncing diff --git a/src/main/java/org/opentripplanner/middleware/otp/OtpGraphQLVariables.java b/src/main/java/org/opentripplanner/middleware/otp/OtpGraphQLVariables.java index 8a4c8c172..816fdb797 100644 --- a/src/main/java/org/opentripplanner/middleware/otp/OtpGraphQLVariables.java +++ b/src/main/java/org/opentripplanner/middleware/otp/OtpGraphQLVariables.java @@ -44,6 +44,7 @@ public OtpGraphQLVariables clone() { clone.carReluctance = carReluctance; clone.date = date; clone.fromPlace = fromPlace; + clone.mobilityProfile = mobilityProfile; if (modes != null) { clone.modes = List.copyOf(modes); } diff --git a/src/test/java/org/opentripplanner/middleware/utils/ItineraryUtilsTest.java b/src/test/java/org/opentripplanner/middleware/utils/ItineraryUtilsTest.java index 6ce321555..0cff04b77 100644 --- a/src/test/java/org/opentripplanner/middleware/utils/ItineraryUtilsTest.java +++ b/src/test/java/org/opentripplanner/middleware/utils/ItineraryUtilsTest.java @@ -323,6 +323,7 @@ private MonitoredTrip makeTestTrip() { trip.queryParams = BASE_QUERY; trip.otp2QueryParams = new OtpGraphQLVariables(); trip.otp2QueryParams.date = QUERY_DATE; + trip.otp2QueryParams.mobilityProfile = "mobility-profile"; trip.otp2QueryParams.time = QUERY_TIME; trip.tripTime = QUERY_TIME;