diff --git a/src/ext/java/org/opentripplanner/ext/restapi/resources/RoutingResource.java b/src/ext/java/org/opentripplanner/ext/restapi/resources/RoutingResource.java index 5746317039e..38e50b283dc 100644 --- a/src/ext/java/org/opentripplanner/ext/restapi/resources/RoutingResource.java +++ b/src/ext/java/org/opentripplanner/ext/restapi/resources/RoutingResource.java @@ -23,6 +23,7 @@ import org.opentripplanner.framework.application.OTPFeature; import org.opentripplanner.framework.lang.StringUtils; import org.opentripplanner.framework.time.DurationUtils; +import org.opentripplanner.framework.time.ZoneIdFallback; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.api.request.preference.ItineraryFilterDebugProfile; import org.opentripplanner.routing.api.request.request.filter.SelectRequest; @@ -711,7 +712,7 @@ protected RouteRequest buildRequest(MultivaluedMap queryParamete { //FIXME: move into setter method on routing request - ZoneId tz = serverContext.transitService().getTimeZone(); + ZoneId tz = ZoneIdFallback.zoneId(serverContext.transitService().getTimeZone()); if (date == null && time != null) { // Time was provided but not date LOG.debug("parsing ISO datetime {}", time); try { diff --git a/src/main/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapper.java b/src/main/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapper.java index 790064aba22..2eeaf229b11 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapper.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapper.java @@ -17,6 +17,7 @@ import org.opentripplanner.api.parameter.QualifiedModeSet; import org.opentripplanner.apis.gtfs.GraphQLRequestContext; import org.opentripplanner.framework.graphql.GraphQLUtils; +import org.opentripplanner.framework.time.ZoneIdFallback; import org.opentripplanner.model.GenericLocation; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.api.request.framework.CostLinearFunction; @@ -55,7 +56,7 @@ public static RouteRequest toRouteRequest( request.setDateTime( environment.getArgument("date"), environment.getArgument("time"), - context.transitService().getTimeZone() + ZoneIdFallback.zoneId(context.transitService().getTimeZone()) ); callWith.argument("wheelchair", request::setWheelchair); diff --git a/src/main/java/org/opentripplanner/framework/logging/Throttle.java b/src/main/java/org/opentripplanner/framework/logging/Throttle.java index 47417aa974a..631d59a2697 100644 --- a/src/main/java/org/opentripplanner/framework/logging/Throttle.java +++ b/src/main/java/org/opentripplanner/framework/logging/Throttle.java @@ -35,6 +35,10 @@ public static Throttle ofOneSecond() { return new Throttle(1000); } + public static Throttle ofOneMinute() { + return new Throttle(1000 * 60); + } + public String setupInfo() { return setupInfo; } diff --git a/src/main/java/org/opentripplanner/framework/time/ZoneIdFallback.java b/src/main/java/org/opentripplanner/framework/time/ZoneIdFallback.java new file mode 100644 index 00000000000..2d43216e4b2 --- /dev/null +++ b/src/main/java/org/opentripplanner/framework/time/ZoneIdFallback.java @@ -0,0 +1,39 @@ +package org.opentripplanner.framework.time; + +import java.time.ZoneId; +import javax.annotation.Nullable; +import org.opentripplanner.framework.logging.Throttle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class provides a fallback mechanism for retrieving a zone id (=time zone). + * If a ZoneId is not provided, it returns a default fallback ZoneId (UTC). + *

+ * This situation happens when you don't load any transit data into the graph but want to route + * anyway, perhaps only on the street network. + */ +public class ZoneIdFallback { + + private static final Logger LOG = LoggerFactory.getLogger(ZoneIdFallback.class); + private static final ZoneId FALLBACK = ZoneId.of("UTC"); + private static final Throttle THROTTLE = Throttle.ofOneMinute(); + + /** + * Accepts a nullable zone id (time zone) and returns UTC as the fallback. + */ + public static ZoneId zoneId(@Nullable ZoneId id) { + if (id == null) { + THROTTLE.throttle(() -> { + LOG.warn( + "Your instance doesn't contain a time zone (which is usually derived from transit data). Assuming {}.", + FALLBACK + ); + LOG.warn("Please double-check that transit data was correctly loaded."); + }); + return FALLBACK; + } else { + return id; + } + } +} diff --git a/src/main/java/org/opentripplanner/routing/algorithm/mapping/GraphPathToItineraryMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/mapping/GraphPathToItineraryMapper.java index 9858ccfee50..11302098f25 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/mapping/GraphPathToItineraryMapper.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/mapping/GraphPathToItineraryMapper.java @@ -18,6 +18,7 @@ import org.opentripplanner.framework.application.OTPFeature; import org.opentripplanner.framework.geometry.GeometryUtils; import org.opentripplanner.framework.i18n.I18NString; +import org.opentripplanner.framework.time.ZoneIdFallback; import org.opentripplanner.model.plan.ElevationProfile; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.Leg; @@ -58,7 +59,7 @@ public GraphPathToItineraryMapper( StreetNotesService streetNotesService, double ellipsoidToGeoidDifference ) { - this.timeZone = timeZone; + this.timeZone = ZoneIdFallback.zoneId(timeZone); this.streetNotesService = streetNotesService; this.ellipsoidToGeoidDifference = ellipsoidToGeoidDifference; } diff --git a/src/main/java/org/opentripplanner/routing/service/DefaultRoutingService.java b/src/main/java/org/opentripplanner/routing/service/DefaultRoutingService.java index 9879b52c9c1..01736aac80e 100644 --- a/src/main/java/org/opentripplanner/routing/service/DefaultRoutingService.java +++ b/src/main/java/org/opentripplanner/routing/service/DefaultRoutingService.java @@ -2,6 +2,7 @@ import java.time.ZoneId; import org.opentripplanner.framework.application.OTPRequestTimeoutException; +import org.opentripplanner.framework.time.ZoneIdFallback; import org.opentripplanner.framework.tostring.MultiLineToStringBuilder; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.routing.algorithm.RoutingWorker; @@ -30,7 +31,7 @@ public class DefaultRoutingService implements RoutingService { public DefaultRoutingService(OtpServerRequestContext serverContext) { this.serverContext = serverContext; - this.timeZone = serverContext.transitService().getTimeZone(); + this.timeZone = ZoneIdFallback.zoneId(serverContext.transitService().getTimeZone()); } @Override diff --git a/src/test/java/org/opentripplanner/framework/FrameworkArchitectureTest.java b/src/test/java/org/opentripplanner/framework/FrameworkArchitectureTest.java index e1e00076a73..9e44dd05dda 100644 --- a/src/test/java/org/opentripplanner/framework/FrameworkArchitectureTest.java +++ b/src/test/java/org/opentripplanner/framework/FrameworkArchitectureTest.java @@ -97,7 +97,7 @@ void enforceTextPackageDependencies() { @Test void enforceTimePackageDependencies() { - TIME.verify(); + TIME.dependsOn(LOGGING).verify(); } @Test diff --git a/src/test/java/org/opentripplanner/framework/time/ZoneIdFallbackTest.java b/src/test/java/org/opentripplanner/framework/time/ZoneIdFallbackTest.java new file mode 100644 index 00000000000..b69e3ee2ff1 --- /dev/null +++ b/src/test/java/org/opentripplanner/framework/time/ZoneIdFallbackTest.java @@ -0,0 +1,19 @@ +package org.opentripplanner.framework.time; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.opentripplanner._support.time.ZoneIds; + +class ZoneIdFallbackTest { + + @Test + void fallback() { + assertEquals(ZoneIds.UTC, ZoneIdFallback.zoneId(null)); + } + + @Test + void keepOriginal() { + assertEquals(ZoneIds.BERLIN, ZoneIdFallback.zoneId(ZoneIds.BERLIN)); + } +}