From 1faa689d33d11fc27746cb0c88f6f527882cf643 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 7 Feb 2024 17:43:50 +0100 Subject: [PATCH 001/121] Optionally abort the startup if configuration is invalid --- .../java/org/opentripplanner/standalone/OTPMain.java | 8 ++++++++ .../standalone/config/BuildConfig.java | 4 ++++ .../standalone/config/CommandLineParameters.java | 6 ++++++ .../standalone/config/ConfigModel.java | 11 +++++++++++ .../opentripplanner/standalone/config/OtpConfig.java | 4 ++++ .../standalone/config/RouterConfig.java | 4 ++++ .../standalone/config/framework/json/NodeAdapter.java | 4 ++++ 7 files changed, 41 insertions(+) diff --git a/src/main/java/org/opentripplanner/standalone/OTPMain.java b/src/main/java/org/opentripplanner/standalone/OTPMain.java index 365e1fb49c8..badfb73443d 100644 --- a/src/main/java/org/opentripplanner/standalone/OTPMain.java +++ b/src/main/java/org/opentripplanner/standalone/OTPMain.java @@ -113,6 +113,14 @@ private static void startOTPServer(CommandLineParameters cli) { var loadApp = new LoadApplication(cli); var config = loadApp.config(); + // optionally check if the config is valid and if not abort the startup process + if (cli.configCheck && config.hasInvalidProperties()) { + throw new OtpAppException( + "Configuration contains invalid properties (see above for details). " + + "Please fix your configuration or remove --configCheck from your OTP CLI parameters." + ); + } + // Validate data sources, command line arguments and config before loading and // processing input data to fail early loadApp.validateConfigAndDataSources(); diff --git a/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java b/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java index d62aa1bf41f..97b3c0de9f2 100644 --- a/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java @@ -719,4 +719,8 @@ public int getSubwayAccessTimeSeconds() { public NodeAdapter asNodeAdapter() { return root; } + + public boolean hasInvalidProperties() { + return root.hasInvalidProperties(); + } } diff --git a/src/main/java/org/opentripplanner/standalone/config/CommandLineParameters.java b/src/main/java/org/opentripplanner/standalone/config/CommandLineParameters.java index fb26db4877d..57446d0942e 100644 --- a/src/main/java/org/opentripplanner/standalone/config/CommandLineParameters.java +++ b/src/main/java/org/opentripplanner/standalone/config/CommandLineParameters.java @@ -133,6 +133,12 @@ public class CommandLineParameters { ) public boolean visualize; + @Parameter( + names = { "--configCheck" }, + description = "Abort the startup if configuration files are found to be invalid." + ) + public boolean configCheck = false; + /** * The remaining single parameter after the switches is the directory with the configuration * files. This directory may contain other files like the graph, input data and report files. diff --git a/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java b/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java index 48966aefc7b..df798dca672 100644 --- a/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java +++ b/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java @@ -105,4 +105,15 @@ public static void initializeOtpFeatures(OtpConfig otpConfig) { OTPFeature.enableFeatures(otpConfig.otpFeatures); OTPFeature.logFeatureSetup(); } + + /** + * Checks if any unknown or invalid properties were encountered while loading of the configuration. + */ + public boolean hasInvalidProperties() { + return ( + otpConfig.hasInvalidProperties() || + buildConfig.hasInvalidProperties() || + routerConfig.hasInvalidProperties() + ); + } } diff --git a/src/main/java/org/opentripplanner/standalone/config/OtpConfig.java b/src/main/java/org/opentripplanner/standalone/config/OtpConfig.java index 40a659df1ab..22845b60ad1 100644 --- a/src/main/java/org/opentripplanner/standalone/config/OtpConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/OtpConfig.java @@ -71,4 +71,8 @@ public OtpConfig(NodeAdapter nodeAdapter, boolean logUnusedParams) { root.logAllWarnings(LOG::warn); } } + + public boolean hasInvalidProperties() { + return root.hasInvalidProperties(); + } } diff --git a/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java b/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java index bf97155b747..c7c20ca065a 100644 --- a/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java @@ -150,4 +150,8 @@ public String toString() { // Print ONLY the values set, not default values return root.toPrettyString(); } + + public boolean hasInvalidProperties() { + return root.hasInvalidProperties(); + } } diff --git a/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java b/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java index 69d9937582b..52079d9f5a8 100644 --- a/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java +++ b/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java @@ -172,6 +172,10 @@ public void logAllWarnings(Consumer logger) { allWarnings().forEach(logger); } + public boolean hasInvalidProperties() { + return !unusedParams().isEmpty() || !allWarnings().toList().isEmpty(); + } + /** * Be careful when using this method - this bypasses the NodeAdaptor, and we loose * track of unused parameters and cannot generate documentation for the children. From a6d7518fe254e8de657935e172ec2ac5575a1232 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 8 Feb 2024 14:10:12 +0100 Subject: [PATCH 002/121] Add documentation --- .../org/opentripplanner/standalone/config/BuildConfig.java | 3 +++ .../org/opentripplanner/standalone/config/ConfigModel.java | 2 +- .../java/org/opentripplanner/standalone/config/OtpConfig.java | 3 +++ .../org/opentripplanner/standalone/config/RouterConfig.java | 4 +++- .../standalone/config/framework/json/NodeAdapter.java | 3 +++ 5 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java b/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java index 97b3c0de9f2..6ebd15019eb 100644 --- a/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java @@ -720,6 +720,9 @@ public NodeAdapter asNodeAdapter() { return root; } + /** + * Checks if any unknown or invalid properties were encountered while loading the configuration. + */ public boolean hasInvalidProperties() { return root.hasInvalidProperties(); } diff --git a/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java b/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java index df798dca672..820737ec8f9 100644 --- a/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java +++ b/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java @@ -107,7 +107,7 @@ public static void initializeOtpFeatures(OtpConfig otpConfig) { } /** - * Checks if any unknown or invalid properties were encountered while loading of the configuration. + * Checks if any unknown or invalid properties were encountered while loading the configuration. */ public boolean hasInvalidProperties() { return ( diff --git a/src/main/java/org/opentripplanner/standalone/config/OtpConfig.java b/src/main/java/org/opentripplanner/standalone/config/OtpConfig.java index 22845b60ad1..bb361c15d4f 100644 --- a/src/main/java/org/opentripplanner/standalone/config/OtpConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/OtpConfig.java @@ -72,6 +72,9 @@ public OtpConfig(NodeAdapter nodeAdapter, boolean logUnusedParams) { } } + /** + * Checks if any unknown or invalid properties were encountered while loading the configuration. + */ public boolean hasInvalidProperties() { return root.hasInvalidProperties(); } diff --git a/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java b/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java index c7c20ca065a..bea05936de7 100644 --- a/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java @@ -150,7 +150,9 @@ public String toString() { // Print ONLY the values set, not default values return root.toPrettyString(); } - + /** + * Checks if any unknown or invalid properties were encountered while loading the configuration. + */ public boolean hasInvalidProperties() { return root.hasInvalidProperties(); } diff --git a/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java b/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java index 52079d9f5a8..7a097b2edff 100644 --- a/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java +++ b/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java @@ -172,6 +172,9 @@ public void logAllWarnings(Consumer logger) { allWarnings().forEach(logger); } + /** + * Checks if any unknown or invalid properties were encountered while loading the configuration. + */ public boolean hasInvalidProperties() { return !unusedParams().isEmpty() || !allWarnings().toList().isEmpty(); } From 57243b0f2eac7435fdd2a2f94be376a93c841607 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 8 Feb 2024 14:10:56 +0100 Subject: [PATCH 003/121] Remove 'public' modifier --- .../framework/json/NodeAdapterTest.java | 90 +++++++++---------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java b/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java index be44d1ea86f..f414f6e7b34 100644 --- a/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java +++ b/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java @@ -34,7 +34,7 @@ public class NodeAdapterTest { public static final String NON_UNUSED_PARAMETERS = "EXPECTED_NONE"; @Test - public void testAsRawNode() { + void testAsRawNode() { NodeAdapter subject = newNodeAdapterForTest("{ child : { foo : 'bar' } }"); // Define child @@ -53,7 +53,7 @@ public void testAsRawNode() { } @Test - public void isEmpty() { + void isEmpty() { NodeAdapter subject = newNodeAdapterForTest(""); assertTrue(subject.of("alf").asObject().isEmpty()); @@ -64,7 +64,7 @@ public void isEmpty() { } @Test - public void path() { + void path() { NodeAdapter subject = newNodeAdapterForTest("{ foo : 'bar' }"); assertFalse(subject.of("foo").asObject().isEmpty()); assertTrue(subject.of("missingObject").asObject().isEmpty()); @@ -72,7 +72,7 @@ public void path() { } @Test - public void docInfo() { + void docInfo() { NodeAdapter subject = newNodeAdapterForTest("{ bool: false }"); subject.of("bool").since(V2_0).summary("B Summary").description("Ddd").asBoolean(); subject.of("en").since(V2_1).summary("EN Summary").asEnum(SECONDS); @@ -95,7 +95,7 @@ public void docInfo() { } @Test - public void asBoolean() { + void asBoolean() { NodeAdapter subject = newNodeAdapterForTest("{ aBoolean : true }"); assertTrue(subject.of("aBoolean").asBoolean()); assertTrue(subject.of("aBoolean").asBoolean(false)); @@ -103,7 +103,7 @@ public void asBoolean() { } @Test - public void asDouble() { + void asDouble() { NodeAdapter subject = newNodeAdapterForTest("{ aDouble : 7.0 }"); assertEquals(7.0, subject.of("aDouble").asDouble(-1d), 0.01); assertEquals(7.0, subject.of("aDouble").asDouble(), 0.01); @@ -111,28 +111,28 @@ public void asDouble() { } @Test - public void asDoubles() { + void asDoubles() { NodeAdapter subject = newNodeAdapterForTest("{ key : [ 2.0, 3.0, 5.0 ] }"); assertEquals(List.of(2d, 3d, 5d), subject.of("key").asDoubles(null)); assertEquals(NON_UNUSED_PARAMETERS, unusedParams(subject)); } @Test - public void asInt() { + void asInt() { NodeAdapter subject = newNodeAdapterForTest("{ aInt : 5 }"); assertEquals(5, subject.of("aInt").asInt(-1)); assertEquals(-1, subject.of("missingField").asInt(-1)); } @Test - public void asLong() { + void asLong() { NodeAdapter subject = newNodeAdapterForTest("{ key : 5 }"); assertEquals(5, subject.of("key").asLong(-1)); assertEquals(-1, subject.of("missingField").asLong(-1)); } @Test - public void asText() { + void asText() { NodeAdapter subject = newNodeAdapterForTest("{ aText : 'TEXT' }"); assertEquals("TEXT", subject.of("aText").asString("DEFAULT")); assertEquals("DEFAULT", subject.of("missingField").asString("DEFAULT")); @@ -142,19 +142,19 @@ public void asText() { } @Test - public void requiredAsText() { + void requiredAsText() { NodeAdapter subject = newNodeAdapterForTest("{ }"); assertThrows(OtpAppException.class, () -> subject.of("missingField").asString()); } @Test - public void rawAsText() { + void rawAsText() { NodeAdapter subject = newNodeAdapterForTest("{ aText : 'TEXT' }"); assertEquals("TEXT", subject.of("aText").asObject().asText()); } @Test - public void asEnum() { + void asEnum() { // Given NodeAdapter subject = newNodeAdapterForTest("{ a : 'A', abc : 'a-b-c' }"); @@ -169,7 +169,7 @@ public void asEnum() { } @Test - public void asEnumWithIllegalPropertySet() { + void asEnumWithIllegalPropertySet() { // Given NodeAdapter subject = newNodeAdapterForTest( """ @@ -205,7 +205,7 @@ public void asEnumWithIllegalPropertySet() { } @Test - public void asEnumMap() { + void asEnumMap() { // With optional enum values in map NodeAdapter subject = newNodeAdapterForTest("{ key : { A: true, B: false } }"); assertEquals( @@ -220,7 +220,7 @@ public void asEnumMap() { } @Test - public void asEnumMapWithCustomType() { + void asEnumMapWithCustomType() { // With optional enum values in map NodeAdapter subject = newNodeAdapterForTest("{ key : { A: {a:'Foo'} } }"); assertEquals( @@ -235,7 +235,7 @@ public void asEnumMapWithCustomType() { } @Test - public void asEnumMapWithDefaultValue() { + void asEnumMapWithDefaultValue() { var subject = newNodeAdapterForTest("{}"); final Map dflt = Map.of(AnEnum.A, new ARecord("Foo")); assertEquals(dflt, subject.of("key").asEnumMap(AnEnum.class, ARecord::fromJson, dflt)); @@ -243,7 +243,7 @@ public void asEnumMapWithDefaultValue() { } @Test - public void asEnumMapWithUnknownKey() { + void asEnumMapWithUnknownKey() { NodeAdapter subject = newNodeAdapterForTest("{ enumMap : { unknown : 7 } }"); subject.of("enumMap").asEnumMap(AnEnum.class, Double.class); @@ -261,7 +261,7 @@ public void asEnumMapWithUnknownKey() { } @Test - public void asEnumMapAllKeysRequired() { + void asEnumMapAllKeysRequired() { var subject = newNodeAdapterForTest("{ key : { A: true, b: false, a_B_c: true } }"); assertEquals( Map.of(AnEnum.A, true, AnEnum.B, false, AnEnum.A_B_C, true), @@ -280,7 +280,7 @@ public void asEnumMapAllKeysRequired() { } @Test - public void asEnumMapWithRequiredMissingValue() { + void asEnumMapWithRequiredMissingValue() { // A value for C is missing in map NodeAdapter subject = newNodeAdapterForTest("{ key : { A: true, B: false } }"); @@ -291,7 +291,7 @@ public void asEnumMapWithRequiredMissingValue() { } @Test - public void asEnumSet() { + void asEnumSet() { NodeAdapter subject = newNodeAdapterForTest("{ key : [ 'A', 'B' ] }"); assertEquals(Set.of(AnEnum.A, AnEnum.B), subject.of("key").asEnumSet(AnEnum.class)); assertEquals(Set.of(), subject.of("missing-key").asEnumSet(AnEnum.class)); @@ -299,13 +299,13 @@ public void asEnumSet() { } @Test - public void asEnumSetFailsUsingWrongFormat() { + void asEnumSetFailsUsingWrongFormat() { NodeAdapter subject = newNodeAdapterForTest("{ key : 'A,B' }"); assertThrows(OtpAppException.class, () -> subject.of("key").asEnumSet(AnEnum.class)); } @Test - public void asFeedScopedId() { + void asFeedScopedId() { NodeAdapter subject = newNodeAdapterForTest("{ key1: 'A:23', key2: 'B:12' }"); assertEquals("A:23", subject.of("key1").asFeedScopedId(null).toString()); assertEquals("B:12", subject.of("key2").asFeedScopedId(null).toString()); @@ -316,7 +316,7 @@ public void asFeedScopedId() { } @Test - public void asFeedScopedIds() { + void asFeedScopedIds() { NodeAdapter subject = newNodeAdapterForTest("{ routes: ['A:23', 'B:12']}"); assertEquals("[A:23, B:12]", subject.of("routes").asFeedScopedIds(List.of()).toString()); assertEquals("[]", subject.of("missing-key").asFeedScopedIds(List.of()).toString()); @@ -328,7 +328,7 @@ public void asFeedScopedIds() { } @Test - public void asFeedScopedIdSet() { + void asFeedScopedIdSet() { NodeAdapter subject = newNodeAdapterForTest("{ routes: ['A:23', 'B:12', 'A:23']}"); assertEquals( List.of( @@ -342,7 +342,7 @@ public void asFeedScopedIdSet() { } @Test - public void asDateOrRelativePeriod() { + void asDateOrRelativePeriod() { // Given var subject = newNodeAdapterForTest("{ 'a' : '2020-02-28', 'b' : '-P3Y' }"); var utc = ZoneIds.UTC; @@ -362,7 +362,7 @@ public void asDateOrRelativePeriod() { } @Test - public void testParsePeriodDateThrowsException() { + void testParsePeriodDateThrowsException() { // Given NodeAdapter subject = newNodeAdapterForTest("{ 'foo' : 'bar' }"); @@ -374,7 +374,7 @@ public void testParsePeriodDateThrowsException() { } @Test - public void asDuration() { + void asDuration() { NodeAdapter subject = newNodeAdapterForTest("{ k1:'PT1s', k2:'3h2m1s', k3:7 }"); // as required duration @@ -390,13 +390,13 @@ public void asDuration() { } @Test - public void requiredAsDuration() { + void requiredAsDuration() { NodeAdapter subject = newNodeAdapterForTest("{ }"); assertThrows(OtpAppException.class, () -> subject.of("missingField").asDuration()); } @Test - public void asDurations() { + void asDurations() { NodeAdapter subject = newNodeAdapterForTest("{ key1 : ['PT1s', '2h'] }"); assertEquals("[PT1S, PT2H]", subject.of("key1").asDurations(List.of()).toString()); assertEquals("[PT3H]", subject.of("missing-key").asDurations(List.of(D3h)).toString()); @@ -404,7 +404,7 @@ public void asDurations() { } @Test - public void asLocale() { + void asLocale() { NodeAdapter subject = newNodeAdapterForTest( "{ key1 : 'no', key2 : 'no_NO', key3 : 'no_NO_NY' }" ); @@ -415,14 +415,14 @@ public void asLocale() { } @Test - public void asPattern() { + void asPattern() { NodeAdapter subject = newNodeAdapterForTest("{ key : 'Ab*a' }"); assertEquals("Ab*a", subject.of("key").asPattern("ABC").toString()); assertEquals("ABC", subject.of("missingField").asPattern("ABC").toString()); } @Test - public void uri() { + void uri() { var URL = "gs://bucket/a.obj"; NodeAdapter subject = newNodeAdapterForTest("{ aUri : '" + URL + "' }"); @@ -433,14 +433,14 @@ public void uri() { } @Test - public void uriSyntaxException() { + void uriSyntaxException() { NodeAdapter subject = newNodeAdapterForTest("{ aUri : 'error$%uri' }"); assertThrows(OtpAppException.class, () -> subject.of("aUri").asUri(null), "error$%uri"); } @Test - public void uriRequiredValueMissing() { + void uriRequiredValueMissing() { NodeAdapter subject = newNodeAdapterForTest("{ }"); assertThrows( @@ -451,7 +451,7 @@ public void uriRequiredValueMissing() { } @Test - public void uris() { + void uris() { NodeAdapter subject = newNodeAdapterForTest("{ foo : ['gs://a/b', 'gs://c/d'] }"); assertEquals("[gs://a/b, gs://c/d]", subject.of("foo").asUris().toString()); @@ -461,7 +461,7 @@ public void uris() { } @Test - public void urisNotAnArrayException() { + void urisNotAnArrayException() { NodeAdapter subject = newNodeAdapterForTest("{ 'uris': 'no array' }"); assertThrows( @@ -472,7 +472,7 @@ public void urisNotAnArrayException() { } @Test - public void objectAsList() { + void objectAsList() { NodeAdapter subject = newNodeAdapterForTest("{ key : [{ a: 'I' }, { a: '2' } ] }"); List result = subject @@ -487,21 +487,21 @@ public void objectAsList() { } @Test - public void asCostLinearFunction() { + void asCostLinearFunction() { NodeAdapter subject = newNodeAdapterForTest("{ key : '400+8x' }"); assertEquals("6m40s + 8.0 t", subject.of("key").asCostLinearFunction(null).toString()); assertNull(subject.of("no-key").asCostLinearFunction(null)); } @Test - public void asTimePenalty() { + void asTimePenalty() { NodeAdapter subject = newNodeAdapterForTest("{ key : '400+8x' }"); assertEquals("6m40s + 8.0 t", subject.of("key").asTimePenalty(null).toString()); assertNull(subject.of("no-key").asTimePenalty(null)); } @Test - public void asZoneId() { + void asZoneId() { NodeAdapter subject = newNodeAdapterForTest( "{ key1 : 'UTC', key2 : 'Europe/Oslo', key3 : '+02:00', key4: 'invalid' }" ); @@ -515,7 +515,7 @@ public void asZoneId() { } @Test - public void asTextSet() { + void asTextSet() { NodeAdapter subject = newNodeAdapterForTest("{ ids : ['A', 'C', 'F'] }"); assertEquals( Set.of("A", "C", "F"), @@ -528,7 +528,7 @@ public void asTextSet() { } @Test - public void isNonEmptyArray() { + void isNonEmptyArray() { NodeAdapter subject = newNodeAdapterForTest("{ foo : ['A'], bar: [], foobar: true }"); assertTrue(subject.of("foo").asObject().isNonEmptyArray()); assertFalse(subject.of("bar").asObject().isNonEmptyArray()); @@ -538,13 +538,13 @@ public void isNonEmptyArray() { } @Test - public void deduplicateChildren() { + void deduplicateChildren() { NodeAdapter subject = newNodeAdapterForTest("{ foo : { enabled: true } }"); assertSame(subject.of("foo").asObject(), subject.of("foo").asObject()); } @Test - public void unusedParams() { + void unusedParams() { // Given: two parameters a and b NodeAdapter subject = newNodeAdapterForTest("{ foo : { a: true, b: false } }"); var buf = new StringBuilder(); From 43a682662b4caf6379d8f320efc29054dc13d0ef Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 8 Feb 2024 14:24:44 +0100 Subject: [PATCH 004/121] Add test --- .../standalone/config/RouterConfig.java | 1 + .../framework/json/ParameterBuilder.java | 4 --- .../framework/json/NodeAdapterTest.java | 28 +++++++++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java b/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java index bea05936de7..d4df555c600 100644 --- a/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java @@ -150,6 +150,7 @@ public String toString() { // Print ONLY the values set, not default values return root.toPrettyString(); } + /** * Checks if any unknown or invalid properties were encountered while loading the configuration. */ diff --git a/src/main/java/org/opentripplanner/standalone/config/framework/json/ParameterBuilder.java b/src/main/java/org/opentripplanner/standalone/config/framework/json/ParameterBuilder.java index 088a7794585..3ecc4d484cb 100644 --- a/src/main/java/org/opentripplanner/standalone/config/framework/json/ParameterBuilder.java +++ b/src/main/java/org/opentripplanner/standalone/config/framework/json/ParameterBuilder.java @@ -120,10 +120,6 @@ public Boolean asBoolean(boolean defaultValue) { return ofOptional(BOOLEAN, defaultValue, JsonNode::asBoolean); } - public Map asBooleanMap() { - return ofOptionalMap(BOOLEAN, JsonNode::asBoolean); - } - /** @throws OtpAppException if parameter is missing. */ public double asDouble() { return ofRequired(DOUBLE).asDouble(); diff --git a/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java b/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java index f414f6e7b34..71bb9d380a2 100644 --- a/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java +++ b/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java @@ -23,6 +23,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.opentripplanner._support.time.ZoneIds; import org.opentripplanner.framework.application.OtpAppException; @@ -557,6 +558,33 @@ void unusedParams() { assertEquals("Unexpected config parameter: 'foo.b:false' in 'Test'", buf.toString()); } + @Nested + class Validation { + + @Test + void invalidProperties() { + // Given: two parameters a and b + NodeAdapter subject = newNodeAdapterForTest("{ foo : { a: true, b: false } }"); + + // When: Access ONLY parameter 'a', but not 'b' + subject.of("foo").asObject().of("a").asBoolean(); + + assertTrue(subject.hasInvalidProperties()); + } + + @Test + void valid() { + // Given: two parameters a and b + NodeAdapter subject = newNodeAdapterForTest("{ foo : { a: true, b: false } }"); + + var object = subject.of("foo").asObject(); + object.of("a").asBoolean(); + object.of("b").asBoolean(); + + assertFalse(subject.hasInvalidProperties()); + } + } + private static String unusedParams(NodeAdapter subject) { var buf = new StringBuilder(); subject.logAllWarnings(m -> buf.append('\n').append(m)); From c3da460ce0f90b290ad5feedcea3b1b42e448116 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 8 Feb 2024 14:44:29 +0100 Subject: [PATCH 005/121] Add documentation --- docs/Migrating-Configuration.md | 27 +++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 28 insertions(+) create mode 100644 docs/Migrating-Configuration.md diff --git a/docs/Migrating-Configuration.md b/docs/Migrating-Configuration.md new file mode 100644 index 00000000000..5517d0c272e --- /dev/null +++ b/docs/Migrating-Configuration.md @@ -0,0 +1,27 @@ +While OTP's GraphQL APIs are very, very stable even across versions, the JSON configuration schema +is not. Changes to it are relatively frequent and you can see all PRs that change it with +the [Github tag 'config change'](https://github.com/opentripplanner/OpenTripPlanner/pulls?q=label%3A%22config+change%22). + +### Migrating the JSON configuration + +OTP validates the configuration and prints warnings during startup. This means that when you +migrate to a newer version, you should carefully inspect the logs. If you see messages like + +``` +(NodeAdapter.java:170) Unexpected config parameter: 'routingDefaults.stairsReluctance:1.65' in 'router-config.json' +``` + +this means there are properties in your configuration that are unknown to OTP and therefore likely +to be a configuration error, perhaps because the schema was changed. In such a case you should +consult the [feature](Configuration.md#otp-features), [router](RouterConfiguration.md) or +[build configuration documentation](BuildConfiguration.md) to find out what he new schema looks like. + +### Aborting on invalid configuration + +If you want OTP to abort the startup when encountering invalid configuration, you can add the flag +`--configCheck` to your regular OTP CLI commands. + +This should of course be used wisely as it can also accidentally make your production instances refuse +to start up. +Therefore, we recommend that you use it only in a separate pre-production step, perhaps during graph +build. \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index c4717d4d2e0..36ea39050ac 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -75,6 +75,7 @@ nav: - Router: 'RouterConfiguration.md' - "Route Request": 'RouteRequest.md' - "Realtime Updaters": 'UpdaterConfig.md' + - "Migrating Configuration": 'Migrating-Configuration.md' - Features explained: - "Routing modes": 'RoutingModes.md' - "In-station navigation": 'In-Station-Navigation.md' From f499a455b6c0597daac112a4855cf35374fc0d3c Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 9 Feb 2024 10:19:30 +0100 Subject: [PATCH 006/121] Fix typo --- docs/Migrating-Configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Migrating-Configuration.md b/docs/Migrating-Configuration.md index 5517d0c272e..0d40faf74e8 100644 --- a/docs/Migrating-Configuration.md +++ b/docs/Migrating-Configuration.md @@ -14,7 +14,7 @@ migrate to a newer version, you should carefully inspect the logs. If you see me this means there are properties in your configuration that are unknown to OTP and therefore likely to be a configuration error, perhaps because the schema was changed. In such a case you should consult the [feature](Configuration.md#otp-features), [router](RouterConfiguration.md) or -[build configuration documentation](BuildConfiguration.md) to find out what he new schema looks like. +[build configuration documentation](BuildConfiguration.md) to find out what the new schema looks like. ### Aborting on invalid configuration From cc0c13d34e4c2054697ec52973027ae626e4b68c Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 1 Mar 2024 12:51:00 +0200 Subject: [PATCH 007/121] Fix issue with cancellations on trip patterns that run after midnight --- .../routing/algorithm/raptoradapter/transit/TransitLayer.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayer.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayer.java index 60cfb72ef7d..461c15e8f66 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayer.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayer.java @@ -119,9 +119,11 @@ public List getTripPatternsRunningOnDateCopy(LocalDate runni public List getTripPatternsStartingOnDateCopy(LocalDate date) { List tripPatternsRunningOnDate = getTripPatternsRunningOnDateCopy(date); + tripPatternsRunningOnDate.addAll(getTripPatternsRunningOnDateCopy(date.plusDays(1))); return tripPatternsRunningOnDate .stream() .filter(t -> t.getLocalDate().equals(date)) + .distinct() .collect(Collectors.toList()); } From bd702cda23caf0b09aa342c932268f955a11469b Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 11 Mar 2024 12:58:43 +0100 Subject: [PATCH 008/121] Apply review feedback --- .../opentripplanner/standalone/OTPMain.java | 21 ++++++++++++------- .../standalone/config/BuildConfig.java | 4 ++-- .../standalone/config/ConfigModel.java | 8 +++---- .../standalone/config/OtpConfig.java | 4 ++-- .../standalone/config/RouterConfig.java | 4 ++-- .../config/framework/json/NodeAdapter.java | 2 +- .../framework/json/NodeAdapterTest.java | 4 ++-- 7 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/opentripplanner/standalone/OTPMain.java b/src/main/java/org/opentripplanner/standalone/OTPMain.java index badfb73443d..eef7415644d 100644 --- a/src/main/java/org/opentripplanner/standalone/OTPMain.java +++ b/src/main/java/org/opentripplanner/standalone/OTPMain.java @@ -13,6 +13,7 @@ import org.opentripplanner.raptor.configure.RaptorConfig; import org.opentripplanner.routing.graph.SerializedGraphObject; import org.opentripplanner.standalone.config.CommandLineParameters; +import org.opentripplanner.standalone.config.ConfigModel; import org.opentripplanner.standalone.configure.ConstructApplication; import org.opentripplanner.standalone.configure.LoadApplication; import org.opentripplanner.standalone.server.GrizzlyServer; @@ -113,13 +114,7 @@ private static void startOTPServer(CommandLineParameters cli) { var loadApp = new LoadApplication(cli); var config = loadApp.config(); - // optionally check if the config is valid and if not abort the startup process - if (cli.configCheck && config.hasInvalidProperties()) { - throw new OtpAppException( - "Configuration contains invalid properties (see above for details). " + - "Please fix your configuration or remove --configCheck from your OTP CLI parameters." - ); - } + detectUnusedConfigParams(cli, config); // Validate data sources, command line arguments and config before loading and // processing input data to fail early @@ -180,6 +175,18 @@ private static void startOTPServer(CommandLineParameters cli) { } } + /** + * Optionally, check if the config is valid and if not abort the startup process. + */ + private static void detectUnusedConfigParams(CommandLineParameters cli, ConfigModel config) { + if (cli.configCheck && config.hasIUnknownProperties()) { + throw new OtpAppException( + "Configuration contains invalid properties (see above for details). " + + "Please fix your configuration or remove --configCheck from your OTP CLI parameters." + ); + } + } + private static void startOtpWebServer(CommandLineParameters params, ConstructApplication app) { // Index graph for travel search app.transitModel().index(); diff --git a/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java b/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java index 6ebd15019eb..b6912488173 100644 --- a/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java @@ -723,7 +723,7 @@ public NodeAdapter asNodeAdapter() { /** * Checks if any unknown or invalid properties were encountered while loading the configuration. */ - public boolean hasInvalidProperties() { - return root.hasInvalidProperties(); + public boolean hasUnknownProperties() { + return root.hasUnknownProperties(); } } diff --git a/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java b/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java index 820737ec8f9..a9506ed514e 100644 --- a/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java +++ b/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java @@ -109,11 +109,11 @@ public static void initializeOtpFeatures(OtpConfig otpConfig) { /** * Checks if any unknown or invalid properties were encountered while loading the configuration. */ - public boolean hasInvalidProperties() { + public boolean hasIUnknownProperties() { return ( - otpConfig.hasInvalidProperties() || - buildConfig.hasInvalidProperties() || - routerConfig.hasInvalidProperties() + otpConfig.hasUnknownProperties() || + buildConfig.hasUnknownProperties() || + routerConfig.hasUnknownProperties() ); } } diff --git a/src/main/java/org/opentripplanner/standalone/config/OtpConfig.java b/src/main/java/org/opentripplanner/standalone/config/OtpConfig.java index bb361c15d4f..29f866123e3 100644 --- a/src/main/java/org/opentripplanner/standalone/config/OtpConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/OtpConfig.java @@ -75,7 +75,7 @@ public OtpConfig(NodeAdapter nodeAdapter, boolean logUnusedParams) { /** * Checks if any unknown or invalid properties were encountered while loading the configuration. */ - public boolean hasInvalidProperties() { - return root.hasInvalidProperties(); + public boolean hasUnknownProperties() { + return root.hasUnknownProperties(); } } diff --git a/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java b/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java index d4df555c600..ee8c46aa447 100644 --- a/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java @@ -154,7 +154,7 @@ public String toString() { /** * Checks if any unknown or invalid properties were encountered while loading the configuration. */ - public boolean hasInvalidProperties() { - return root.hasInvalidProperties(); + public boolean hasUnknownProperties() { + return root.hasUnknownProperties(); } } diff --git a/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java b/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java index 7a097b2edff..930b5c1799f 100644 --- a/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java +++ b/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java @@ -175,7 +175,7 @@ public void logAllWarnings(Consumer logger) { /** * Checks if any unknown or invalid properties were encountered while loading the configuration. */ - public boolean hasInvalidProperties() { + public boolean hasUnknownProperties() { return !unusedParams().isEmpty() || !allWarnings().toList().isEmpty(); } diff --git a/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java b/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java index 71bb9d380a2..4ab5545cc23 100644 --- a/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java +++ b/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java @@ -569,7 +569,7 @@ void invalidProperties() { // When: Access ONLY parameter 'a', but not 'b' subject.of("foo").asObject().of("a").asBoolean(); - assertTrue(subject.hasInvalidProperties()); + assertTrue(subject.hasUnknownProperties()); } @Test @@ -581,7 +581,7 @@ void valid() { object.of("a").asBoolean(); object.of("b").asBoolean(); - assertFalse(subject.hasInvalidProperties()); + assertFalse(subject.hasUnknownProperties()); } } From e6ba88e461f5220a97a1ea6f3165850ac4eabef5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 11 Mar 2024 13:14:56 +0100 Subject: [PATCH 009/121] Update documentation --- docs/Migrating-Configuration.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/Migrating-Configuration.md b/docs/Migrating-Configuration.md index 0d40faf74e8..54b34ae4719 100644 --- a/docs/Migrating-Configuration.md +++ b/docs/Migrating-Configuration.md @@ -16,10 +16,20 @@ to be a configuration error, perhaps because the schema was changed. In such a c consult the [feature](Configuration.md#otp-features), [router](RouterConfiguration.md) or [build configuration documentation](BuildConfiguration.md) to find out what the new schema looks like. +By default, OTP starts up even when unknown configuration parameters have been found. This is there +to support the style deployment where old config parameters remain in the file for a certain migration +period. + +This allows you to roll back the OTP version without the need to roll back the OTP configuration. + +An example: you change the location of the graphs, a critical error occurs afterwards and you need to +roll back. Any member of the dev-ops team should then be confident that they can roll back without +risk - even if the environment changed. + ### Aborting on invalid configuration -If you want OTP to abort the startup when encountering invalid configuration, you can add the flag -`--configCheck` to your regular OTP CLI commands. +If you want OTP to abort the startup when encountering unknown configuration parameters, you can add +the flag `--configCheck` to your regular OTP CLI commands. This should of course be used wisely as it can also accidentally make your production instances refuse to start up. From ba8e563a5f3e0572808d1ed41a4dcbea6dd7b23c Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 12 Mar 2024 15:41:02 +0100 Subject: [PATCH 010/121] Apply review feedback --- docs/Migrating-Configuration.md | 2 +- mkdocs.yml | 2 +- src/main/java/org/opentripplanner/standalone/OTPMain.java | 4 ++-- .../standalone/config/CommandLineParameters.java | 4 ++-- .../org/opentripplanner/standalone/config/ConfigModel.java | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/Migrating-Configuration.md b/docs/Migrating-Configuration.md index 54b34ae4719..ab36ebf4fa0 100644 --- a/docs/Migrating-Configuration.md +++ b/docs/Migrating-Configuration.md @@ -29,7 +29,7 @@ risk - even if the environment changed. ### Aborting on invalid configuration If you want OTP to abort the startup when encountering unknown configuration parameters, you can add -the flag `--configCheck` to your regular OTP CLI commands. +the flag `--abortOnUnknownConfig` to your regular OTP CLI commands. This should of course be used wisely as it can also accidentally make your production instances refuse to start up. diff --git a/mkdocs.yml b/mkdocs.yml index 3fbcf849a03..c14e451a906 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -76,7 +76,7 @@ nav: - Router: 'RouterConfiguration.md' - "Route Request": 'RouteRequest.md' - "Realtime Updaters": 'UpdaterConfig.md' - - "Migrating Configuration": 'Migrating-Configuration.md' + - "Migrating between versions/builds": 'Migrating-Configuration.md' - Features explained: - "Routing modes": 'RoutingModes.md' - "In-station navigation": 'In-Station-Navigation.md' diff --git a/src/main/java/org/opentripplanner/standalone/OTPMain.java b/src/main/java/org/opentripplanner/standalone/OTPMain.java index c2adc1d9db2..133024dcaa8 100644 --- a/src/main/java/org/opentripplanner/standalone/OTPMain.java +++ b/src/main/java/org/opentripplanner/standalone/OTPMain.java @@ -180,10 +180,10 @@ private static void startOTPServer(CommandLineParameters cli) { * Optionally, check if the config is valid and if not abort the startup process. */ private static void detectUnusedConfigParams(CommandLineParameters cli, ConfigModel config) { - if (cli.configCheck && config.hasIUnknownProperties()) { + if (cli.abortOnUnknownConfig && config.hasUnknownProperties()) { throw new OtpAppException( "Configuration contains invalid properties (see above for details). " + - "Please fix your configuration or remove --configCheck from your OTP CLI parameters." + "Please fix your configuration or remove --abortOnUnknownConfig from your OTP CLI parameters." ); } } diff --git a/src/main/java/org/opentripplanner/standalone/config/CommandLineParameters.java b/src/main/java/org/opentripplanner/standalone/config/CommandLineParameters.java index 57446d0942e..2cdd8ed5c1b 100644 --- a/src/main/java/org/opentripplanner/standalone/config/CommandLineParameters.java +++ b/src/main/java/org/opentripplanner/standalone/config/CommandLineParameters.java @@ -134,10 +134,10 @@ public class CommandLineParameters { public boolean visualize; @Parameter( - names = { "--configCheck" }, + names = { "--abortOnUnknownConfig" }, description = "Abort the startup if configuration files are found to be invalid." ) - public boolean configCheck = false; + public boolean abortOnUnknownConfig = false; /** * The remaining single parameter after the switches is the directory with the configuration diff --git a/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java b/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java index a9506ed514e..b03f6b4f959 100644 --- a/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java +++ b/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java @@ -109,7 +109,7 @@ public static void initializeOtpFeatures(OtpConfig otpConfig) { /** * Checks if any unknown or invalid properties were encountered while loading the configuration. */ - public boolean hasIUnknownProperties() { + public boolean hasUnknownProperties() { return ( otpConfig.hasUnknownProperties() || buildConfig.hasUnknownProperties() || From 5aeeffa2a953c9e80e4c66d2cec7ca83afe58114 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 13 Mar 2024 10:56:34 +0100 Subject: [PATCH 011/121] 'property' -> 'parameter' --- .../java/org/opentripplanner/standalone/OTPMain.java | 4 ++-- .../opentripplanner/standalone/config/BuildConfig.java | 6 +++--- .../standalone/config/CommandLineParameters.java | 2 +- .../opentripplanner/standalone/config/ConfigModel.java | 10 +++++----- .../opentripplanner/standalone/config/OtpConfig.java | 6 +++--- .../standalone/config/RouterConfig.java | 6 +++--- .../standalone/config/framework/json/NodeAdapter.java | 2 +- .../config/framework/json/NodeAdapterTest.java | 4 ++-- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/opentripplanner/standalone/OTPMain.java b/src/main/java/org/opentripplanner/standalone/OTPMain.java index 133024dcaa8..de5ccd7057c 100644 --- a/src/main/java/org/opentripplanner/standalone/OTPMain.java +++ b/src/main/java/org/opentripplanner/standalone/OTPMain.java @@ -180,9 +180,9 @@ private static void startOTPServer(CommandLineParameters cli) { * Optionally, check if the config is valid and if not abort the startup process. */ private static void detectUnusedConfigParams(CommandLineParameters cli, ConfigModel config) { - if (cli.abortOnUnknownConfig && config.hasUnknownProperties()) { + if (cli.abortOnUnknownConfig && config.hasUnknownParameters()) { throw new OtpAppException( - "Configuration contains invalid properties (see above for details). " + + "Configuration contains unknown parameters (see above for details). " + "Please fix your configuration or remove --abortOnUnknownConfig from your OTP CLI parameters." ); } diff --git a/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java b/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java index 1019a945c58..a3c6f313799 100644 --- a/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java @@ -728,9 +728,9 @@ public NodeAdapter asNodeAdapter() { } /** - * Checks if any unknown or invalid properties were encountered while loading the configuration. + * Checks if any unknown or invalid parameters were encountered while loading the configuration. */ - public boolean hasUnknownProperties() { - return root.hasUnknownProperties(); + public boolean hasUnknownParameters() { + return root.hasUnknownParameters(); } } diff --git a/src/main/java/org/opentripplanner/standalone/config/CommandLineParameters.java b/src/main/java/org/opentripplanner/standalone/config/CommandLineParameters.java index 2cdd8ed5c1b..3513ec252ea 100644 --- a/src/main/java/org/opentripplanner/standalone/config/CommandLineParameters.java +++ b/src/main/java/org/opentripplanner/standalone/config/CommandLineParameters.java @@ -135,7 +135,7 @@ public class CommandLineParameters { @Parameter( names = { "--abortOnUnknownConfig" }, - description = "Abort the startup if configuration files are found to be invalid." + description = "Abort the startup if configuration files are found to contain unknown parameters." ) public boolean abortOnUnknownConfig = false; diff --git a/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java b/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java index b03f6b4f959..8cffa5002e4 100644 --- a/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java +++ b/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java @@ -107,13 +107,13 @@ public static void initializeOtpFeatures(OtpConfig otpConfig) { } /** - * Checks if any unknown or invalid properties were encountered while loading the configuration. + * Checks if any unknown or invalid parameters were encountered while loading the configuration. */ - public boolean hasUnknownProperties() { + public boolean hasUnknownParameters() { return ( - otpConfig.hasUnknownProperties() || - buildConfig.hasUnknownProperties() || - routerConfig.hasUnknownProperties() + otpConfig.hasUnknownParameters() || + buildConfig.hasUnknownParameters() || + routerConfig.hasUnknownParameters() ); } } diff --git a/src/main/java/org/opentripplanner/standalone/config/OtpConfig.java b/src/main/java/org/opentripplanner/standalone/config/OtpConfig.java index 29f866123e3..2918cbc3884 100644 --- a/src/main/java/org/opentripplanner/standalone/config/OtpConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/OtpConfig.java @@ -73,9 +73,9 @@ public OtpConfig(NodeAdapter nodeAdapter, boolean logUnusedParams) { } /** - * Checks if any unknown or invalid properties were encountered while loading the configuration. + * Checks if any unknown or invalid parameters were encountered while loading the configuration. */ - public boolean hasUnknownProperties() { - return root.hasUnknownProperties(); + public boolean hasUnknownParameters() { + return root.hasUnknownParameters(); } } diff --git a/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java b/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java index ee8c46aa447..4ac0688a759 100644 --- a/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java @@ -152,9 +152,9 @@ public String toString() { } /** - * Checks if any unknown or invalid properties were encountered while loading the configuration. + * Checks if any unknown or invalid parameters were encountered while loading the configuration. */ - public boolean hasUnknownProperties() { - return root.hasUnknownProperties(); + public boolean hasUnknownParameters() { + return root.hasUnknownParameters(); } } diff --git a/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java b/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java index 930b5c1799f..9523e330eca 100644 --- a/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java +++ b/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java @@ -175,7 +175,7 @@ public void logAllWarnings(Consumer logger) { /** * Checks if any unknown or invalid properties were encountered while loading the configuration. */ - public boolean hasUnknownProperties() { + public boolean hasUnknownParameters() { return !unusedParams().isEmpty() || !allWarnings().toList().isEmpty(); } diff --git a/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java b/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java index 4ab5545cc23..5a1aa2f0063 100644 --- a/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java +++ b/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java @@ -569,7 +569,7 @@ void invalidProperties() { // When: Access ONLY parameter 'a', but not 'b' subject.of("foo").asObject().of("a").asBoolean(); - assertTrue(subject.hasUnknownProperties()); + assertTrue(subject.hasUnknownParameters()); } @Test @@ -581,7 +581,7 @@ void valid() { object.of("a").asBoolean(); object.of("b").asBoolean(); - assertFalse(subject.hasUnknownProperties()); + assertFalse(subject.hasUnknownParameters()); } } From be6884015c5da64969b3b67f925a01a105a88714 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Wed, 20 Mar 2024 22:20:23 +0200 Subject: [PATCH 012/121] Add tests for TransitLayer --- .../transit/TransitLayerTest.java | 201 ++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayerTest.java diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayerTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayerTest.java new file mode 100644 index 00000000000..9886ab5b9fc --- /dev/null +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayerTest.java @@ -0,0 +1,201 @@ +package org.opentripplanner.routing.algorithm.raptoradapter.transit; + +import static java.util.Map.entry; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.LocalDate; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; +import org.opentripplanner.model.StopTime; +import org.opentripplanner.transit.model._data.TransitModelForTest; +import org.opentripplanner.transit.model.framework.Deduplicator; +import org.opentripplanner.transit.model.network.RoutingTripPattern; +import org.opentripplanner.transit.model.network.StopPattern; +import org.opentripplanner.transit.model.network.TripPattern; +import org.opentripplanner.transit.model.timetable.TripTimes; +import org.opentripplanner.transit.model.timetable.TripTimesFactory; + +class TransitLayerTest { + + private static final TransitModelForTest TEST_MODEL = TransitModelForTest.of(); + private static final TripTimes TRIP_TIMES; + + private static final RoutingTripPattern TRIP_PATTERN; + + static { + var stop = TEST_MODEL.stop("TEST:STOP", 0, 0).build(); + var stopTime = new StopTime(); + stopTime.setStop(stop); + var stopPattern = new StopPattern(List.of(stopTime)); + var route = TransitModelForTest.route("1").build(); + TRIP_PATTERN = + TripPattern + .of(TransitModelForTest.id("P1")) + .withRoute(route) + .withStopPattern(stopPattern) + .build() + .getRoutingTripPattern(); + TRIP_TIMES = + TripTimesFactory.tripTimes( + TransitModelForTest.trip("1").withRoute(route).build(), + List.of(new StopTime()), + new Deduplicator() + ); + } + + @Test + void testGetTripPatternsRunningOnDateCopy() { + var date = LocalDate.of(2024, 1, 1); + + var tripPatternForDate = new TripPatternForDate( + TRIP_PATTERN, + List.of(TRIP_TIMES), + List.of(), + date + ); + var tripPatterns = List.of(tripPatternForDate); + var transitLayer = new TransitLayer( + Map.of(date, tripPatterns), + null, + null, + null, + null, + null, + null, + null, + null + ); + var runningOnDate = transitLayer.getTripPatternsRunningOnDateCopy(date); + assertEquals(1, runningOnDate.size()); + assertEquals(tripPatterns, runningOnDate); + assertFalse(tripPatterns == runningOnDate); + assertEquals(0, transitLayer.getTripPatternsStartingOnDateCopy(date.minusDays(1)).size()); + assertEquals(0, transitLayer.getTripPatternsStartingOnDateCopy(date.plusDays(1)).size()); + } + + @Test + void testGetTripPatternsForDate() { + var date = LocalDate.of(2024, 1, 1); + + var tripPatternForDate = new TripPatternForDate( + TRIP_PATTERN, + List.of(TRIP_TIMES), + List.of(), + date + ); + var tripPatterns = List.of(tripPatternForDate); + var transitLayer = new TransitLayer( + Map.of(date, tripPatterns), + null, + null, + null, + null, + null, + null, + null, + null + ); + var runningOnDate = transitLayer.getTripPatternsForDate(date); + assertEquals(1, runningOnDate.size()); + assertEquals(tripPatterns, runningOnDate); + assertTrue(tripPatterns == runningOnDate); + assertEquals(0, transitLayer.getTripPatternsStartingOnDateCopy(date.minusDays(1)).size()); + assertEquals(0, transitLayer.getTripPatternsStartingOnDateCopy(date.plusDays(1)).size()); + } + + @Test + void testGetTripPatternsStartingOnDateCopyWithSameRunningAndServiceDate() { + var date = LocalDate.of(2024, 1, 1); + + var tripPatternForDate = new TripPatternForDate( + TRIP_PATTERN, + List.of(TRIP_TIMES), + List.of(), + date + ); + var transitLayer = new TransitLayer( + Map.of(date, List.of(tripPatternForDate)), + null, + null, + null, + null, + null, + null, + null, + null + ); + var startingOnDate = transitLayer.getTripPatternsStartingOnDateCopy(date); + assertEquals(1, startingOnDate.size()); + assertEquals(tripPatternForDate, startingOnDate.getFirst()); + assertEquals(0, transitLayer.getTripPatternsStartingOnDateCopy(date.minusDays(1)).size()); + assertEquals(0, transitLayer.getTripPatternsStartingOnDateCopy(date.plusDays(1)).size()); + } + + @Test + void testGetTripPatternsStartingOnDateCopyWithServiceRunningAfterMidnight() { + var runningDate = LocalDate.of(2024, 1, 1); + var serviceDate = runningDate.minusDays(1); + + var tripPatternForDate = new TripPatternForDate( + TRIP_PATTERN, + List.of(TRIP_TIMES), + List.of(), + serviceDate + ); + var transitLayer = new TransitLayer( + Map.of(runningDate, List.of(tripPatternForDate)), + null, + null, + null, + null, + null, + null, + null, + null + ); + var startingOnDate = transitLayer.getTripPatternsStartingOnDateCopy(serviceDate); + // starting date should be determined by service date, not running date which refers to the + // normal calendar date that the trip pattern is running on + assertEquals(1, startingOnDate.size()); + assertEquals(tripPatternForDate, startingOnDate.getFirst()); + assertEquals(0, transitLayer.getTripPatternsStartingOnDateCopy(runningDate).size()); + } + + @Test + void testGetTripPatternsStartingOnDateCopyWithServiceRunningBeforeAndAfterMidnight() { + // This is same as the service date + var firstRunningDate = LocalDate.of(2024, 1, 1); + var secondRunningDate = firstRunningDate.plusDays(1); + + var tripPatternForDate = new TripPatternForDate( + TRIP_PATTERN, + List.of(TRIP_TIMES), + List.of(), + firstRunningDate + ); + var transitLayer = new TransitLayer( + Map.ofEntries( + entry(firstRunningDate, List.of(tripPatternForDate)), + entry(secondRunningDate, List.of(tripPatternForDate)) + ), + null, + null, + null, + null, + null, + null, + null, + null + ); + var startingOnDate = transitLayer.getTripPatternsStartingOnDateCopy(firstRunningDate); + // Transit layer indexes trip patterns by running date and to get trip patterns for certain + // service date, we need to look up the trip patterns for the next running date as well, but + // we don't want to return duplicates + assertEquals(1, startingOnDate.size()); + assertEquals(tripPatternForDate, startingOnDate.getFirst()); + assertEquals(0, transitLayer.getTripPatternsStartingOnDateCopy(secondRunningDate).size()); + } +} From a3d0e67ced2b8d3be6c6c8e9f98b8bf6f2a7b1ab Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Wed, 20 Mar 2024 22:51:39 +0200 Subject: [PATCH 013/121] Rename methods/fields and add docs --- .../raptoradapter/transit/TransitLayer.java | 30 +++++++++--- .../transit/TripPatternForDate.java | 49 ++++++++++++------- .../frequency/TripFrequencyAlightSearch.java | 2 +- .../frequency/TripFrequencyBoardSearch.java | 2 +- .../transit/mappers/TransitLayerUpdater.java | 6 +-- ...aptorRoutingRequestTransitDataCreator.java | 6 ++- .../request/TripScheduleWithOffset.java | 2 +- .../transit/TransitLayerTest.java | 32 ++++++------ .../support/AssertSpeedTestSetup.java | 2 +- 9 files changed, 83 insertions(+), 48 deletions(-) diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayer.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayer.java index 461c15e8f66..288f429a861 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayer.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayer.java @@ -22,6 +22,8 @@ public class TransitLayer { /** * Transit data required for routing, indexed by each local date(Graph TimeZone) it runs through. * A Trip "runs through" a date if any of its arrivals or departures is happening on that date. + * The same trip pattern can therefore have multiple running dates and trip pattern is not + * required to "run" on its service date. */ private final HashMap> tripPatternsRunningOnDate; @@ -94,7 +96,12 @@ public StopLocation getStopByIndex(int stop) { return stop == -1 ? null : this.stopModel.stopByIndex(stop); } - public Collection getTripPatternsForDate(LocalDate date) { + /** + * Returns trip patterns for the given running date. Running date is not necessarily the same + * as the service date. A Trip "runs through" a date if any of its arrivals or departures is + * happening on that date. Trip pattern can have multiple running dates. + */ + public Collection getTripPatternsForRunningDate(LocalDate date) { return tripPatternsRunningOnDate.getOrDefault(date, List.of()); } @@ -112,17 +119,28 @@ public int getStopCount() { return stopModel.stopIndexSize(); } + /** + * Returns a copy of the list of trip patterns for the given running date. Running date is not + * necessarily the same as the service date. A Trip "runs through" a date if any of its arrivals + * or departures is happening on that date. Trip pattern can have multiple running dates. + */ public List getTripPatternsRunningOnDateCopy(LocalDate runningPeriodDate) { List tripPatternForDate = tripPatternsRunningOnDate.get(runningPeriodDate); return tripPatternForDate != null ? new ArrayList<>(tripPatternForDate) : new ArrayList<>(); } - public List getTripPatternsStartingOnDateCopy(LocalDate date) { - List tripPatternsRunningOnDate = getTripPatternsRunningOnDateCopy(date); - tripPatternsRunningOnDate.addAll(getTripPatternsRunningOnDateCopy(date.plusDays(1))); - return tripPatternsRunningOnDate + /** + * Returns a copy of the list of trip patterns for the given service date. Service date is not + * necessarily the same as any of the trip pattern's running dates. + */ + public List getTripPatternsOnServiceDateCopy(LocalDate date) { + List tripPatternsRunningOnDates = getTripPatternsRunningOnDateCopy(date); + // Trip pattern can run only after midnight. Therefore, we need to get the trip pattern's for + // the next running date as well and filter out duplicates. + tripPatternsRunningOnDates.addAll(getTripPatternsRunningOnDateCopy(date.plusDays(1))); + return tripPatternsRunningOnDates .stream() - .filter(t -> t.getLocalDate().equals(date)) + .filter(t -> t.getServiceDate().equals(date)) .distinct() .collect(Collectors.toList()); } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TripPatternForDate.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TripPatternForDate.java index b86314aa42c..1411424dfc6 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TripPatternForDate.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TripPatternForDate.java @@ -43,16 +43,16 @@ public class TripPatternForDate implements Comparable { */ private final FrequencyEntry[] frequencies; - /** The date for which the filtering was performed. */ - private final LocalDate localDate; + /** The service date of the trip pattern. */ + private final LocalDate serviceDate; /** - * The date on which the first trip departs. + * The running date on which the first trip departs. Not necessarily the same as the service date. */ private final LocalDate startOfRunningPeriod; /** - * The date on which the last trip arrives. + * The running date on which the last trip arrives. */ private final LocalDate endOfRunningPeriod; @@ -60,19 +60,19 @@ public TripPatternForDate( RoutingTripPattern tripPattern, List tripTimes, List frequencies, - LocalDate localDate + LocalDate serviceDate ) { this.tripPattern = tripPattern; this.tripTimes = tripTimes.toArray(new TripTimes[0]); this.frequencies = frequencies.toArray(new FrequencyEntry[0]); - this.localDate = localDate; + this.serviceDate = serviceDate; // TODO: We expect a pattern only containing trips or frequencies, fix ability to merge if (hasFrequencies()) { this.startOfRunningPeriod = ServiceDateUtils .asDateTime( - localDate, + serviceDate, frequencies .stream() .mapToInt(frequencyEntry -> frequencyEntry.startTime) @@ -84,7 +84,7 @@ public TripPatternForDate( this.endOfRunningPeriod = ServiceDateUtils .asDateTime( - localDate, + serviceDate, frequencies .stream() .mapToInt(frequencyEntry -> frequencyEntry.endTime) @@ -96,11 +96,11 @@ public TripPatternForDate( // These depend on the tripTimes array being sorted var first = tripTimes.get(0); this.startOfRunningPeriod = - ServiceDateUtils.asDateTime(localDate, first.getDepartureTime(0)).toLocalDate(); + ServiceDateUtils.asDateTime(serviceDate, first.getDepartureTime(0)).toLocalDate(); var last = tripTimes.get(tripTimes.size() - 1); this.endOfRunningPeriod = ServiceDateUtils - .asDateTime(localDate, last.getArrivalTime(last.getNumStops() - 1)) + .asDateTime(serviceDate, last.getArrivalTime(last.getNumStops() - 1)) .toLocalDate(); assertValidRunningPeriod(startOfRunningPeriod, endOfRunningPeriod, first, last); } @@ -126,18 +126,31 @@ public TripTimes getTripTimes(int i) { return tripTimes[i]; } - public LocalDate getLocalDate() { - return localDate; + /** + * The service date for which the trip pattern belongs to. Not necessarily the same as the start + * of the running period in cases where the trip pattern only runs after midnight. + */ + public LocalDate getServiceDate() { + return serviceDate; } public int numberOfTripSchedules() { return tripTimes.length; } + /** + * The start of the running period. This is determined by the first departure time for this + * pattern. Not necessarily the same as the service date if the pattern runs after midnight. + */ public LocalDate getStartOfRunningPeriod() { return startOfRunningPeriod; } + /** + * Returns the running dates. A Trip "runs through" a date if any of its arrivals or departures is + * happening on that date. The same trip pattern can therefore have multiple running dates and + * trip pattern is not required to "run" on its service date. + */ public List getRunningPeriodDates() { // Add one day to ensure last day is included return startOfRunningPeriod @@ -151,14 +164,14 @@ public boolean hasFrequencies() { @Override public int compareTo(TripPatternForDate other) { - return localDate.compareTo(other.localDate); + return serviceDate.compareTo(other.serviceDate); } @Override public int hashCode() { return Objects.hash( tripPattern, - localDate, + serviceDate, Arrays.hashCode(tripTimes), Arrays.hashCode(frequencies) ); @@ -176,7 +189,7 @@ public boolean equals(Object o) { return ( tripPattern.equals(that.tripPattern) && - localDate.equals(that.localDate) && + serviceDate.equals(that.serviceDate) && Arrays.equals(tripTimes, that.tripTimes) && Arrays.equals(frequencies, that.frequencies) ); @@ -184,7 +197,9 @@ public boolean equals(Object o) { @Override public String toString() { - return "TripPatternForDate{" + "tripPattern=" + tripPattern + ", localDate=" + localDate + '}'; + return ( + "TripPatternForDate{" + "tripPattern=" + tripPattern + ", serviceDate=" + serviceDate + '}' + ); } @Nullable @@ -214,7 +229,7 @@ public TripPatternForDate newWithFilteredTripTimes(Predicate filter) return this; } - return new TripPatternForDate(tripPattern, filteredTripTimes, filteredFrequencies, localDate); + return new TripPatternForDate(tripPattern, filteredTripTimes, filteredFrequencies, serviceDate); } private static void assertValidRunningPeriod( diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/TripFrequencyAlightSearch.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/TripFrequencyAlightSearch.java index 451f51b2aa5..2f020e22cf5 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/TripFrequencyAlightSearch.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/TripFrequencyAlightSearch.java @@ -55,7 +55,7 @@ public RaptorBoardOrAlightEvent search( arrivalTime + headway, headway, offset, - pattern.getLocalDate() + pattern.getServiceDate() ); } } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/TripFrequencyBoardSearch.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/TripFrequencyBoardSearch.java index 897ce370a93..ea58e870547 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/TripFrequencyBoardSearch.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/TripFrequencyBoardSearch.java @@ -54,7 +54,7 @@ public RaptorBoardOrAlightEvent search( departureTime - headway, headway, offset, - pattern.getLocalDate() + pattern.getServiceDate() ); } } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/TransitLayerUpdater.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/TransitLayerUpdater.java index bed27497587..fad5de83de0 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/TransitLayerUpdater.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/TransitLayerUpdater.java @@ -96,7 +96,7 @@ public void update( if (!tripPatternsStartingOnDateMapCache.containsKey(date)) { Map map = realtimeTransitLayer - .getTripPatternsStartingOnDateCopy(date) + .getTripPatternsOnServiceDateCopy(date) .stream() .collect(Collectors.toMap(t -> t.getTripPattern().getPattern(), t -> t)); tripPatternsStartingOnDateMapCache.put(date, map); @@ -146,7 +146,7 @@ public void update( } else { LOG.debug( "NEW TripPatternForDate: {} - {}", - newTripPatternForDate.getLocalDate(), + newTripPatternForDate.getServiceDate(), newTripPatternForDate.getTripPattern().debugInfo() ); } @@ -179,7 +179,7 @@ public void update( } for (TripPatternForDate tripPatternForDate : previouslyUsedPatterns) { - if (tripPatternForDate.getLocalDate().equals(date)) { + if (tripPatternForDate.getServiceDate().equals(date)) { TripPattern pattern = tripPatternForDate.getTripPattern().getPattern(); if (!pattern.isCreatedByRealtimeUpdater()) { continue; diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RaptorRoutingRequestTransitDataCreator.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RaptorRoutingRequestTransitDataCreator.java index 863a4ca9ae8..f987e4f7a21 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RaptorRoutingRequestTransitDataCreator.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RaptorRoutingRequestTransitDataCreator.java @@ -120,7 +120,7 @@ static List merge( // Calculate offsets per date int[] offsets = new int[patternsSorted.length]; for (int i = 0; i < patternsSorted.length; i++) { - LocalDate serviceDate = patternsSorted[i].getLocalDate(); + LocalDate serviceDate = patternsSorted[i].getServiceDate(); if (offsetCache.containsKey(serviceDate)) { offsets[i] = offsetCache.get(serviceDate); } else { @@ -185,7 +185,9 @@ private static List filterActiveTripPatterns( filter.tripTimesPredicate(tripTimes, filter.hasSubModeFilters()); Predicate tripTimesWithoutSubmodesPredicate = tripTimes -> filter.tripTimesPredicate(tripTimes, false); - Collection tripPatternsForDate = transitLayer.getTripPatternsForDate(date); + Collection tripPatternsForDate = transitLayer.getTripPatternsForRunningDate( + date + ); List result = new ArrayList<>(tripPatternsForDate.size()); for (TripPatternForDate p : tripPatternsForDate) { if (firstDay || p.getStartOfRunningPeriod().equals(date)) { diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleWithOffset.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleWithOffset.java index 642dbd2d6e5..aca998b24ca 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleWithOffset.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleWithOffset.java @@ -124,7 +124,7 @@ private void findTripTimes() { if (index < numSchedules) { this.tripTimes = tripPatternForDate.getTripTimes(index); - this.serviceDate = tripPatternForDate.getLocalDate(); + this.serviceDate = tripPatternForDate.getServiceDate(); this.secondsOffset = pattern.tripPatternForDateOffsets(i); return; } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayerTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayerTest.java index 9886ab5b9fc..7c674252e6a 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayerTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayerTest.java @@ -72,12 +72,12 @@ void testGetTripPatternsRunningOnDateCopy() { assertEquals(1, runningOnDate.size()); assertEquals(tripPatterns, runningOnDate); assertFalse(tripPatterns == runningOnDate); - assertEquals(0, transitLayer.getTripPatternsStartingOnDateCopy(date.minusDays(1)).size()); - assertEquals(0, transitLayer.getTripPatternsStartingOnDateCopy(date.plusDays(1)).size()); + assertEquals(0, transitLayer.getTripPatternsRunningOnDateCopy(date.minusDays(1)).size()); + assertEquals(0, transitLayer.getTripPatternsRunningOnDateCopy(date.plusDays(1)).size()); } @Test - void testGetTripPatternsForDate() { + void testGetTripPatternsForRunningDate() { var date = LocalDate.of(2024, 1, 1); var tripPatternForDate = new TripPatternForDate( @@ -98,16 +98,16 @@ void testGetTripPatternsForDate() { null, null ); - var runningOnDate = transitLayer.getTripPatternsForDate(date); + var runningOnDate = transitLayer.getTripPatternsForRunningDate(date); assertEquals(1, runningOnDate.size()); assertEquals(tripPatterns, runningOnDate); assertTrue(tripPatterns == runningOnDate); - assertEquals(0, transitLayer.getTripPatternsStartingOnDateCopy(date.minusDays(1)).size()); - assertEquals(0, transitLayer.getTripPatternsStartingOnDateCopy(date.plusDays(1)).size()); + assertEquals(0, transitLayer.getTripPatternsForRunningDate(date.minusDays(1)).size()); + assertEquals(0, transitLayer.getTripPatternsForRunningDate(date.plusDays(1)).size()); } @Test - void testGetTripPatternsStartingOnDateCopyWithSameRunningAndServiceDate() { + void testGetTripPatternsOnServiceDateCopyWithSameRunningAndServiceDate() { var date = LocalDate.of(2024, 1, 1); var tripPatternForDate = new TripPatternForDate( @@ -127,15 +127,15 @@ void testGetTripPatternsStartingOnDateCopyWithSameRunningAndServiceDate() { null, null ); - var startingOnDate = transitLayer.getTripPatternsStartingOnDateCopy(date); + var startingOnDate = transitLayer.getTripPatternsOnServiceDateCopy(date); assertEquals(1, startingOnDate.size()); assertEquals(tripPatternForDate, startingOnDate.getFirst()); - assertEquals(0, transitLayer.getTripPatternsStartingOnDateCopy(date.minusDays(1)).size()); - assertEquals(0, transitLayer.getTripPatternsStartingOnDateCopy(date.plusDays(1)).size()); + assertEquals(0, transitLayer.getTripPatternsOnServiceDateCopy(date.minusDays(1)).size()); + assertEquals(0, transitLayer.getTripPatternsOnServiceDateCopy(date.plusDays(1)).size()); } @Test - void testGetTripPatternsStartingOnDateCopyWithServiceRunningAfterMidnight() { + void testGetTripPatternsOnServiceDateCopyWithServiceRunningAfterMidnight() { var runningDate = LocalDate.of(2024, 1, 1); var serviceDate = runningDate.minusDays(1); @@ -156,16 +156,16 @@ void testGetTripPatternsStartingOnDateCopyWithServiceRunningAfterMidnight() { null, null ); - var startingOnDate = transitLayer.getTripPatternsStartingOnDateCopy(serviceDate); + var startingOnDate = transitLayer.getTripPatternsOnServiceDateCopy(serviceDate); // starting date should be determined by service date, not running date which refers to the // normal calendar date that the trip pattern is running on assertEquals(1, startingOnDate.size()); assertEquals(tripPatternForDate, startingOnDate.getFirst()); - assertEquals(0, transitLayer.getTripPatternsStartingOnDateCopy(runningDate).size()); + assertEquals(0, transitLayer.getTripPatternsOnServiceDateCopy(runningDate).size()); } @Test - void testGetTripPatternsStartingOnDateCopyWithServiceRunningBeforeAndAfterMidnight() { + void testGetTripPatternsOnServiceDateCopyWithServiceRunningBeforeAndAfterMidnight() { // This is same as the service date var firstRunningDate = LocalDate.of(2024, 1, 1); var secondRunningDate = firstRunningDate.plusDays(1); @@ -190,12 +190,12 @@ void testGetTripPatternsStartingOnDateCopyWithServiceRunningBeforeAndAfterMidnig null, null ); - var startingOnDate = transitLayer.getTripPatternsStartingOnDateCopy(firstRunningDate); + var startingOnDate = transitLayer.getTripPatternsOnServiceDateCopy(firstRunningDate); // Transit layer indexes trip patterns by running date and to get trip patterns for certain // service date, we need to look up the trip patterns for the next running date as well, but // we don't want to return duplicates assertEquals(1, startingOnDate.size()); assertEquals(tripPatternForDate, startingOnDate.getFirst()); - assertEquals(0, transitLayer.getTripPatternsStartingOnDateCopy(secondRunningDate).size()); + assertEquals(0, transitLayer.getTripPatternsOnServiceDateCopy(secondRunningDate).size()); } } diff --git a/src/test/java/org/opentripplanner/transit/speed_test/support/AssertSpeedTestSetup.java b/src/test/java/org/opentripplanner/transit/speed_test/support/AssertSpeedTestSetup.java index 031df343a9a..4113d5979b1 100644 --- a/src/test/java/org/opentripplanner/transit/speed_test/support/AssertSpeedTestSetup.java +++ b/src/test/java/org/opentripplanner/transit/speed_test/support/AssertSpeedTestSetup.java @@ -15,7 +15,7 @@ public static void assertTestDateHasData( ) { int numberOfPatternForTestDate = transitModel .getTransitLayer() - .getTripPatternsForDate(config.testDate) + .getTripPatternsForRunningDate(config.testDate) .size(); if (numberOfPatternForTestDate < 10) { From 32eefbcfbeb4c2dda4fb6c5acf340c8ed8bd9cf0 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 25 Mar 2024 10:46:11 +0100 Subject: [PATCH 014/121] Apply suggestions from code review Co-authored-by: Thomas Gran --- docs/Migrating-Configuration.md | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/docs/Migrating-Configuration.md b/docs/Migrating-Configuration.md index ab36ebf4fa0..e78dfa55357 100644 --- a/docs/Migrating-Configuration.md +++ b/docs/Migrating-Configuration.md @@ -16,22 +16,19 @@ to be a configuration error, perhaps because the schema was changed. In such a c consult the [feature](Configuration.md#otp-features), [router](RouterConfiguration.md) or [build configuration documentation](BuildConfiguration.md) to find out what the new schema looks like. -By default, OTP starts up even when unknown configuration parameters have been found. This is there -to support the style deployment where old config parameters remain in the file for a certain migration -period. - -This allows you to roll back the OTP version without the need to roll back the OTP configuration. +By default, OTP starts up even if unknown configuration parameters exists. This supports forward and backwards +migration of config parameters independent if the OTP version. This allow the configuration to follow the lifecycle of the environment and still be able to roll back OTP. Combined with the config parameter substitution it also allows using the same configuration in different environments. Tip! Rolling out the configuration before rolling out a new +version of OTP, ensure you that you are safe and can roll back later. An example: you change the location of the graphs, a critical error occurs afterwards and you need to roll back. Any member of the dev-ops team should then be confident that they can roll back without -risk - even if the environment changed. +risk - even if the environment changed since the last OTP version was rolled out. ### Aborting on invalid configuration If you want OTP to abort the startup when encountering unknown configuration parameters, you can add the flag `--abortOnUnknownConfig` to your regular OTP CLI commands. -This should of course be used wisely as it can also accidentally make your production instances refuse -to start up. -Therefore, we recommend that you use it only in a separate pre-production step, perhaps during graph -build. \ No newline at end of file +This should of course be used wisely as it can also accidentally make your production instances refuse to start up. +For some deployments this is a good solution - especially if the config substitution feature is used to inject +environment specific information. Using this feature in the graph-build phase is less risky, than in the OTP serve phase. \ No newline at end of file From cc4b0d9939a373b1275ca016298c5c752ad8a727 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 25 Mar 2024 10:54:19 +0100 Subject: [PATCH 015/121] Rename tests --- .../framework/json/NodeAdapterTest.java | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java b/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java index 5a1aa2f0063..29969851c29 100644 --- a/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java +++ b/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java @@ -23,7 +23,6 @@ import java.util.Locale; import java.util.Map; import java.util.Set; -import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.opentripplanner._support.time.ZoneIds; import org.opentripplanner.framework.application.OtpAppException; @@ -558,31 +557,27 @@ void unusedParams() { assertEquals("Unexpected config parameter: 'foo.b:false' in 'Test'", buf.toString()); } - @Nested - class Validation { - - @Test - void invalidProperties() { - // Given: two parameters a and b - NodeAdapter subject = newNodeAdapterForTest("{ foo : { a: true, b: false } }"); + @Test + void unknownProperties() { + // Given: two parameters a and b + NodeAdapter subject = newNodeAdapterForTest("{ foo : { a: true, b: false } }"); - // When: Access ONLY parameter 'a', but not 'b' - subject.of("foo").asObject().of("a").asBoolean(); + // When: Access ONLY parameter 'a', but not 'b' + subject.of("foo").asObject().of("a").asBoolean(); - assertTrue(subject.hasUnknownParameters()); - } + assertTrue(subject.hasUnknownParameters()); + } - @Test - void valid() { - // Given: two parameters a and b - NodeAdapter subject = newNodeAdapterForTest("{ foo : { a: true, b: false } }"); + @Test + void allPropertiesAreKnown() { + // Given: two parameters a and b + NodeAdapter subject = newNodeAdapterForTest("{ foo : { a: true, b: false } }"); - var object = subject.of("foo").asObject(); - object.of("a").asBoolean(); - object.of("b").asBoolean(); + var object = subject.of("foo").asObject(); + object.of("a").asBoolean(); + object.of("b").asBoolean(); - assertFalse(subject.hasUnknownParameters()); - } + assertFalse(subject.hasUnknownParameters()); } private static String unusedParams(NodeAdapter subject) { From 86f1a8321a2163e6687363b1423f9a61d107b45a Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 25 Mar 2024 10:55:38 +0100 Subject: [PATCH 016/121] Don't check warnings Co-authored-by: Thomas Gran --- .../standalone/config/framework/json/NodeAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java b/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java index 9523e330eca..51303ea4fc5 100644 --- a/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java +++ b/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeAdapter.java @@ -176,7 +176,7 @@ public void logAllWarnings(Consumer logger) { * Checks if any unknown or invalid properties were encountered while loading the configuration. */ public boolean hasUnknownParameters() { - return !unusedParams().isEmpty() || !allWarnings().toList().isEmpty(); + return !unusedParams().isEmpty(); } /** From 7cf928e96811a24e825e39331ad3e2beffc71cc3 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 25 Mar 2024 10:57:00 +0100 Subject: [PATCH 017/121] Rename from properties to parameters --- .../standalone/config/framework/json/NodeAdapterTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java b/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java index 29969851c29..8128a48a678 100644 --- a/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java +++ b/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java @@ -558,7 +558,7 @@ void unusedParams() { } @Test - void unknownProperties() { + void unknownParameters() { // Given: two parameters a and b NodeAdapter subject = newNodeAdapterForTest("{ foo : { a: true, b: false } }"); @@ -569,7 +569,7 @@ void unknownProperties() { } @Test - void allPropertiesAreKnown() { + void allParametersAreKnown() { // Given: two parameters a and b NodeAdapter subject = newNodeAdapterForTest("{ foo : { a: true, b: false } }"); From fae03b1b0648657c90fa40fec96457ac9e45d192 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 25 Mar 2024 11:02:39 +0100 Subject: [PATCH 018/121] Move exception throwing code into ConfigModel.java --- .../opentripplanner/standalone/OTPMain.java | 7 ++---- .../standalone/config/ConfigModel.java | 22 ++++++++++++++----- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/opentripplanner/standalone/OTPMain.java b/src/main/java/org/opentripplanner/standalone/OTPMain.java index de5ccd7057c..d865f8fa28c 100644 --- a/src/main/java/org/opentripplanner/standalone/OTPMain.java +++ b/src/main/java/org/opentripplanner/standalone/OTPMain.java @@ -180,11 +180,8 @@ private static void startOTPServer(CommandLineParameters cli) { * Optionally, check if the config is valid and if not abort the startup process. */ private static void detectUnusedConfigParams(CommandLineParameters cli, ConfigModel config) { - if (cli.abortOnUnknownConfig && config.hasUnknownParameters()) { - throw new OtpAppException( - "Configuration contains unknown parameters (see above for details). " + - "Please fix your configuration or remove --abortOnUnknownConfig from your OTP CLI parameters." - ); + if (cli.abortOnUnknownConfig) { + config.abortOnUnknownParameters(); } } diff --git a/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java b/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java index 8cffa5002e4..c82dd33ddbf 100644 --- a/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java +++ b/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.node.MissingNode; import org.opentripplanner.framework.application.OTPFeature; +import org.opentripplanner.framework.application.OtpAppException; import org.opentripplanner.framework.application.OtpFileNames; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -108,12 +109,21 @@ public static void initializeOtpFeatures(OtpConfig otpConfig) { /** * Checks if any unknown or invalid parameters were encountered while loading the configuration. + *

+ * If so it throws an exception. */ - public boolean hasUnknownParameters() { - return ( - otpConfig.hasUnknownParameters() || - buildConfig.hasUnknownParameters() || - routerConfig.hasUnknownParameters() - ); + public void abortOnUnknownParameters() { + if ( + ( + otpConfig.hasUnknownParameters() || + buildConfig.hasUnknownParameters() || + routerConfig.hasUnknownParameters() + ) + ) { + throw new OtpAppException( + "Configuration contains unknown parameters (see above for details). " + + "Please fix your configuration or remove --abortOnUnknownConfig from your OTP CLI parameters." + ); + } } } From 70026b92c4a00a98a45cfea6f8ac4ae2dce78b59 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 25 Mar 2024 11:05:34 +0100 Subject: [PATCH 019/121] Improve documentation --- docs/Migrating-Configuration.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/Migrating-Configuration.md b/docs/Migrating-Configuration.md index e78dfa55357..c6f1ee946f6 100644 --- a/docs/Migrating-Configuration.md +++ b/docs/Migrating-Configuration.md @@ -16,8 +16,11 @@ to be a configuration error, perhaps because the schema was changed. In such a c consult the [feature](Configuration.md#otp-features), [router](RouterConfiguration.md) or [build configuration documentation](BuildConfiguration.md) to find out what the new schema looks like. -By default, OTP starts up even if unknown configuration parameters exists. This supports forward and backwards -migration of config parameters independent if the OTP version. This allow the configuration to follow the lifecycle of the environment and still be able to roll back OTP. Combined with the config parameter substitution it also allows using the same configuration in different environments. Tip! Rolling out the configuration before rolling out a new +By default, OTP starts up even if unknown configuration parameters exist. This supports forward and backwards +migration of config parameters independent if the OTP version. This allows the configuration to follow +the lifecycle of the environment and still be able to roll back OTP. +Combined with the config parameter substitution it also allows using the same configuration in +different environments. Tip! Rolling out the configuration before rolling out a new version of OTP, ensure you that you are safe and can roll back later. An example: you change the location of the graphs, a critical error occurs afterwards and you need to From 1023451ccd88c3db2b7a6663ef4c69fa07559984 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 25 Mar 2024 17:03:49 +0100 Subject: [PATCH 020/121] Add NOI OpenDataHub parking updater --- docs/sandbox/VehicleParking.md | 10 +- .../vehicleparking/noi/NoiUpdaterTest.java | 51 ++++++ .../ext/vehicleparking/noi/stations.json | 159 ++++++++++++++++++ .../ext/vehicleparking/noi/NoiUpdater.java | 69 ++++++++ .../noi/NoiUpdaterParameters.java | 25 +++ .../vehicle_parking/VehicleParking.java | 5 +- .../config/framework/json/OtpVersion.java | 3 +- .../updaters/VehicleParkingUpdaterConfig.java | 17 +- .../VehicleParkingDataSourceFactory.java | 3 + .../VehicleParkingSourceType.java | 1 + .../apis/gtfs/GraphQLIntegrationTest.java | 1 + .../module/VehicleParkingLinkingTest.java | 23 ++- .../VehicleParkingHelperTest.java | 9 +- .../VehicleParkingTestUtil.java | 5 +- .../model/_data/StreetModelForTest.java | 5 + .../model/edge/VehicleParkingEdgeTest.java | 5 +- .../edge/VehicleParkingPreferredTagsTest.java | 7 +- .../VehicleParkingUpdaterTest.java | 19 ++- 18 files changed, 376 insertions(+), 41 deletions(-) create mode 100644 src/ext-test/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdaterTest.java create mode 100644 src/ext-test/resources/org/opentripplanner/ext/vehicleparking/noi/stations.json create mode 100644 src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdater.java create mode 100644 src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdaterParameters.java diff --git a/docs/sandbox/VehicleParking.md b/docs/sandbox/VehicleParking.md index 4bfc2f6bd36..8a659446516 100644 --- a/docs/sandbox/VehicleParking.md +++ b/docs/sandbox/VehicleParking.md @@ -60,7 +60,7 @@ This will end up in the API responses as the feed id of of the parking lot. **Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Required` **Path:** /updaters/[2] -**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` +**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub` The source of the vehicle updates. @@ -110,7 +110,7 @@ Used for converting abstract opening hours into concrete points in time. | frequency | `duration` | How often to update the source. | *Optional* | `"PT1M"` | 2.2 | | [sourceType](#u__3__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 | | [timeZone](#u__3__timeZone) | `time-zone` | The time zone of the feed. | *Optional* | | 2.2 | -| url | `string` | URL of the resource. | *Optional* | | 2.2 | +| url | `string` | URL of the resource. | *Required* | | 2.2 | | [headers](#u__3__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.2 | | [tags](#u__3__tags) | `string[]` | Tags to add to the parking lots. | *Optional* | | 2.2 | @@ -130,7 +130,7 @@ This will end up in the API responses as the feed id of of the parking lot. **Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Required` **Path:** /updaters/[3] -**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` +**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub` The source of the vehicle updates. @@ -196,7 +196,7 @@ Tags to add to the parking lots. | [feedId](#u__4__feedId) | `string` | The name of the data source. | *Required* | | 2.2 | | frequency | `duration` | How often to update the source. | *Optional* | `"PT1M"` | 2.3 | | [sourceType](#u__4__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 | -| url | `uri` | URL of the locations endpoint. | *Optional* | | 2.3 | +| url | `uri` | URL of the locations endpoint. | *Required* | | 2.3 | | [headers](#u__4__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 | @@ -215,7 +215,7 @@ This will end up in the API responses as the feed id of of the parking lot. **Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Required` **Path:** /updaters/[4] -**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` +**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub` The source of the vehicle updates. diff --git a/src/ext-test/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdaterTest.java b/src/ext-test/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdaterTest.java new file mode 100644 index 00000000000..f931e3d964e --- /dev/null +++ b/src/ext-test/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdaterTest.java @@ -0,0 +1,51 @@ +package org.opentripplanner.ext.vehicleparking.noi; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.time.Duration; +import org.junit.jupiter.api.Test; +import org.opentripplanner.test.support.ResourceLoader; +import org.opentripplanner.updater.spi.HttpHeaders; + +class NoiUpdaterTest { + + @Test + void parse() { + var uri = ResourceLoader.of(this).uri("stations.json"); + var parameters = new NoiUpdaterParameters( + "noi", + uri, + "noi", + Duration.ofSeconds(30), + HttpHeaders.empty() + ); + var updater = new NoiUpdater(parameters); + updater.update(); + var lots = updater.getUpdates(); + + assertEquals(14, lots.size()); + + lots.forEach(l -> assertNotNull(l.getName())); + + var first = lots.getFirst(); + assertEquals("noi:105", first.getId().toString()); + assertEquals("(46.49817, 11.35726)", first.getCoordinate().toString()); + assertEquals("P05 - Laurin", first.getName().toString()); + assertEquals(57, first.getAvailability().getCarSpaces()); + assertEquals(90, first.getCapacity().getCarSpaces()); + + var last = lots.getLast(); + assertEquals( + "noi:935af00d-aa5f-eb11-9889-501ac5928d31-0.8458736393052522", + last.getId().toString() + ); + assertEquals("(46.5057, 11.3395)", last.getCoordinate().toString()); + assertEquals( + "Parksensoren Bozen - PNI Parksensor Nr.10 Commissariato - Viale Eugenio di savoia", + last.getName().toString() + ); + assertEquals(0, last.getAvailability().getCarSpaces()); + assertEquals(1, last.getCapacity().getCarSpaces()); + } +} diff --git a/src/ext-test/resources/org/opentripplanner/ext/vehicleparking/noi/stations.json b/src/ext-test/resources/org/opentripplanner/ext/vehicleparking/noi/stations.json new file mode 100644 index 00000000000..2bbb07ac98b --- /dev/null +++ b/src/ext-test/resources/org/opentripplanner/ext/vehicleparking/noi/stations.json @@ -0,0 +1,159 @@ +{ + "last_updated": 1711368767, + "ttl": 0, + "version": "3.0.0", + "data": { + "stations": [ + { + "type": "station", + "station_id": "105", + "name": "P05 - Laurin", + "lat": 46.498174, + "lon": 11.357255, + "city": "Bolzano - Bozen", + "capacity": 90, + "free": 57 + }, + { + "type": "station", + "station_id": "TRENTO:areaexsitviacanestrinip1", + "name": "Area ex SIT via Canestrini - P1", + "lat": 46.0691, + "lon": 11.1162, + "address": "Lung'Adige Monte Grappa", + "city": "Trento", + "capacity": 300, + "free": 0 + }, + { + "type": "station", + "station_id": "ROVERETO:asm", + "name": "A.S.M.", + "lat": 45.893593, + "lon": 11.036507, + "address": "Piazzale ex-A.S.M - Via Manzoni - Rovereto", + "city": "Rovereto", + "capacity": 145, + "free": 42 + }, + { + "type": "station", + "station_id": "ROVERETO:centrostorico", + "name": "Centro Storico", + "lat": 45.890306, + "lon": 11.045004, + "address": "Viale dei Colli - Rovereto", + "city": "Rovereto", + "capacity": 143, + "free": 20 + }, + { + "type": "station", + "station_id": "ROVERETO:mart", + "name": "Mart", + "lat": 45.894705, + "lon": 11.044661, + "address": "Mart - Via Sticcotta - Rovereto", + "city": "Rovereto", + "capacity": 224, + "free": 224 + }, + { + "type": "sensor", + "station_id": "001bc50670100557-0.30188412882192206", + "group_name": "area viale Druso", + "group_id": "area_viale_druso", + "name": "piazzetta Mazzoni 3", + "lat": 46.495025, + "lon": 11.347069, + "address": "area viale Druso", + "city": "Bolzano - Bozen", + "free": false + }, + { + "type": "sensor", + "station_id": "001bc50670100541-0.9632040952321754", + "group_name": "Via A. Rosmini 22-26", + "group_id": "via_a_rosmini_22_26", + "name": "Via A. Rosmini 22-26", + "lat": 46.498292, + "lon": 11.348031, + "address": "Via A. Rosmini 22-26", + "city": "Bolzano - Bozen", + "free": false + }, + { + "type": "sensor", + "station_id": "001bc50670112a6b-0.6239539554369709", + "group_name": "Via Amalfi", + "group_id": "via_amalfi", + "name": "Via Amalfi angolo Via Druso", + "lat": 46.495283, + "lon": 11.332472, + "address": "Via Amalfi", + "city": "Bolzano - Bozen", + "free": false + }, + { + "type": "sensor", + "station_id": "001bc5067010064d-0.18879954213280836", + "group_name": "area viale Druso", + "group_id": "area_viale_druso", + "name": "piazzetta Mazzoni 4", + "lat": 46.495056, + "lon": 11.347056, + "address": "area viale Druso", + "city": "Bolzano - Bozen", + "free": false + }, + { + "type": "sensor", + "station_id": "001bc50670112976-0.4989211141789258", + "group_name": "Viale Druso 237", + "group_id": "viale_druso_237", + "name": "Viale Druso 237", + "lat": 46.495, + "lon": 11.328703, + "address": "Viale Druso 237", + "city": "Bolzano - Bozen", + "free": true + }, + { + "type": "sensor", + "station_id": "9398a35b-ef3d-eb11-b9ed-0050f244b601-0.12775006754129703", + "group_id": "", + "name": "Parksensoren Bozen - PNI Parksensor Nr.3 Siegesplatz Parkplatz", + "lat": 46.501, + "lon": 11.3431, + "free": true + }, + { + "type": "sensor", + "station_id": "7776d25f-f03d-eb11-b9ed-0050f244b601-0.4355636862513992", + "group_id": "", + "name": "Parksensoren Bozen - PNI Parksensor Nr.5 DucaDaostastrasse", + "lat": 46.4953, + "lon": 11.3396, + "free": false + }, + { + "type": "sensor", + "station_id": "e3e26add-ee3d-eb11-b9ed-0050f244b601-0.8423578257530036", + "group_id": "", + "name": "Parksensoren Bozen - PNI Parksensor Nr.4 Bahnhof BZ Richtung Rittnerseilbahn", + "lat": 46.497, + "lon": 11.3583, + "free": false + }, + { + "type": "sensor", + "station_id": "935af00d-aa5f-eb11-9889-501ac5928d31-0.8458736393052522", + "group_id": "", + "name": "Parksensoren Bozen - PNI Parksensor Nr.10 Commissariato - Viale Eugenio di savoia", + "lat": 46.5057, + "lon": 11.3395, + "free": false + } + ] + } +} \ No newline at end of file diff --git a/src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdater.java b/src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdater.java new file mode 100644 index 00000000000..9bd64d9612f --- /dev/null +++ b/src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdater.java @@ -0,0 +1,69 @@ +package org.opentripplanner.ext.vehicleparking.noi; + +import com.fasterxml.jackson.databind.JsonNode; +import org.opentripplanner.framework.geometry.WgsCoordinate; +import org.opentripplanner.framework.i18n.NonLocalizedString; +import org.opentripplanner.routing.vehicle_parking.VehicleParking; +import org.opentripplanner.routing.vehicle_parking.VehicleParkingSpaces; +import org.opentripplanner.routing.vehicle_parking.VehicleParkingState; +import org.opentripplanner.transit.model.framework.FeedScopedId; +import org.opentripplanner.updater.spi.GenericJsonDataSource; + +/** + * Vehicle parking updater class for NOI's open data hub format APIs. + */ +public class NoiUpdater extends GenericJsonDataSource { + + private static final String JSON_PARSE_PATH = "data/stations"; + + private final String feedId; + + public NoiUpdater(NoiUpdaterParameters parameters) { + super(parameters.url().toString(), JSON_PARSE_PATH, parameters.httpHeaders()); + this.feedId = parameters.feedId(); + } + + @Override + protected VehicleParking parseElement(JsonNode jsonNode) { + var type = jsonNode.path("type").textValue(); + VehicleParkingSpaces capacity, availability; + if (type.equals("station")) { + capacity = extractSpaces(jsonNode, "capacity"); + availability = extractSpaces(jsonNode, "free"); + } else if (type.equals("sensor")) { + capacity = VehicleParkingSpaces.builder().carSpaces(1).build(); + var isFree = jsonNode.path("free").asBoolean(); + availability = VehicleParkingSpaces.builder().carSpaces(isFree ? 1 : 0).build(); + } else { + throw new IllegalArgumentException("Unknown type '%s'".formatted(type)); + } + + var vehicleParkId = new FeedScopedId(feedId, jsonNode.path("station_id").asText()); + var name = new NonLocalizedString(jsonNode.path("name").asText()); + double lat = jsonNode.path("lat").asDouble(); + double lon = jsonNode.path("lon").asDouble(); + var coordinate = new WgsCoordinate(lat, lon); + VehicleParking.VehicleParkingEntranceCreator entrance = builder -> + builder + .entranceId(new FeedScopedId(feedId, vehicleParkId.getId() + "/entrance")) + .coordinate(coordinate) + .walkAccessible(true) + .carAccessible(true); + + return VehicleParking + .builder() + .id(vehicleParkId) + .name(name) + .state(VehicleParkingState.OPERATIONAL) + .coordinate(coordinate) + .capacity(capacity) + .availability(availability) + .carPlaces(true) + .entrance(entrance) + .build(); + } + + private static VehicleParkingSpaces extractSpaces(JsonNode jsonNode, String free) { + return VehicleParkingSpaces.builder().carSpaces(jsonNode.get(free).asInt()).build(); + } +} diff --git a/src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdaterParameters.java b/src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdaterParameters.java new file mode 100644 index 00000000000..371ffdc9f33 --- /dev/null +++ b/src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdaterParameters.java @@ -0,0 +1,25 @@ +package org.opentripplanner.ext.vehicleparking.noi; + +import java.net.URI; +import java.time.Duration; +import org.opentripplanner.updater.spi.HttpHeaders; +import org.opentripplanner.updater.vehicle_parking.VehicleParkingSourceType; +import org.opentripplanner.updater.vehicle_parking.VehicleParkingUpdaterParameters; + +/** + * Class that extends {@link VehicleParkingUpdaterParameters} with parameters required by {@link + * NoiUpdater}. + */ +public record NoiUpdaterParameters( + String configRef, + URI url, + String feedId, + Duration frequency, + HttpHeaders httpHeaders +) + implements VehicleParkingUpdaterParameters { + @Override + public VehicleParkingSourceType sourceType() { + return VehicleParkingSourceType.NOI_OPEN_DATA_HUB; + } +} diff --git a/src/main/java/org/opentripplanner/routing/vehicle_parking/VehicleParking.java b/src/main/java/org/opentripplanner/routing/vehicle_parking/VehicleParking.java index e5b0fd083dc..6ebd34e1287 100644 --- a/src/main/java/org/opentripplanner/routing/vehicle_parking/VehicleParking.java +++ b/src/main/java/org/opentripplanner/routing/vehicle_parking/VehicleParking.java @@ -120,9 +120,10 @@ public class VehicleParking implements Serializable { VehicleParkingSpaces availability, VehicleParkingGroup vehicleParkingGroup ) { - this.id = id; + this.id = + Objects.requireNonNull(id, "%s must have an ID".formatted(this.getClass().getSimpleName())); this.name = name; - this.coordinate = coordinate; + this.coordinate = Objects.requireNonNull(coordinate); this.detailsUrl = detailsUrl; this.imageUrl = imageUrl; this.tags = tags; diff --git a/src/main/java/org/opentripplanner/standalone/config/framework/json/OtpVersion.java b/src/main/java/org/opentripplanner/standalone/config/framework/json/OtpVersion.java index 6caf9082cff..70b8e261ee4 100644 --- a/src/main/java/org/opentripplanner/standalone/config/framework/json/OtpVersion.java +++ b/src/main/java/org/opentripplanner/standalone/config/framework/json/OtpVersion.java @@ -10,7 +10,8 @@ public enum OtpVersion { V2_2("2.2"), V2_3("2.3"), V2_4("2.4"), - V2_5("2.5"); + V2_5("2.5"), + V2_6("2.6"); private final String text; diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/VehicleParkingUpdaterConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/VehicleParkingUpdaterConfig.java index e808ad6905c..f0306941547 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/VehicleParkingUpdaterConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/VehicleParkingUpdaterConfig.java @@ -2,6 +2,7 @@ import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_2; import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_3; +import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_6; import java.time.Duration; import java.time.ZoneId; @@ -9,6 +10,7 @@ import java.util.Set; import org.opentripplanner.ext.vehicleparking.bikely.BikelyUpdaterParameters; import org.opentripplanner.ext.vehicleparking.hslpark.HslParkUpdaterParameters; +import org.opentripplanner.ext.vehicleparking.noi.NoiUpdaterParameters; import org.opentripplanner.ext.vehicleparking.parkapi.ParkAPIUpdaterParameters; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; import org.opentripplanner.updater.vehicle_parking.VehicleParkingSourceType; @@ -50,7 +52,7 @@ public static VehicleParkingUpdaterParameters create(String updaterRef, NodeAdap ); case PARK_API, BICYCLE_PARK_API -> new ParkAPIUpdaterParameters( updaterRef, - c.of("url").since(V2_2).summary("URL of the resource.").asString(null), + c.of("url").since(V2_2).summary("URL of the resource.").asString(), feedId, c .of("frequency") @@ -66,7 +68,7 @@ public static VehicleParkingUpdaterParameters create(String updaterRef, NodeAdap ); case BIKELY -> new BikelyUpdaterParameters( updaterRef, - c.of("url").since(V2_3).summary("URL of the locations endpoint.").asUri(null), + c.of("url").since(V2_3).summary("URL of the locations endpoint.").asUri(), feedId, c .of("frequency") @@ -75,6 +77,17 @@ public static VehicleParkingUpdaterParameters create(String updaterRef, NodeAdap .asDuration(Duration.ofMinutes(1)), HttpHeadersConfig.headers(c, V2_3) ); + case NOI_OPEN_DATA_HUB -> new NoiUpdaterParameters( + updaterRef, + c.of("url").since(V2_6).summary("URL of the locations endpoint.").asUri(), + feedId, + c + .of("frequency") + .since(V2_6) + .summary("How often to update the source.") + .asDuration(Duration.ofMinutes(1)), + HttpHeadersConfig.headers(c, V2_6) + ); }; } diff --git a/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingDataSourceFactory.java b/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingDataSourceFactory.java index e0214fd9d57..3fe465a8cd5 100644 --- a/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingDataSourceFactory.java +++ b/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingDataSourceFactory.java @@ -4,6 +4,8 @@ import org.opentripplanner.ext.vehicleparking.bikely.BikelyUpdaterParameters; import org.opentripplanner.ext.vehicleparking.hslpark.HslParkUpdater; import org.opentripplanner.ext.vehicleparking.hslpark.HslParkUpdaterParameters; +import org.opentripplanner.ext.vehicleparking.noi.NoiUpdater; +import org.opentripplanner.ext.vehicleparking.noi.NoiUpdaterParameters; import org.opentripplanner.ext.vehicleparking.parkapi.BicycleParkAPIUpdater; import org.opentripplanner.ext.vehicleparking.parkapi.CarParkAPIUpdater; import org.opentripplanner.ext.vehicleparking.parkapi.ParkAPIUpdaterParameters; @@ -36,6 +38,7 @@ public static DataSource create( openingHoursCalendarService ); case BIKELY -> new BikelyUpdater((BikelyUpdaterParameters) parameters); + case NOI_OPEN_DATA_HUB -> new NoiUpdater((NoiUpdaterParameters) parameters); }; } } diff --git a/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingSourceType.java b/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingSourceType.java index 583bc9afc99..3a0cb7d31b3 100644 --- a/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingSourceType.java +++ b/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingSourceType.java @@ -5,4 +5,5 @@ public enum VehicleParkingSourceType { BICYCLE_PARK_API, HSL_PARK, BIKELY, + NOI_OPEN_DATA_HUB, } diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java index f630e0cee3c..e9121a3248d 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java @@ -130,6 +130,7 @@ static void setup() { VehicleParking .builder() .id(id("parking-1")) + .coordinate(WgsCoordinate.GREENWICH) .name(NonLocalizedString.ofNullable("parking")) .build() ), diff --git a/src/test/java/org/opentripplanner/graph_builder/module/VehicleParkingLinkingTest.java b/src/test/java/org/opentripplanner/graph_builder/module/VehicleParkingLinkingTest.java index 95f4df79b7b..23f4ffc72ca 100644 --- a/src/test/java/org/opentripplanner/graph_builder/module/VehicleParkingLinkingTest.java +++ b/src/test/java/org/opentripplanner/graph_builder/module/VehicleParkingLinkingTest.java @@ -9,7 +9,6 @@ import org.junit.jupiter.api.Test; import org.opentripplanner.framework.geometry.WgsCoordinate; import org.opentripplanner.routing.graph.Graph; -import org.opentripplanner.routing.vehicle_parking.VehicleParking; import org.opentripplanner.routing.vehicle_parking.VehicleParkingHelper; import org.opentripplanner.routing.vehicle_parking.VehicleParkingTestGraphData; import org.opentripplanner.street.model.StreetTraversalPermission; @@ -46,8 +45,8 @@ public void setup() { @Test public void entranceWithVertexLinkingTest() { - var parking = VehicleParking - .builder() + var parking = StreetModelForTest + .vehicleParking() .entrance(builder -> builder.entranceId(id("1")).coordinate(new WgsCoordinate(A.getCoordinate())).vertex(A) ) @@ -65,8 +64,8 @@ public void entranceWithVertexLinkingTest() { @Test public void entranceWithoutVertexLinkingTest() { - var parking = VehicleParking - .builder() + var parking = StreetModelForTest + .vehicleParking() .entrance(builder -> builder .entranceId(id("1")) @@ -99,8 +98,8 @@ public void carParkingEntranceToAllTraversableStreetLinkingTest() { StreetModelForTest.streetEdge(A, C, StreetTraversalPermission.NONE); - var parking = VehicleParking - .builder() + var parking = StreetModelForTest + .vehicleParking() .entrance(builder -> builder .entranceId(id("1")) @@ -123,9 +122,8 @@ public void carParkingEntranceToAllTraversableStreetLinkingTest() { @Test public void removeEntranceWithNonExistingVertexTest() { - var vehicleParking = VehicleParking - .builder() - .id(id("VP")) + var vehicleParking = StreetModelForTest + .vehicleParking() .bicyclePlaces(true) .entrance(builder -> builder @@ -159,9 +157,8 @@ public void removeEntranceWithNonExistingVertexTest() { @Test public void removeVehicleParkingWithOneEntranceAndNonExistingVertexTest() { - var vehicleParking = VehicleParking - .builder() - .id(id("VP")) + var vehicleParking = StreetModelForTest + .vehicleParking() .bicyclePlaces(true) .entrance(builder -> builder diff --git a/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingHelperTest.java b/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingHelperTest.java index 9c80cb9cda9..90bdeb015a4 100644 --- a/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingHelperTest.java +++ b/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingHelperTest.java @@ -10,6 +10,7 @@ import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.vehicle_parking.VehicleParking.VehicleParkingEntranceCreator; +import org.opentripplanner.street.model._data.StreetModelForTest; import org.opentripplanner.street.model.edge.VehicleParkingEdge; import org.opentripplanner.street.model.vertex.VehicleParkingEntranceVertex; import org.opentripplanner.transit.model.framework.FeedScopedId; @@ -41,8 +42,8 @@ void linkThreeVerticesTest() { @Test void linkSkippingEdgesTest() { Graph graph = new Graph(); - var vehicleParking = VehicleParking - .builder() + var vehicleParking = StreetModelForTest + .vehicleParking() .entrances( IntStream .rangeClosed(1, 3) @@ -67,8 +68,8 @@ void linkSkippingEdgesTest() { } private VehicleParking createParingWithEntrances(int entranceNumber) { - return VehicleParking - .builder() + return StreetModelForTest + .vehicleParking() .bicyclePlaces(true) .entrances( IntStream diff --git a/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingTestUtil.java b/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingTestUtil.java index 078d7350dcc..fca20322ebe 100644 --- a/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingTestUtil.java +++ b/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingTestUtil.java @@ -2,6 +2,7 @@ import org.opentripplanner.framework.geometry.WgsCoordinate; import org.opentripplanner.framework.i18n.NonLocalizedString; +import org.opentripplanner.street.model._data.StreetModelForTest; import org.opentripplanner.transit.model.framework.FeedScopedId; public class VehicleParkingTestUtil { @@ -25,8 +26,8 @@ public static VehicleParking createParkingWithEntrances( .coordinate(new WgsCoordinate(y, x)) .walkAccessible(true); - return VehicleParking - .builder() + return StreetModelForTest + .vehicleParking() .id(new FeedScopedId(TEST_FEED_ID, id)) .bicyclePlaces(true) .capacity(vehiclePlaces) diff --git a/src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java b/src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java index d50c8a74dfc..141331e80cd 100644 --- a/src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java +++ b/src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java @@ -9,6 +9,7 @@ import org.opentripplanner.framework.geometry.SphericalDistanceLibrary; import org.opentripplanner.framework.geometry.WgsCoordinate; import org.opentripplanner.framework.i18n.I18NString; +import org.opentripplanner.routing.vehicle_parking.VehicleParking; import org.opentripplanner.service.vehiclerental.model.TestFreeFloatingRentalVehicleBuilder; import org.opentripplanner.service.vehiclerental.street.VehicleRentalPlaceVertex; import org.opentripplanner.street.model.RentalFormFactor; @@ -111,4 +112,8 @@ public static VehicleRentalPlaceVertex rentalVertex(RentalFormFactor formFactor) } return new VehicleRentalPlaceVertex(rentalVehicleBuilder.build()); } + + public static VehicleParking.VehicleParkingBuilder vehicleParking() { + return VehicleParking.builder().id(id("vehicle-parking-1")).coordinate(WgsCoordinate.GREENWICH); + } } diff --git a/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingEdgeTest.java b/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingEdgeTest.java index 7dad61fbd6b..81bee23ad54 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingEdgeTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingEdgeTest.java @@ -10,6 +10,7 @@ import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.routing.vehicle_parking.VehicleParking; import org.opentripplanner.routing.vehicle_parking.VehicleParkingSpaces; +import org.opentripplanner.street.model._data.StreetModelForTest; import org.opentripplanner.street.model.vertex.VehicleParkingEntranceVertex; import org.opentripplanner.street.search.request.StreetSearchRequest; import org.opentripplanner.street.search.state.State; @@ -130,8 +131,8 @@ private VehicleParking createVehicleParking( boolean carPlaces, VehicleParkingSpaces availability ) { - return VehicleParking - .builder() + return StreetModelForTest + .vehicleParking() .id(TransitModelForTest.id("VehicleParking")) .bicyclePlaces(bicyclePlaces) .carPlaces(carPlaces) diff --git a/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingPreferredTagsTest.java b/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingPreferredTagsTest.java index 5969121b6d6..579ae4e964d 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingPreferredTagsTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingPreferredTagsTest.java @@ -11,9 +11,9 @@ import org.opentripplanner.framework.geometry.WgsCoordinate; import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.routing.api.request.StreetMode; -import org.opentripplanner.routing.vehicle_parking.VehicleParking; import org.opentripplanner.routing.vehicle_parking.VehicleParkingEntrance; import org.opentripplanner.routing.vehicle_parking.VehicleParkingSpaces; +import org.opentripplanner.street.model._data.StreetModelForTest; import org.opentripplanner.street.model.vertex.VehicleParkingEntranceVertex; import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.search.request.StreetSearchRequest; @@ -62,9 +62,8 @@ private void runTest( double expectedCost, boolean arriveBy ) { - var parking = VehicleParking - .builder() - .coordinate(COORDINATE) + var parking = StreetModelForTest + .vehicleParking() .tags(parkingTags) .availability(VehicleParkingSpaces.builder().bicycleSpaces(100).build()) .bicyclePlaces(true) diff --git a/src/test/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdaterTest.java b/src/test/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdaterTest.java index 2bcb49defae..a31b5cfb387 100644 --- a/src/test/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdaterTest.java +++ b/src/test/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdaterTest.java @@ -16,6 +16,7 @@ import org.opentripplanner.routing.vehicle_parking.VehicleParkingState; import org.opentripplanner.routing.vehicle_parking.VehicleParkingTestGraphData; import org.opentripplanner.routing.vehicle_parking.VehicleParkingTestUtil; +import org.opentripplanner.street.model._data.StreetModelForTest; import org.opentripplanner.street.model.edge.StreetVehicleParkingLink; import org.opentripplanner.street.model.edge.VehicleParkingEdge; import org.opentripplanner.street.model.vertex.VehicleParkingEntranceVertex; @@ -142,7 +143,10 @@ void deleteVehicleParkingTest() { @Test void addNotOperatingVehicleParkingTest() { - var vehicleParking = VehicleParking.builder().state(VehicleParkingState.CLOSED).build(); + var vehicleParking = StreetModelForTest + .vehicleParking() + .state(VehicleParkingState.CLOSED) + .build(); when(dataSource.getUpdates()).thenReturn(List.of(vehicleParking)); runUpdaterOnce(); @@ -155,8 +159,8 @@ void addNotOperatingVehicleParkingTest() { void updateNotOperatingVehicleParkingTest() { var vehiclePlaces = VehicleParkingSpaces.builder().bicycleSpaces(1).build(); - var vehicleParking = VehicleParking - .builder() + var vehicleParking = StreetModelForTest + .vehicleParking() .availability(vehiclePlaces) .state(VehicleParkingState.CLOSED) .build(); @@ -175,8 +179,8 @@ void updateNotOperatingVehicleParkingTest() { vehiclePlaces = VehicleParkingSpaces.builder().bicycleSpaces(2).build(); vehicleParking = - VehicleParking - .builder() + StreetModelForTest + .vehicleParking() .availability(vehiclePlaces) .state(VehicleParkingState.CLOSED) .build(); @@ -194,7 +198,10 @@ void updateNotOperatingVehicleParkingTest() { @Test void deleteNotOperatingVehicleParkingTest() { - var vehicleParking = VehicleParking.builder().state(VehicleParkingState.CLOSED).build(); + var vehicleParking = StreetModelForTest + .vehicleParking() + .state(VehicleParkingState.CLOSED) + .build(); when(dataSource.getUpdates()).thenReturn(List.of(vehicleParking)); runUpdaterOnce(); From 999f28b5224d2ad352497fba6acd8983eb38d457 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 25 Mar 2024 17:20:52 +0100 Subject: [PATCH 021/121] Update docs --- doc-templates/VehicleParking.md | 7 +- docs/sandbox/VehicleParking.md | 64 ++++++++++++++++++- .../standalone/config/router-config.json | 6 ++ 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/doc-templates/VehicleParking.md b/doc-templates/VehicleParking.md index 37988ef7902..50bd8806267 100644 --- a/doc-templates/VehicleParking.md +++ b/doc-templates/VehicleParking.md @@ -3,7 +3,7 @@ ## Contact Info - For HSL Park and Ride updater: Digitransit team, HSL, Helsinki, Finland -- For Bikely updater: Leonard Ehrenfried, [mail@leonard.io](mailto:mail@leonard.io) +- For Bikely and NOI updater: Leonard Ehrenfried, [mail@leonard.io](mailto:mail@leonard.io) ## Documentation @@ -16,6 +16,7 @@ Currently contains the following updaters: - [HSL Park and Ride](https://p.hsl.fi/docs/index.html) - [ParkAPI](https://github.com/offenesdresden/ParkAPI) - [Bikely](https://www.safebikely.com/) +- [NOI Open Data Hub](https://opendatahub.com/) ### Configuration @@ -39,6 +40,10 @@ All updaters have the following parameters in common: +## NOI Open Data Hub + + + ## Changelog diff --git a/docs/sandbox/VehicleParking.md b/docs/sandbox/VehicleParking.md index 8a659446516..2721fff9b0c 100644 --- a/docs/sandbox/VehicleParking.md +++ b/docs/sandbox/VehicleParking.md @@ -3,7 +3,7 @@ ## Contact Info - For HSL Park and Ride updater: Digitransit team, HSL, Helsinki, Finland -- For Bikely updater: Leonard Ehrenfried, [mail@leonard.io](mailto:mail@leonard.io) +- For Bikely and NOI updater: Leonard Ehrenfried, [mail@leonard.io](mailto:mail@leonard.io) ## Documentation @@ -16,6 +16,7 @@ Currently contains the following updaters: - [HSL Park and Ride](https://p.hsl.fi/docs/index.html) - [ParkAPI](https://github.com/offenesdresden/ParkAPI) - [Bikely](https://www.safebikely.com/) +- [NOI Open Data Hub](https://opendatahub.com/) ### Configuration @@ -250,6 +251,67 @@ HTTP headers to add to the request. Any header key, value can be inserted. +## NOI Open Data Hub + + + + +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|---------------------------------|:---------------:|----------------------------------------------------------------------------|:----------:|---------------|:-----:| +| type = "vehicle-parking" | `enum` | The type of the updater. | *Required* | | 1.5 | +| [feedId](#u__5__feedId) | `string` | The name of the data source. | *Required* | | 2.2 | +| frequency | `duration` | How often to update the source. | *Optional* | `"PT1M"` | 2.6 | +| [sourceType](#u__5__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 | +| url | `uri` | URL of the locations endpoint. | *Required* | | 2.6 | +| [headers](#u__5__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.6 | + + +#### Details + +

feedId

+ +**Since version:** `2.2` ∙ **Type:** `string` ∙ **Cardinality:** `Required` +**Path:** /updaters/[5] + +The name of the data source. + +This will end up in the API responses as the feed id of of the parking lot. + +

sourceType

+ +**Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Required` +**Path:** /updaters/[5] +**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub` + +The source of the vehicle updates. + +

headers

+ +**Since version:** `2.6` ∙ **Type:** `map of string` ∙ **Cardinality:** `Optional` +**Path:** /updaters/[5] + +HTTP headers to add to the request. Any header key, value can be inserted. + + + +##### Example configuration + +```JSON +// router-config.json +{ + "updaters" : [ + { + "type" : "vehicle-parking", + "feedId" : "noi", + "sourceType" : "noi-open-data-hub", + "url" : "https://parking.otp.opendatahub.com/parking/all.json" + } + ] +} +``` + + + ## Changelog diff --git a/src/test/resources/standalone/config/router-config.json b/src/test/resources/standalone/config/router-config.json index 3a07cddfeb8..f5eaa1f942b 100644 --- a/src/test/resources/standalone/config/router-config.json +++ b/src/test/resources/standalone/config/router-config.json @@ -334,6 +334,12 @@ "Authorization": "${BIKELY_AUTHORIZATION}" } }, + { + "type": "vehicle-parking", + "feedId": "noi", + "sourceType": "noi-open-data-hub", + "url": "https://parking.otp.opendatahub.com/parking/all.json" + }, { "type": "stop-time-updater", "frequency": "1m", From 95c4f6c27f26d0e11b925f35d2ec587544168fee Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 26 Mar 2024 09:57:07 +0100 Subject: [PATCH 022/121] Add nicer toString --- docs/RouterConfiguration.md | 6 +++ docs/UpdaterConfig.md | 36 +++++++------- docs/sandbox/siri/SiriAzureUpdater.md | 48 +++++++++---------- docs/sandbox/siri/SiriUpdater.md | 46 +++++++++--------- .../ext/vehicleparking/noi/NoiUpdater.java | 18 +++++-- .../VehicleParkingUpdater.java | 8 +++- 6 files changed, 91 insertions(+), 71 deletions(-) diff --git a/docs/RouterConfiguration.md b/docs/RouterConfiguration.md index 503b8c7370f..e0f1d81b590 100644 --- a/docs/RouterConfiguration.md +++ b/docs/RouterConfiguration.md @@ -764,6 +764,12 @@ Used to group requests when monitoring OTP. "Authorization" : "${BIKELY_AUTHORIZATION}" } }, + { + "type" : "vehicle-parking", + "feedId" : "noi", + "sourceType" : "noi-open-data-hub", + "url" : "https://parking.otp.opendatahub.com/parking/all.json" + }, { "type" : "stop-time-updater", "frequency" : "1m", diff --git a/docs/UpdaterConfig.md b/docs/UpdaterConfig.md index 973874be66a..3e0907f60ad 100644 --- a/docs/UpdaterConfig.md +++ b/docs/UpdaterConfig.md @@ -92,20 +92,20 @@ The information is downloaded in a single HTTP request and polled regularly. | Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | |-----------------------------------------------------------------------|:---------------:|----------------------------------------------------------------------------|:----------:|----------------------|:-----:| | type = "stop-time-updater" | `enum` | The type of the updater. | *Required* | | 1.5 | -| [backwardsDelayPropagationType](#u__5__backwardsDelayPropagationType) | `enum` | How backwards propagation should be handled. | *Optional* | `"required-no-data"` | 2.2 | +| [backwardsDelayPropagationType](#u__6__backwardsDelayPropagationType) | `enum` | How backwards propagation should be handled. | *Optional* | `"required-no-data"` | 2.2 | | feedId | `string` | Which feed the updates apply to. | *Required* | | 1.5 | | frequency | `duration` | How often the data should be downloaded. | *Optional* | `"PT1M"` | 1.5 | | fuzzyTripMatching | `boolean` | If the trips should be matched fuzzily. | *Optional* | `false` | 1.5 | -| [url](#u__5__url) | `string` | The URL of the GTFS-RT resource. | *Required* | | 1.5 | -| [headers](#u__5__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 | +| [url](#u__6__url) | `string` | The URL of the GTFS-RT resource. | *Required* | | 1.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 | ##### Parameter details -

backwardsDelayPropagationType

+

backwardsDelayPropagationType

**Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Optional` ∙ **Default value:** `"required-no-data"` -**Path:** /updaters/[5] +**Path:** /updaters/[6] **Enum values:** `required-no-data` | `required` | `always` How backwards propagation should be handled. @@ -124,19 +124,19 @@ How backwards propagation should be handled. The updated times are exposed through APIs. -

url

+

url

**Since version:** `1.5` ∙ **Type:** `string` ∙ **Cardinality:** `Required` -**Path:** /updaters/[5] +**Path:** /updaters/[6] The URL of the GTFS-RT resource. `file:` URLs are also supported if you want to read a file from the local disk. -

headers

+

headers

**Since version:** `2.3` ∙ **Type:** `map of string` ∙ **Cardinality:** `Optional` -**Path:** /updaters/[5] +**Path:** /updaters/[6] HTTP headers to add to the request. Any header key, value can be inserted. @@ -178,7 +178,7 @@ This system powers the realtime updates in Helsinki and more information can be | 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 | +| [backwardsDelayPropagationType](#u__7__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 | @@ -188,10 +188,10 @@ This system powers the realtime updates in Helsinki and more information can be ##### Parameter details -

backwardsDelayPropagationType

+

backwardsDelayPropagationType

**Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Optional` ∙ **Default value:** `"required-no-data"` -**Path:** /updaters/[6] +**Path:** /updaters/[7] **Enum values:** `required-no-data` | `required` | `always` How backwards propagation should be handled. @@ -247,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__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 | +| [features](#u__8__features) | `enum set` | Which features of GTFS RT vehicle positions should be loaded into OTP. | *Optional* | | 2.5 | +| [headers](#u__8__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/[7] +**Path:** /updaters/[8] **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/[7] +**Path:** /updaters/[8] HTTP headers to add to the request. Any header key, value can be inserted. diff --git a/docs/sandbox/siri/SiriAzureUpdater.md b/docs/sandbox/siri/SiriAzureUpdater.md index 3b5c536946d..c6ddf9f3ebe 100644 --- a/docs/sandbox/siri/SiriAzureUpdater.md +++ b/docs/sandbox/siri/SiriAzureUpdater.md @@ -24,14 +24,14 @@ To enable the SIRI updater you need to add it to the updaters section of the `ro | 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 | +| [authenticationType](#u__12__authenticationType) | `enum` | Which authentication type to use | *Optional* | `"sharedaccesskey"` | 2.5 | | autoDeleteOnIdle | `duration` | The time after which an inactive subscription is removed. | *Optional* | `"PT1H"` | 2.5 | -| [customMidnight](#u__11__customMidnight) | `integer` | Time on which time breaks into new day. | *Optional* | `0` | 2.2 | +| [customMidnight](#u__12__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 | +| [fullyQualifiedNamespace](#u__12__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 | | prefetchCount | `integer` | The number of messages to fetch from the subscription at a time. | *Optional* | `10` | 2.5 | -| [servicebus-url](#u__11__servicebus_url) | `string` | Service Bus connection used for authentication. | *Optional* | | 2.2 | +| [servicebus-url](#u__12__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 | @@ -41,36 +41,36 @@ To enable the SIRI updater you need to add it to the updaters section of the `ro ##### Parameter details -

authenticationType

+

authenticationType

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

customMidnight

+

customMidnight

**Since version:** `2.2` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0` -**Path:** /updaters/[11] +**Path:** /updaters/[12] 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

+

fullyQualifiedNamespace

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

servicebus-url

+

servicebus-url

**Since version:** `2.2` ∙ **Type:** `string` ∙ **Cardinality:** `Optional` -**Path:** /updaters/[11] +**Path:** /updaters/[12] Service Bus connection used for authentication. @@ -112,14 +112,14 @@ Has to be present for authenticationMethod SharedAccessKey. This should be Prima | 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 | +| [authenticationType](#u__11__authenticationType) | `enum` | Which authentication type to use | *Optional* | `"sharedaccesskey"` | 2.5 | | autoDeleteOnIdle | `duration` | The time after which an inactive subscription is removed. | *Optional* | `"PT1H"` | 2.5 | -| [customMidnight](#u__10__customMidnight) | `integer` | Time on which time breaks into new day. | *Optional* | `0` | 2.2 | +| [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__10__fullyQualifiedNamespace) | `string` | Service Bus fully qualified namespace used for authentication. | *Optional* | | 2.5 | +| [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 | | prefetchCount | `integer` | The number of messages to fetch from the subscription at a time. | *Optional* | `10` | 2.5 | -| [servicebus-url](#u__10__servicebus_url) | `string` | Service Bus connection used for authentication. | *Optional* | | 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 | @@ -130,36 +130,36 @@ Has to be present for authenticationMethod SharedAccessKey. This should be Prima ##### Parameter details -

authenticationType

+

authenticationType

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

customMidnight

+

customMidnight

**Since version:** `2.2` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0` -**Path:** /updaters/[10] +**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

+

fullyQualifiedNamespace

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

servicebus-url

+

servicebus-url

**Since version:** `2.2` ∙ **Type:** `string` ∙ **Cardinality:** `Optional` -**Path:** /updaters/[10] +**Path:** /updaters/[11] Service Bus connection used for authentication. diff --git a/docs/sandbox/siri/SiriUpdater.md b/docs/sandbox/siri/SiriUpdater.md index f6c4c3f999f..72ab45d0f39 100644 --- a/docs/sandbox/siri/SiriUpdater.md +++ b/docs/sandbox/siri/SiriUpdater.md @@ -37,16 +37,16 @@ To enable the SIRI updater you need to add it to the updaters section of the `ro | previewInterval | `duration` | TODO | *Optional* | | 2.0 | | requestorRef | `string` | The requester reference. | *Optional* | | 2.0 | | timeout | `duration` | The HTTP timeout to download the updates. | *Optional* | `"PT15S"` | 2.0 | -| [url](#u__8__url) | `string` | The URL to send the HTTP requests to. | *Required* | | 2.0 | -| [headers](#u__8__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 | +| [url](#u__9__url) | `string` | The URL to send the HTTP requests to. | *Required* | | 2.0 | +| [headers](#u__9__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 | ##### Parameter details -

url

+

url

**Since version:** `2.0` ∙ **Type:** `string` ∙ **Cardinality:** `Required` -**Path:** /updaters/[8] +**Path:** /updaters/[9] The URL to send the HTTP requests to. @@ -58,10 +58,10 @@ renamed by the loader when processed: -

headers

+

headers

**Since version:** `2.3` ∙ **Type:** `map of string` ∙ **Cardinality:** `Optional` -**Path:** /updaters/[8] +**Path:** /updaters/[9] HTTP headers to add to the request. Any header key, value can be inserted. @@ -93,25 +93,25 @@ HTTP headers to add to the request. Any header key, value can be inserted. -| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | -|---------------------------------|:---------------:|--------------------------------------------------------------------------------------------------------|:----------:|---------------|:-----:| -| type = "siri-sx-updater" | `enum` | The type of the updater. | *Required* | | 1.5 | -| blockReadinessUntilInitialized | `boolean` | Whether catching up with the updates should block the readiness check from returning a 'ready' result. | *Optional* | `false` | 2.0 | -| [earlyStart](#u__9__earlyStart) | `duration` | This value is subtracted from the actual validity defined in the message. | *Optional* | `"PT0S"` | 2.0 | -| feedId | `string` | The ID of the feed to apply the updates to. | *Required* | | 2.0 | -| frequency | `duration` | How often the updates should be retrieved. | *Optional* | `"PT1M"` | 2.0 | -| requestorRef | `string` | The requester reference. | *Optional* | | 2.0 | -| timeout | `duration` | The HTTP timeout to download the updates. | *Optional* | `"PT15S"` | 2.0 | -| [url](#u__9__url) | `string` | The URL to send the HTTP requests to. Supports http/https and file protocol. | *Required* | | 2.0 | -| [headers](#u__9__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 | +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|----------------------------------|:---------------:|--------------------------------------------------------------------------------------------------------|:----------:|---------------|:-----:| +| type = "siri-sx-updater" | `enum` | The type of the updater. | *Required* | | 1.5 | +| blockReadinessUntilInitialized | `boolean` | Whether catching up with the updates should block the readiness check from returning a 'ready' result. | *Optional* | `false` | 2.0 | +| [earlyStart](#u__10__earlyStart) | `duration` | This value is subtracted from the actual validity defined in the message. | *Optional* | `"PT0S"` | 2.0 | +| feedId | `string` | The ID of the feed to apply the updates to. | *Required* | | 2.0 | +| frequency | `duration` | How often the updates should be retrieved. | *Optional* | `"PT1M"` | 2.0 | +| requestorRef | `string` | The requester reference. | *Optional* | | 2.0 | +| timeout | `duration` | The HTTP timeout to download the updates. | *Optional* | `"PT15S"` | 2.0 | +| [url](#u__10__url) | `string` | The URL to send the HTTP requests to. Supports http/https and file protocol. | *Required* | | 2.0 | +| [headers](#u__10__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 | ##### Parameter details -

earlyStart

+

earlyStart

**Since version:** `2.0` ∙ **Type:** `duration` ∙ **Cardinality:** `Optional` ∙ **Default value:** `"PT0S"` -**Path:** /updaters/[9] +**Path:** /updaters/[10] This value is subtracted from the actual validity defined in the message. @@ -119,10 +119,10 @@ Normally the planned departure time is used, so setting this to 10s will cause t SX-message to be included in trip-results 10 seconds before the the planned departure time. -

url

+

url

**Since version:** `2.0` ∙ **Type:** `string` ∙ **Cardinality:** `Required` -**Path:** /updaters/[9] +**Path:** /updaters/[10] The URL to send the HTTP requests to. Supports http/https and file protocol. @@ -135,10 +135,10 @@ renamed by the loader when processed: -

headers

+

headers

**Since version:** `2.3` ∙ **Type:** `map of string` ∙ **Cardinality:** `Optional` -**Path:** /updaters/[9] +**Path:** /updaters/[10] HTTP headers to add to the request. Any header key, value can be inserted. diff --git a/src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdater.java b/src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdater.java index 9bd64d9612f..d5ef7e63d13 100644 --- a/src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdater.java +++ b/src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdater.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.databind.JsonNode; import org.opentripplanner.framework.geometry.WgsCoordinate; import org.opentripplanner.framework.i18n.NonLocalizedString; +import org.opentripplanner.framework.tostring.ToStringBuilder; import org.opentripplanner.routing.vehicle_parking.VehicleParking; import org.opentripplanner.routing.vehicle_parking.VehicleParkingSpaces; import org.opentripplanner.routing.vehicle_parking.VehicleParkingState; @@ -15,12 +16,11 @@ public class NoiUpdater extends GenericJsonDataSource { private static final String JSON_PARSE_PATH = "data/stations"; - - private final String feedId; + private final NoiUpdaterParameters params; public NoiUpdater(NoiUpdaterParameters parameters) { super(parameters.url().toString(), JSON_PARSE_PATH, parameters.httpHeaders()); - this.feedId = parameters.feedId(); + this.params = parameters; } @Override @@ -38,14 +38,14 @@ protected VehicleParking parseElement(JsonNode jsonNode) { throw new IllegalArgumentException("Unknown type '%s'".formatted(type)); } - var vehicleParkId = new FeedScopedId(feedId, jsonNode.path("station_id").asText()); + var vehicleParkId = new FeedScopedId(params.feedId(), jsonNode.path("station_id").asText()); var name = new NonLocalizedString(jsonNode.path("name").asText()); double lat = jsonNode.path("lat").asDouble(); double lon = jsonNode.path("lon").asDouble(); var coordinate = new WgsCoordinate(lat, lon); VehicleParking.VehicleParkingEntranceCreator entrance = builder -> builder - .entranceId(new FeedScopedId(feedId, vehicleParkId.getId() + "/entrance")) + .entranceId(new FeedScopedId(params.feedId(), vehicleParkId.getId() + "/entrance")) .coordinate(coordinate) .walkAccessible(true) .carAccessible(true); @@ -66,4 +66,12 @@ protected VehicleParking parseElement(JsonNode jsonNode) { private static VehicleParkingSpaces extractSpaces(JsonNode jsonNode, String free) { return VehicleParkingSpaces.builder().carSpaces(jsonNode.get(free).asInt()).build(); } + + @Override + public String toString() { + return ToStringBuilder + .of(this.getClass()) + .addStr("url", this.params.url().toString()) + .toString(); + } } diff --git a/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdater.java b/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdater.java index 3d2e9b21e29..185de6bddb7 100644 --- a/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdater.java +++ b/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdater.java @@ -8,6 +8,7 @@ import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import org.opentripplanner.framework.tostring.ToStringBuilder; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.linking.DisposableEdgeCollection; import org.opentripplanner.routing.linking.LinkingDirection; @@ -68,7 +69,7 @@ public void setGraphUpdaterManager(WriteToGraphCallback saveResultOnGraph) { } @Override - protected void runPolling() throws Exception { + protected void runPolling() { LOG.debug("Updating vehicle parkings from {}", source); if (!source.update()) { LOG.debug("No updates"); @@ -239,4 +240,9 @@ private void removeVehicleParkingEdgesFromGraph( graph.remove(entranceVertex); } } + + @Override + public String toString() { + return ToStringBuilder.of(this.getClass()).addObj("source", source).toString(); + } } From aebead92b2e822a6fafd4ae797aaba7c8752de43 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 27 Mar 2024 22:41:04 +0100 Subject: [PATCH 023/121] Correct x/y lat/lon confusion --- .../flex/AreaStopsToVerticesMapperTest.java | 62 ++++++++----------- .../_support/geometry/Coordinates.java | 19 ++++-- .../_support/geometry/Polygons.java | 12 ++-- .../framework/geometry/WgsCoordinateTest.java | 8 +-- .../framework/lang/StringUtilsTest.java | 2 + .../module/StreetLinkerModuleTest.java | 8 +-- .../core/TemporaryVerticesContainerTest.java | 4 +- .../model/_data/StreetModelForTest.java | 6 +- .../street/model/edge/StreetEdgeTest.java | 4 +- .../GeofencingVertexUpdaterTest.java | 21 ++++--- 10 files changed, 75 insertions(+), 71 deletions(-) diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/AreaStopsToVerticesMapperTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/AreaStopsToVerticesMapperTest.java index 9e95350020f..3b41cf9632d 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/AreaStopsToVerticesMapperTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/AreaStopsToVerticesMapperTest.java @@ -2,7 +2,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.DynamicTest.dynamicTest; import static org.opentripplanner._support.geometry.Coordinates.BERLIN; import static org.opentripplanner._support.geometry.Coordinates.HAMBURG; import static org.opentripplanner.street.model.StreetTraversalPermission.ALL; @@ -13,9 +12,8 @@ import java.util.List; import java.util.Set; -import java.util.stream.Stream; -import org.junit.jupiter.api.DynamicTest; -import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.locationtech.jts.geom.Coordinate; import org.opentripplanner._support.geometry.Polygons; import org.opentripplanner.routing.graph.Graph; @@ -42,44 +40,38 @@ class AreaStopsToVerticesMapperTest { public static final TransitModel TRANSIT_MODEL = new TransitModel(STOP_MODEL, new Deduplicator()); - private final List testCases = List.of( - new TestCase(BERLIN, ALL, Set.of(BERLIN_AREA_STOP)), - new TestCase(BERLIN, PEDESTRIAN_AND_CAR, Set.of(BERLIN_AREA_STOP)), - new TestCase(BERLIN, BICYCLE_AND_CAR, Set.of()), - new TestCase(HAMBURG, ALL, Set.of()), - new TestCase(BERLIN, PEDESTRIAN, Set.of()), - new TestCase(HAMBURG, PEDESTRIAN, Set.of()), - new TestCase(BERLIN, CAR, Set.of()) - ); + static List testCases() { + return List.of( + new TestCase(BERLIN, ALL, Set.of(BERLIN_AREA_STOP)), + new TestCase(BERLIN, PEDESTRIAN_AND_CAR, Set.of(BERLIN_AREA_STOP)), + new TestCase(BERLIN, BICYCLE_AND_CAR, Set.of()), + new TestCase(HAMBURG, ALL, Set.of()), + new TestCase(BERLIN, PEDESTRIAN, Set.of()), + new TestCase(HAMBURG, PEDESTRIAN, Set.of()), + new TestCase(BERLIN, CAR, Set.of()) + ); + } - @TestFactory - Stream mapAreaStopsInVertex() { - return testCases - .stream() - .map(tc -> - dynamicTest( - tc.toString(), - () -> { - var graph = new Graph(); + @ParameterizedTest + @MethodSource("testCases") + void mapAreaStopsInVertex(TestCase tc) { + var graph = new Graph(); - var fromVertex = StreetModelForTest.intersectionVertex(tc.coordinate); - var toVertex = StreetModelForTest.intersectionVertex(tc.coordinate); + var fromVertex = StreetModelForTest.intersectionVertex(tc.coordinate); + var toVertex = StreetModelForTest.intersectionVertex(tc.coordinate); - var edge = StreetModelForTest.streetEdge(fromVertex, toVertex); - edge.setPermission(tc.permission); - fromVertex.addOutgoing(edge); + var edge = StreetModelForTest.streetEdge(fromVertex, toVertex); + edge.setPermission(tc.permission); + fromVertex.addOutgoing(edge); - graph.addVertex(fromVertex); - assertTrue(fromVertex.areaStops().isEmpty()); + graph.addVertex(fromVertex); + assertTrue(fromVertex.areaStops().isEmpty()); - var mapper = new AreaStopsToVerticesMapper(graph, TRANSIT_MODEL); + var mapper = new AreaStopsToVerticesMapper(graph, TRANSIT_MODEL); - mapper.buildGraph(); + mapper.buildGraph(); - assertEquals(tc.expectedAreaStops, fromVertex.areaStops()); - } - ) - ); + assertEquals(tc.expectedAreaStops, fromVertex.areaStops()); } private record TestCase( diff --git a/src/test/java/org/opentripplanner/_support/geometry/Coordinates.java b/src/test/java/org/opentripplanner/_support/geometry/Coordinates.java index 3e5bddd9f94..88fcdcf1160 100644 --- a/src/test/java/org/opentripplanner/_support/geometry/Coordinates.java +++ b/src/test/java/org/opentripplanner/_support/geometry/Coordinates.java @@ -4,9 +4,18 @@ public class Coordinates { - public static final Coordinate BERLIN = new Coordinate(52.5212, 13.4105); - public static final Coordinate BERLIN_BRANDENBURG_GATE = new Coordinate(52.51627, 13.37770); - public static final Coordinate HAMBURG = new Coordinate(53.5566, 10.0003); - public static final Coordinate KONGSBERG_PLATFORM_1 = new Coordinate(59.67216, 9.65107); - public static final Coordinate BOSTON = new Coordinate(42.36541, -71.06129); + public static final Coordinate BERLIN = of(52.5212, 13.4105); + public static final Coordinate BERLIN_BRANDENBURG_GATE = of(52.51627, 13.37770); + public static final Coordinate HAMBURG = of(53.5566, 10.0003); + public static final Coordinate KONGSBERG_PLATFORM_1 = of(59.67216, 9.65107); + public static final Coordinate BOSTON = of(42.36541, -71.06129); + + /** + * Because it is a frequent mistake to mistake x/y and longitude/latitude when + * constructing JTS Coordinates, this static factory method makes is clear + * which is which. + */ + public static Coordinate of(double latitude, double longitude) { + return new Coordinate(longitude, latitude); + } } diff --git a/src/test/java/org/opentripplanner/_support/geometry/Polygons.java b/src/test/java/org/opentripplanner/_support/geometry/Polygons.java index efedd74499c..e3d153ea041 100644 --- a/src/test/java/org/opentripplanner/_support/geometry/Polygons.java +++ b/src/test/java/org/opentripplanner/_support/geometry/Polygons.java @@ -12,11 +12,11 @@ public class Polygons { .getGeometryFactory() .createPolygon( new Coordinate[] { - new Coordinate(52.616841, 13.224692810), - new Coordinate(52.6168419, 13.224692810), - new Coordinate(52.3915238, 13.646107734), - new Coordinate(52.616841, 13.646107734), - new Coordinate(52.616841, 13.224692810), + Coordinates.of(52.616841, 13.224692810), + Coordinates.of(52.616841, 13.646107734), + Coordinates.of(52.3915238, 13.646107734), + Coordinates.of(52.396421, 13.2268067), + Coordinates.of(52.616841, 13.224692810), } ); @@ -25,7 +25,7 @@ public static org.geojson.Polygon toGeoJson(Polygon polygon) { var coordinates = Arrays .stream(polygon.getCoordinates()) - .map(c -> new LngLatAlt(c.y, c.x)) + .map(c -> new LngLatAlt(c.x, c.y)) .toList(); ret.add(coordinates); diff --git a/src/test/java/org/opentripplanner/framework/geometry/WgsCoordinateTest.java b/src/test/java/org/opentripplanner/framework/geometry/WgsCoordinateTest.java index 05051ab7dff..5cd7ac66123 100644 --- a/src/test/java/org/opentripplanner/framework/geometry/WgsCoordinateTest.java +++ b/src/test/java/org/opentripplanner/framework/geometry/WgsCoordinateTest.java @@ -109,15 +109,15 @@ void testGreenwich() { void roundingTo10m() { var hamburg = new WgsCoordinate(Coordinates.HAMBURG); var rounded = hamburg.roundToApproximate10m(); - assertEquals(10.0003, rounded.latitude()); - assertEquals(53.5566, rounded.longitude()); + assertEquals(10.0003, rounded.longitude()); + assertEquals(53.5566, rounded.latitude()); } @Test void roundingTo100m() { var hamburg = new WgsCoordinate(Coordinates.HAMBURG); var rounded = hamburg.roundToApproximate100m(); - assertEquals(10, rounded.latitude()); - assertEquals(53.557, rounded.longitude()); + assertEquals(10, rounded.longitude()); + assertEquals(53.557, rounded.latitude()); } } diff --git a/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java b/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java index 0e67344b2bb..17ee3cbca6a 100644 --- a/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java +++ b/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java @@ -13,6 +13,7 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; +import org.opentripplanner._support.geometry.Polygons; class StringUtilsTest { @@ -77,6 +78,7 @@ void padCenter() { @Test void padRight() { + System.out.println(Polygons.BERLIN); assertEquals("ABC???", StringUtils.padRight("ABC", '?', 6)); assertEquals("??????", StringUtils.padRight(null, '?', 6)); assertEquals("ABC", StringUtils.padRight("ABC", '?', 3)); diff --git a/src/test/java/org/opentripplanner/graph_builder/module/StreetLinkerModuleTest.java b/src/test/java/org/opentripplanner/graph_builder/module/StreetLinkerModuleTest.java index 96e71b9d3ec..4d2141eb38e 100644 --- a/src/test/java/org/opentripplanner/graph_builder/module/StreetLinkerModuleTest.java +++ b/src/test/java/org/opentripplanner/graph_builder/module/StreetLinkerModuleTest.java @@ -102,12 +102,12 @@ private static class TestModel { public TestModel() { var from = StreetModelForTest.intersectionVertex( - KONGSBERG_PLATFORM_1.x - DELTA, - KONGSBERG_PLATFORM_1.y - DELTA + KONGSBERG_PLATFORM_1.y - DELTA, + KONGSBERG_PLATFORM_1.x - DELTA ); var to = StreetModelForTest.intersectionVertex( - KONGSBERG_PLATFORM_1.x + DELTA, - KONGSBERG_PLATFORM_1.y + DELTA + KONGSBERG_PLATFORM_1.y + DELTA, + KONGSBERG_PLATFORM_1.x + DELTA ); Graph graph = new Graph(); diff --git a/src/test/java/org/opentripplanner/routing/core/TemporaryVerticesContainerTest.java b/src/test/java/org/opentripplanner/routing/core/TemporaryVerticesContainerTest.java index 49dc42e6f4c..c01558338a4 100644 --- a/src/test/java/org/opentripplanner/routing/core/TemporaryVerticesContainerTest.java +++ b/src/test/java/org/opentripplanner/routing/core/TemporaryVerticesContainerTest.java @@ -39,8 +39,8 @@ public class TemporaryVerticesContainerTest { private final Graph g = new Graph(new Deduplicator()); private final StreetVertex a = StreetModelForTest.intersectionVertex("A", 1.0, 1.0); - private final StreetVertex b = StreetModelForTest.intersectionVertex("B", 0.0, 1.0); - private final StreetVertex c = StreetModelForTest.intersectionVertex("C", 1.0, 0.0); + private final StreetVertex b = StreetModelForTest.intersectionVertex("B", 1.0, 0.0); + private final StreetVertex c = StreetModelForTest.intersectionVertex("C", 0.0, 1.0); private final List permanentVertexes = Arrays.asList(a, b, c); // - And travel *origin* is 0,4 degrees on the road from B to A private final GenericLocation from = new GenericLocation(1.0, 0.4); diff --git a/src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java b/src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java index d50c8a74dfc..94ebaec73c4 100644 --- a/src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java +++ b/src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java @@ -29,16 +29,16 @@ public class StreetModelForTest { public static StreetVertex V4 = intersectionVertex("V4", 3, 3); public static IntersectionVertex intersectionVertex(Coordinate c) { - return intersectionVertex(c.x, c.y); + return intersectionVertex(c.y, c.x); } public static IntersectionVertex intersectionVertex(double lat, double lon) { var label = "%s_%s".formatted(lat, lon); - return new LabelledIntersectionVertex(label, lat, lon, false, false); + return new LabelledIntersectionVertex(label, lon, lat, false, false); } public static IntersectionVertex intersectionVertex(String label, double lat, double lon) { - return new LabelledIntersectionVertex(label, lat, lon, false, false); + return new LabelledIntersectionVertex(label, lon, lat, false, false); } @Nonnull diff --git a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeTest.java b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeTest.java index 318f133f15e..7de7b0c7ce6 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeTest.java @@ -46,7 +46,7 @@ public class StreetEdgeTest { public void before() { v0 = intersectionVertex("maple_0th", 0.0, 0.0); // label, X, Y v1 = intersectionVertex("maple_1st", 2.0, 2.0); - v2 = intersectionVertex("maple_2nd", 1.0, 2.0); + v2 = intersectionVertex("maple_2nd", 2.0, 1.0); this.proto = StreetSearchRequest @@ -73,7 +73,7 @@ public void testInAndOutAngles() { assertEquals(90, e1.getOutAngle()); // 2 new ones - StreetVertex u = intersectionVertex("test1", 2.0, 1.0); + StreetVertex u = intersectionVertex("test1", 1.0, 2.0); StreetVertex v = intersectionVertex("test2", 2.0, 2.0); // Second edge, heading straight North diff --git a/src/test/java/org/opentripplanner/updater/vehicle_rental/GeofencingVertexUpdaterTest.java b/src/test/java/org/opentripplanner/updater/vehicle_rental/GeofencingVertexUpdaterTest.java index 09dd1cf1cb9..bab86f8cd6f 100644 --- a/src/test/java/org/opentripplanner/updater/vehicle_rental/GeofencingVertexUpdaterTest.java +++ b/src/test/java/org/opentripplanner/updater/vehicle_rental/GeofencingVertexUpdaterTest.java @@ -12,6 +12,7 @@ import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.MultiPolygon; import org.locationtech.jts.geom.Polygon; +import org.opentripplanner._support.geometry.Coordinates; import org.opentripplanner.framework.geometry.GeometryUtils; import org.opentripplanner.service.vehiclerental.model.GeofencingZone; import org.opentripplanner.service.vehiclerental.street.BusinessAreaBorder; @@ -40,21 +41,21 @@ class GeofencingVertexUpdaterTest { GeometryFactory fac = GeometryUtils.getGeometryFactory(); Polygon frognerPark = fac.createPolygon( new Coordinate[] { - new Coordinate(59.93112978539807, 10.691099320272173), - new Coordinate(59.92231848097069, 10.691099320272173), - new Coordinate(59.92231848097069, 10.711758464910503), - new Coordinate(59.92231848097069, 10.691099320272173), - new Coordinate(59.93112978539807, 10.691099320272173), + Coordinates.of(59.93112978539807, 10.691099320272173), + Coordinates.of(59.92231848097069, 10.691099320272173), + Coordinates.of(59.92231848097069, 10.711758464910503), + Coordinates.of(59.92231848097069, 10.691099320272173), + Coordinates.of(59.93112978539807, 10.691099320272173), } ); final GeofencingZone zone = new GeofencingZone(id("frogner-park"), frognerPark, true, false); Polygon osloPolygon = fac.createPolygon( new Coordinate[] { - new Coordinate(59.961055202323195, 10.62535658370308), - new Coordinate(59.889009435700416, 10.62535658370308), - new Coordinate(59.889009435700416, 10.849791142928694), - new Coordinate(59.961055202323195, 10.849791142928694), - new Coordinate(59.961055202323195, 10.62535658370308), + Coordinates.of(59.961055202323195, 10.62535658370308), + Coordinates.of(59.889009435700416, 10.62535658370308), + Coordinates.of(59.889009435700416, 10.849791142928694), + Coordinates.of(59.961055202323195, 10.849791142928694), + Coordinates.of(59.961055202323195, 10.62535658370308), } ); From e58a5a4f05ac1b828c9c06e3174bbd926616996d Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 27 Mar 2024 22:46:48 +0100 Subject: [PATCH 024/121] Move polygons into separate class --- .../_support/geometry/Coordinates.java | 2 +- .../_support/geometry/Polygons.java | 41 ++++++++++++++----- .../framework/lang/StringUtilsTest.java | 1 - .../GeofencingVertexUpdaterTest.java | 33 ++++----------- 4 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/test/java/org/opentripplanner/_support/geometry/Coordinates.java b/src/test/java/org/opentripplanner/_support/geometry/Coordinates.java index 88fcdcf1160..5a4526012c9 100644 --- a/src/test/java/org/opentripplanner/_support/geometry/Coordinates.java +++ b/src/test/java/org/opentripplanner/_support/geometry/Coordinates.java @@ -11,7 +11,7 @@ public class Coordinates { public static final Coordinate BOSTON = of(42.36541, -71.06129); /** - * Because it is a frequent mistake to mistake x/y and longitude/latitude when + * Because it is a frequent mistake to swap x/y and longitude/latitude when * constructing JTS Coordinates, this static factory method makes is clear * which is which. */ diff --git a/src/test/java/org/opentripplanner/_support/geometry/Polygons.java b/src/test/java/org/opentripplanner/_support/geometry/Polygons.java index e3d153ea041..c01921b12b6 100644 --- a/src/test/java/org/opentripplanner/_support/geometry/Polygons.java +++ b/src/test/java/org/opentripplanner/_support/geometry/Polygons.java @@ -3,22 +3,41 @@ import java.util.Arrays; import org.geojson.LngLatAlt; import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.Polygon; import org.opentripplanner.framework.geometry.GeometryUtils; public class Polygons { - public static final Polygon BERLIN = GeometryUtils - .getGeometryFactory() - .createPolygon( - new Coordinate[] { - Coordinates.of(52.616841, 13.224692810), - Coordinates.of(52.616841, 13.646107734), - Coordinates.of(52.3915238, 13.646107734), - Coordinates.of(52.396421, 13.2268067), - Coordinates.of(52.616841, 13.224692810), - } - ); + private static final GeometryFactory FAC = GeometryUtils.getGeometryFactory(); + public static final Polygon BERLIN = FAC.createPolygon( + new Coordinate[] { + Coordinates.of(52.616841, 13.224692810), + Coordinates.of(52.616841, 13.646107734), + Coordinates.of(52.3915238, 13.646107734), + Coordinates.of(52.396421, 13.2268067), + Coordinates.of(52.616841, 13.224692810), + } + ); + + public static Polygon OSLO = FAC.createPolygon( + new Coordinate[] { + Coordinates.of(59.961055202323195, 10.62535658370308), + Coordinates.of(59.889009435700416, 10.62535658370308), + Coordinates.of(59.889009435700416, 10.849791142928694), + Coordinates.of(59.961055202323195, 10.849791142928694), + Coordinates.of(59.961055202323195, 10.62535658370308), + } + ); + public static Polygon OSLO_FROGNER_PARK = FAC.createPolygon( + new Coordinate[] { + Coordinates.of(59.93112978539807, 10.691099320272173), + Coordinates.of(59.92231848097069, 10.691099320272173), + Coordinates.of(59.92231848097069, 10.711758464910503), + Coordinates.of(59.92231848097069, 10.691099320272173), + Coordinates.of(59.93112978539807, 10.691099320272173), + } + ); public static org.geojson.Polygon toGeoJson(Polygon polygon) { var ret = new org.geojson.Polygon(); diff --git a/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java b/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java index 17ee3cbca6a..52cce79ebd5 100644 --- a/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java +++ b/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java @@ -78,7 +78,6 @@ void padCenter() { @Test void padRight() { - System.out.println(Polygons.BERLIN); assertEquals("ABC???", StringUtils.padRight("ABC", '?', 6)); assertEquals("??????", StringUtils.padRight(null, '?', 6)); assertEquals("ABC", StringUtils.padRight("ABC", '?', 3)); diff --git a/src/test/java/org/opentripplanner/updater/vehicle_rental/GeofencingVertexUpdaterTest.java b/src/test/java/org/opentripplanner/updater/vehicle_rental/GeofencingVertexUpdaterTest.java index bab86f8cd6f..99910e04f7c 100644 --- a/src/test/java/org/opentripplanner/updater/vehicle_rental/GeofencingVertexUpdaterTest.java +++ b/src/test/java/org/opentripplanner/updater/vehicle_rental/GeofencingVertexUpdaterTest.java @@ -8,11 +8,10 @@ import java.util.List; import org.junit.jupiter.api.Test; -import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.MultiPolygon; import org.locationtech.jts.geom.Polygon; -import org.opentripplanner._support.geometry.Coordinates; +import org.opentripplanner._support.geometry.Polygons; import org.opentripplanner.framework.geometry.GeometryUtils; import org.opentripplanner.service.vehiclerental.model.GeofencingZone; import org.opentripplanner.service.vehiclerental.street.BusinessAreaBorder; @@ -36,30 +35,16 @@ class GeofencingVertexUpdaterTest { final GeofencingVertexUpdater updater = new GeofencingVertexUpdater(ignored -> List.of(insideFrognerPark, halfInHalfOutFrognerPark, businessBorder) ); - StreetEdge outsideFrognerPark = streetEdge(outsideFrognerPark1, outsideFrognerPark2); - - GeometryFactory fac = GeometryUtils.getGeometryFactory(); - Polygon frognerPark = fac.createPolygon( - new Coordinate[] { - Coordinates.of(59.93112978539807, 10.691099320272173), - Coordinates.of(59.92231848097069, 10.691099320272173), - Coordinates.of(59.92231848097069, 10.711758464910503), - Coordinates.of(59.92231848097069, 10.691099320272173), - Coordinates.of(59.93112978539807, 10.691099320272173), - } - ); - final GeofencingZone zone = new GeofencingZone(id("frogner-park"), frognerPark, true, false); - Polygon osloPolygon = fac.createPolygon( - new Coordinate[] { - Coordinates.of(59.961055202323195, 10.62535658370308), - Coordinates.of(59.889009435700416, 10.62535658370308), - Coordinates.of(59.889009435700416, 10.849791142928694), - Coordinates.of(59.961055202323195, 10.849791142928694), - Coordinates.of(59.961055202323195, 10.62535658370308), - } + + static GeometryFactory fac = GeometryUtils.getGeometryFactory(); + final GeofencingZone zone = new GeofencingZone( + id("frogner-park"), + Polygons.OSLO_FROGNER_PARK, + true, + false ); - MultiPolygon osloMultiPolygon = fac.createMultiPolygon(new Polygon[] { osloPolygon }); + MultiPolygon osloMultiPolygon = fac.createMultiPolygon(new Polygon[] { Polygons.OSLO }); final GeofencingZone businessArea = new GeofencingZone( id("oslo"), osloMultiPolygon, From 4c9d5fcef520600cb7d6a20a4d84601c3e669fa6 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 28 Mar 2024 10:55:45 +0100 Subject: [PATCH 025/121] Correct polygon for Frogner Park --- .../_support/geometry/Polygons.java | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/opentripplanner/_support/geometry/Polygons.java b/src/test/java/org/opentripplanner/_support/geometry/Polygons.java index c01921b12b6..a386d8a27e1 100644 --- a/src/test/java/org/opentripplanner/_support/geometry/Polygons.java +++ b/src/test/java/org/opentripplanner/_support/geometry/Polygons.java @@ -31,11 +31,28 @@ public class Polygons { ); public static Polygon OSLO_FROGNER_PARK = FAC.createPolygon( new Coordinate[] { - Coordinates.of(59.93112978539807, 10.691099320272173), - Coordinates.of(59.92231848097069, 10.691099320272173), - Coordinates.of(59.92231848097069, 10.711758464910503), - Coordinates.of(59.92231848097069, 10.691099320272173), - Coordinates.of(59.93112978539807, 10.691099320272173), + Coordinates.of(59.92939032560119, 10.69770054003061), + Coordinates.of(59.929138466684975, 10.695210909925208), + Coordinates.of(59.92745319808358, 10.692696865071184), + Coordinates.of(59.92709930323093, 10.693774304996225), + Coordinates.of(59.92745914988427, 10.69495957972947), + Coordinates.of(59.92736919590291, 10.697664535925895), + Coordinates.of(59.924837887427856, 10.697927604125255), + Coordinates.of(59.924447953413335, 10.697448767354985), + Coordinates.of(59.92378800804022, 10.697819761729818), + Coordinates.of(59.92329018587293, 10.699196446969069), + Coordinates.of(59.92347619027632, 10.700285749621997), + Coordinates.of(59.92272030268688, 10.704714696822037), + Coordinates.of(59.92597766029715, 10.71001707489603), + Coordinates.of(59.92676341291536, 10.707838597058043), + Coordinates.of(59.92790300889098, 10.708389137506913), + Coordinates.of(59.928376832499424, 10.707060536853078), + Coordinates.of(59.92831087551576, 10.705803789539402), + Coordinates.of(59.92953431964068, 10.706641515204467), + Coordinates.of(59.93046383654274, 10.70484606360543), + Coordinates.of(59.93008590667682, 10.701817874860211), + Coordinates.of(59.93028982601595, 10.700525251174469), + Coordinates.of(59.92939032560119, 10.69770054003061), } ); From 256226dcae0268a59e49adb34d459a84aa104c63 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 31 Mar 2024 22:39:41 +0000 Subject: [PATCH 026/121] Update lucene.version to v9.10.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0de0e7ef711..ad3c0d135f6 100644 --- a/pom.xml +++ b/pom.xml @@ -66,7 +66,7 @@ 1.12.3 5.5.3 1.5.3 - 9.9.1 + 9.10.0 2.0.12 2.0.15 1.26 From ae3562ae27820c26c2ccd1026ac74bcd95741f43 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Apr 2024 01:14:08 +0000 Subject: [PATCH 027/121] Update Debug UI dependencies (non-major) --- client-next/package-lock.json | 136 ++++++++++++++++------------------ client-next/package.json | 14 ++-- 2 files changed, 72 insertions(+), 78 deletions(-) diff --git a/client-next/package-lock.json b/client-next/package-lock.json index 03aa0171357..d3b8c10754b 100644 --- a/client-next/package-lock.json +++ b/client-next/package-lock.json @@ -12,7 +12,7 @@ "bootstrap": "5.3.3", "graphql": "16.8.1", "graphql-request": "6.1.0", - "maplibre-gl": "4.1.1", + "maplibre-gl": "4.1.2", "react": "18.2.0", "react-bootstrap": "2.10.2", "react-dom": "18.2.0", @@ -20,14 +20,14 @@ }, "devDependencies": { "@graphql-codegen/cli": "5.0.2", - "@graphql-codegen/client-preset": "4.2.4", + "@graphql-codegen/client-preset": "4.2.5", "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.4.1", "@testing-library/react": "14.2.2", - "@types/react": "18.2.70", - "@types/react-dom": "18.2.22", - "@typescript-eslint/eslint-plugin": "7.4.0", - "@typescript-eslint/parser": "7.4.0", + "@types/react": "18.2.73", + "@types/react-dom": "18.2.23", + "@typescript-eslint/eslint-plugin": "7.5.0", + "@typescript-eslint/parser": "7.5.0", "@vitejs/plugin-react": "4.2.1", "@vitest/coverage-v8": "1.4.0", "eslint": "8.57.0", @@ -40,7 +40,7 @@ "jsdom": "24.0.0", "prettier": "3.2.5", "typescript": "5.4.3", - "vite": "5.2.6", + "vite": "5.2.7", "vitest": "1.4.0" } }, @@ -1693,9 +1693,9 @@ } }, "node_modules/@graphql-codegen/client-preset": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-4.2.4.tgz", - "integrity": "sha512-k1c8v2YxJhhITGQGxViG9asLAoop9m7X9duU7Zztqjc98ooxsUzXICfvAWsH3mLAUibXAx4Ax6BPzKsTtQmBPg==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-4.2.5.tgz", + "integrity": "sha512-hAdB6HN8EDmkoBtr0bPUN/7NH6svzqbcTDMWBCRXPESXkl7y80po+IXrXUjsSrvhKG8xkNXgJNz/2mjwHzywcA==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", @@ -3528,19 +3528,18 @@ "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "node_modules/@types/react": { - "version": "18.2.70", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.70.tgz", - "integrity": "sha512-hjlM2hho2vqklPhopNkXkdkeq6Lv8WSZTpr7956zY+3WS5cfYUewtCzsJLsbW5dEv3lfSeQ4W14ZFeKC437JRQ==", + "version": "18.2.73", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.73.tgz", + "integrity": "sha512-XcGdod0Jjv84HOC7N5ziY3x+qL0AfmubvKOZ9hJjJ2yd5EE+KYjWhdOjt387e9HPheHkdggF9atTifMRtyAaRA==", "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.2.22", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.22.tgz", - "integrity": "sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==", + "version": "18.2.23", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.23.tgz", + "integrity": "sha512-ZQ71wgGOTmDYpnav2knkjr3qXdAFu0vsk8Ci5w3pGAIdj7/kKAyn+VsQDhXsmzzzepAiI9leWMmubXz690AI/A==", "dev": true, "dependencies": { "@types/react": "*" @@ -3554,11 +3553,6 @@ "@types/react": "*" } }, - "node_modules/@types/scheduler": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" - }, "node_modules/@types/semver": { "version": "7.5.8", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", @@ -3588,16 +3582,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz", - "integrity": "sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.5.0.tgz", + "integrity": "sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.4.0", - "@typescript-eslint/type-utils": "7.4.0", - "@typescript-eslint/utils": "7.4.0", - "@typescript-eslint/visitor-keys": "7.4.0", + "@typescript-eslint/scope-manager": "7.5.0", + "@typescript-eslint/type-utils": "7.5.0", + "@typescript-eslint/utils": "7.5.0", + "@typescript-eslint/visitor-keys": "7.5.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -3656,15 +3650,15 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.4.0.tgz", - "integrity": "sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.5.0.tgz", + "integrity": "sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.4.0", - "@typescript-eslint/types": "7.4.0", - "@typescript-eslint/typescript-estree": "7.4.0", - "@typescript-eslint/visitor-keys": "7.4.0", + "@typescript-eslint/scope-manager": "7.5.0", + "@typescript-eslint/types": "7.5.0", + "@typescript-eslint/typescript-estree": "7.5.0", + "@typescript-eslint/visitor-keys": "7.5.0", "debug": "^4.3.4" }, "engines": { @@ -3684,13 +3678,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.4.0.tgz", - "integrity": "sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.5.0.tgz", + "integrity": "sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.4.0", - "@typescript-eslint/visitor-keys": "7.4.0" + "@typescript-eslint/types": "7.5.0", + "@typescript-eslint/visitor-keys": "7.5.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3701,13 +3695,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.4.0.tgz", - "integrity": "sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.5.0.tgz", + "integrity": "sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.4.0", - "@typescript-eslint/utils": "7.4.0", + "@typescript-eslint/typescript-estree": "7.5.0", + "@typescript-eslint/utils": "7.5.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -3728,9 +3722,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.4.0.tgz", - "integrity": "sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.5.0.tgz", + "integrity": "sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3741,13 +3735,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.4.0.tgz", - "integrity": "sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.5.0.tgz", + "integrity": "sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.4.0", - "@typescript-eslint/visitor-keys": "7.4.0", + "@typescript-eslint/types": "7.5.0", + "@typescript-eslint/visitor-keys": "7.5.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3802,17 +3796,17 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.4.0.tgz", - "integrity": "sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.5.0.tgz", + "integrity": "sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.4.0", - "@typescript-eslint/types": "7.4.0", - "@typescript-eslint/typescript-estree": "7.4.0", + "@typescript-eslint/scope-manager": "7.5.0", + "@typescript-eslint/types": "7.5.0", + "@typescript-eslint/typescript-estree": "7.5.0", "semver": "^7.5.4" }, "engines": { @@ -3860,12 +3854,12 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.4.0.tgz", - "integrity": "sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.5.0.tgz", + "integrity": "sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/types": "7.5.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -8423,9 +8417,9 @@ } }, "node_modules/maplibre-gl": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.1.1.tgz", - "integrity": "sha512-DmHru9FTHCOngNHzIx9W2+MlUziYPfPxd2qjyeWwczBYNx2SDpmH394MkuCvSgnfUm5Zvs4NaYCqMu44jUga1Q==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.1.2.tgz", + "integrity": "sha512-98T+3BesL4w/N39q/rgs9q6HzHLG6pgbS9UaTqg6fMISfzy2WGKokjK205ENFDDmEljj54/LTfdXgqg2XfYU4A==", "dependencies": { "@mapbox/geojson-rewind": "^0.5.2", "@mapbox/jsonlint-lines-primitives": "^2.0.2", @@ -10974,13 +10968,13 @@ } }, "node_modules/vite": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.6.tgz", - "integrity": "sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==", + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.7.tgz", + "integrity": "sha512-k14PWOKLI6pMaSzAuGtT+Cf0YmIx12z9YGon39onaJNy8DLBfBJrzg9FQEmkAM5lpHBZs9wksWAsyF/HkpEwJA==", "dev": true, "dependencies": { "esbuild": "^0.20.1", - "postcss": "^8.4.36", + "postcss": "^8.4.38", "rollup": "^4.13.0" }, "bin": { diff --git a/client-next/package.json b/client-next/package.json index 36569ee11f8..d3f583057d8 100644 --- a/client-next/package.json +++ b/client-next/package.json @@ -21,7 +21,7 @@ "bootstrap": "5.3.3", "graphql": "16.8.1", "graphql-request": "6.1.0", - "maplibre-gl": "4.1.1", + "maplibre-gl": "4.1.2", "react": "18.2.0", "react-bootstrap": "2.10.2", "react-dom": "18.2.0", @@ -29,14 +29,14 @@ }, "devDependencies": { "@graphql-codegen/cli": "5.0.2", - "@graphql-codegen/client-preset": "4.2.4", + "@graphql-codegen/client-preset": "4.2.5", "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.4.1", "@testing-library/react": "14.2.2", - "@types/react": "18.2.70", - "@types/react-dom": "18.2.22", - "@typescript-eslint/eslint-plugin": "7.4.0", - "@typescript-eslint/parser": "7.4.0", + "@types/react": "18.2.73", + "@types/react-dom": "18.2.23", + "@typescript-eslint/eslint-plugin": "7.5.0", + "@typescript-eslint/parser": "7.5.0", "@vitejs/plugin-react": "4.2.1", "@vitest/coverage-v8": "1.4.0", "eslint": "8.57.0", @@ -49,7 +49,7 @@ "jsdom": "24.0.0", "prettier": "3.2.5", "typescript": "5.4.3", - "vite": "5.2.6", + "vite": "5.2.7", "vitest": "1.4.0" } } From 8d15a0d9616bedd15f67b294c91d721131feccd8 Mon Sep 17 00:00:00 2001 From: OTP Bot Date: Tue, 2 Apr 2024 07:26:15 +0000 Subject: [PATCH 028/121] Upgrade debug client to version 2024/04/2024-04-02T07:25 --- src/client/debug-client-preview/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/debug-client-preview/index.html b/src/client/debug-client-preview/index.html index b719c57b507..3973571de30 100644 --- a/src/client/debug-client-preview/index.html +++ b/src/client/debug-client-preview/index.html @@ -5,8 +5,8 @@ OTP Debug Client - - + +
From 258398db202f97434662e5bf37fe82b18ac490b2 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 2 Apr 2024 10:57:07 +0200 Subject: [PATCH 029/121] Remove import --- .../java/org/opentripplanner/framework/lang/StringUtilsTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java b/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java index 52cce79ebd5..0e67344b2bb 100644 --- a/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java +++ b/src/test/java/org/opentripplanner/framework/lang/StringUtilsTest.java @@ -13,7 +13,6 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; -import org.opentripplanner._support.geometry.Polygons; class StringUtilsTest { From 8a45b2ec53d081a96e78b1bbbb709f0e9420a9c1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Apr 2024 01:49:55 +0000 Subject: [PATCH 030/121] Update dependency com.google.cloud.tools:jib-maven-plugin to v3.4.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0de0e7ef711..53cc2f59184 100644 --- a/pom.xml +++ b/pom.xml @@ -444,7 +444,7 @@ com.google.cloud.tools jib-maven-plugin - 3.4.1 + 3.4.2 org.opentripplanner.standalone.OTPMain From c1a91969c5007e539d580926d9e52c15b3f9e7b0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Apr 2024 01:50:02 +0000 Subject: [PATCH 031/121] Update dependency org.jacoco:jacoco-maven-plugin to v0.8.12 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 53cc2f59184..b1dec9cb960 100644 --- a/pom.xml +++ b/pom.xml @@ -312,7 +312,7 @@ org.jacoco jacoco-maven-plugin - 0.8.11 + 0.8.12 - - com.googlecode.json-simple - json-simple - 1.1.1 - - - - junit - junit - - - - diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/TestTransitService.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/TestTransitService.java new file mode 100644 index 00000000000..d187b611ef3 --- /dev/null +++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/TestTransitService.java @@ -0,0 +1,23 @@ +package org.opentripplanner.ext.vectortiles.layers; + +import java.util.Set; +import org.opentripplanner.transit.model._data.TransitModelForTest; +import org.opentripplanner.transit.model.basic.TransitMode; +import org.opentripplanner.transit.model.network.Route; +import org.opentripplanner.transit.model.site.StopLocation; +import org.opentripplanner.transit.service.DefaultTransitService; +import org.opentripplanner.transit.service.TransitModel; + +public class TestTransitService extends DefaultTransitService { + + public TestTransitService(TransitModel transitModel) { + super(transitModel); + } + + @Override + public Set getRoutesForStop(StopLocation stop) { + return Set.of( + TransitModelForTest.route("1").withMode(TransitMode.RAIL).withGtfsType(100).build() + ); + } +} diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stations/DigitransitStationPropertyMapperTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stations/DigitransitStationPropertyMapperTest.java new file mode 100644 index 00000000000..da85285954d --- /dev/null +++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stations/DigitransitStationPropertyMapperTest.java @@ -0,0 +1,46 @@ +package org.opentripplanner.ext.vectortiles.layers.stations; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.transit.model._data.TransitModelForTest.id; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import org.junit.jupiter.api.Test; +import org.opentripplanner.ext.vectortiles.layers.TestTransitService; +import org.opentripplanner.framework.i18n.I18NString; +import org.opentripplanner.transit.model._data.TransitModelForTest; +import org.opentripplanner.transit.model.framework.Deduplicator; +import org.opentripplanner.transit.model.site.Station; +import org.opentripplanner.transit.service.StopModel; +import org.opentripplanner.transit.service.TransitModel; + +public class DigitransitStationPropertyMapperTest { + + @Test + void map() { + var deduplicator = new Deduplicator(); + var transitModel = new TransitModel(new StopModel(), deduplicator); + transitModel.index(); + var transitService = new TestTransitService(transitModel); + + var mapper = DigitransitStationPropertyMapper.create(transitService, Locale.US); + + var station = Station + .of(id("a-station")) + .withCoordinate(1, 1) + .withName(I18NString.of("A station")) + .build(); + + TransitModelForTest.of().stop("stop-1").withParentStation(station).build(); + + Map map = new HashMap<>(); + mapper.map(station).forEach(o -> map.put(o.key(), o.value())); + + assertEquals("F:a-station", map.get("gtfsId")); + assertEquals("A station", map.get("name")); + assertEquals("", map.get("type")); + assertEquals("[{\"mode\":\"RAIL\",\"shortName\":\"R1\"}]", map.get("routes")); + assertEquals("[\"F:stop-1\"]", map.get("stops")); + } +} diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/RealtimeStopsLayerTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/RealtimeStopsLayerTest.java new file mode 100644 index 00000000000..8f2e1f94fa6 --- /dev/null +++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/RealtimeStopsLayerTest.java @@ -0,0 +1,104 @@ +package org.opentripplanner.ext.vectortiles.layers.stops; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.framework.time.TimeUtils.time; +import static org.opentripplanner.model.plan.TestItineraryBuilder.newItinerary; + +import java.time.ZonedDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.opentripplanner._support.time.ZoneIds; +import org.opentripplanner.ext.realtimeresolver.RealtimeResolver; +import org.opentripplanner.framework.i18n.I18NString; +import org.opentripplanner.model.plan.Place; +import org.opentripplanner.routing.alertpatch.AlertEffect; +import org.opentripplanner.routing.alertpatch.EntitySelector; +import org.opentripplanner.routing.alertpatch.TimePeriod; +import org.opentripplanner.routing.alertpatch.TransitAlert; +import org.opentripplanner.routing.impl.TransitAlertServiceImpl; +import org.opentripplanner.routing.services.TransitAlertService; +import org.opentripplanner.transit.model._data.TransitModelForTest; +import org.opentripplanner.transit.model.framework.Deduplicator; +import org.opentripplanner.transit.model.framework.FeedScopedId; +import org.opentripplanner.transit.model.network.Route; +import org.opentripplanner.transit.model.site.RegularStop; +import org.opentripplanner.transit.service.DefaultTransitService; +import org.opentripplanner.transit.service.StopModel; +import org.opentripplanner.transit.service.TransitModel; + +public class RealtimeStopsLayerTest { + + private RegularStop stop; + private RegularStop stop2; + + @BeforeEach + public void setUp() { + var name = I18NString.of("name"); + var desc = I18NString.of("desc"); + stop = + StopModel + .of() + .regularStop(new FeedScopedId("F", "name")) + .withName(name) + .withDescription(desc) + .withCoordinate(50, 10) + .build(); + stop2 = + StopModel + .of() + .regularStop(new FeedScopedId("F", "name")) + .withName(name) + .withDescription(desc) + .withCoordinate(51, 10) + .build(); + } + + @Test + void realtimeStopLayer() { + var deduplicator = new Deduplicator(); + var transitModel = new TransitModel(new StopModel(), deduplicator); + transitModel.initTimeZone(ZoneIds.HELSINKI); + transitModel.index(); + var alertService = new TransitAlertServiceImpl(transitModel); + var transitService = new DefaultTransitService(transitModel) { + @Override + public TransitAlertService getTransitAlertService() { + return alertService; + } + }; + + Route route = TransitModelForTest.route("route").build(); + var itinerary = newItinerary(Place.forStop(stop), time("11:00")) + .bus(route, 1, time("11:05"), time("11:20"), Place.forStop(stop2)) + .build(); + var startDate = ZonedDateTime.now(ZoneIds.HELSINKI).minusDays(1).toEpochSecond(); + var endDate = ZonedDateTime.now(ZoneIds.HELSINKI).plusDays(1).toEpochSecond(); + var alert = TransitAlert + .of(stop.getId()) + .addEntity(new EntitySelector.Stop(stop.getId())) + .addTimePeriod(new TimePeriod(startDate, endDate)) + .withEffect(AlertEffect.NO_SERVICE) + .build(); + transitService.getTransitAlertService().setAlerts(List.of(alert)); + + var itineraries = List.of(itinerary); + RealtimeResolver.populateLegsWithRealtime(itineraries, transitService); + + DigitransitRealtimeStopPropertyMapper mapper = new DigitransitRealtimeStopPropertyMapper( + transitService, + new Locale("en-US") + ); + + Map map = new HashMap<>(); + mapper.map(stop).forEach(o -> map.put(o.key(), o.value())); + + assertEquals("F:name", map.get("gtfsId")); + assertEquals("name", map.get("name")); + assertEquals("desc", map.get("desc")); + assertEquals(true, map.get("closedByServiceAlert")); + } +} diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/StopsLayerTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/StopsLayerTest.java index a914cf9db6c..4c3e60701bd 100644 --- a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/StopsLayerTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/StopsLayerTest.java @@ -1,32 +1,16 @@ package org.opentripplanner.ext.vectortiles.layers.stops; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.opentripplanner.framework.time.TimeUtils.time; -import static org.opentripplanner.model.plan.TestItineraryBuilder.newItinerary; -import java.time.Instant; -import java.time.LocalDate; -import java.time.ZonedDateTime; import java.util.HashMap; -import java.util.List; import java.util.Locale; import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.opentripplanner._support.time.ZoneIds; -import org.opentripplanner.ext.realtimeresolver.RealtimeResolver; +import org.opentripplanner.ext.vectortiles.layers.TestTransitService; import org.opentripplanner.framework.i18n.TranslatedString; -import org.opentripplanner.model.plan.Place; -import org.opentripplanner.routing.alertpatch.AlertEffect; -import org.opentripplanner.routing.alertpatch.EntitySelector; -import org.opentripplanner.routing.alertpatch.TimePeriod; -import org.opentripplanner.routing.alertpatch.TransitAlert; -import org.opentripplanner.routing.impl.TransitAlertServiceImpl; -import org.opentripplanner.routing.services.TransitAlertService; -import org.opentripplanner.transit.model._data.TransitModelForTest; import org.opentripplanner.transit.model.framework.Deduplicator; import org.opentripplanner.transit.model.framework.FeedScopedId; -import org.opentripplanner.transit.model.network.Route; import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.service.DefaultTransitService; import org.opentripplanner.transit.service.StopModel; @@ -35,7 +19,6 @@ public class StopsLayerTest { private RegularStop stop; - private RegularStop stop2; @BeforeEach public void setUp() { @@ -67,14 +50,6 @@ public void setUp() { .withDescription(descTranslations) .withCoordinate(50, 10) .build(); - stop2 = - StopModel - .of() - .regularStop(new FeedScopedId("F", "name")) - .withName(nameTranslations) - .withDescription(descTranslations) - .withCoordinate(51, 10) - .build(); } @Test @@ -82,7 +57,7 @@ public void digitransitStopPropertyMapperTest() { var deduplicator = new Deduplicator(); var transitModel = new TransitModel(new StopModel(), deduplicator); transitModel.index(); - var transitService = new DefaultTransitService(transitModel); + var transitService = new TestTransitService(transitModel); DigitransitStopPropertyMapper mapper = DigitransitStopPropertyMapper.create( transitService, @@ -95,6 +70,7 @@ public void digitransitStopPropertyMapperTest() { assertEquals("F:name", map.get("gtfsId")); assertEquals("name", map.get("name")); assertEquals("desc", map.get("desc")); + assertEquals("[{\"gtfsType\":100}]", map.get("routes")); } @Test @@ -115,49 +91,4 @@ public void digitransitStopPropertyMapperTranslationTest() { assertEquals("nameDE", map.get("name")); assertEquals("descDE", map.get("desc")); } - - @Test - public void digitransitRealtimeStopPropertyMapperTest() { - var deduplicator = new Deduplicator(); - var transitModel = new TransitModel(new StopModel(), deduplicator); - transitModel.initTimeZone(ZoneIds.HELSINKI); - transitModel.index(); - var alertService = new TransitAlertServiceImpl(transitModel); - var transitService = new DefaultTransitService(transitModel) { - @Override - public TransitAlertService getTransitAlertService() { - return alertService; - } - }; - - Route route = TransitModelForTest.route("route").build(); - var itinerary = newItinerary(Place.forStop(stop), time("11:00")) - .bus(route, 1, time("11:05"), time("11:20"), Place.forStop(stop2)) - .build(); - var startDate = ZonedDateTime.now(ZoneIds.HELSINKI).minusDays(1).toEpochSecond(); - var endDate = ZonedDateTime.now(ZoneIds.HELSINKI).plusDays(1).toEpochSecond(); - var alert = TransitAlert - .of(stop.getId()) - .addEntity(new EntitySelector.Stop(stop.getId())) - .addTimePeriod(new TimePeriod(startDate, endDate)) - .withEffect(AlertEffect.NO_SERVICE) - .build(); - transitService.getTransitAlertService().setAlerts(List.of(alert)); - - var itineraries = List.of(itinerary); - RealtimeResolver.populateLegsWithRealtime(itineraries, transitService); - - DigitransitRealtimeStopPropertyMapper mapper = new DigitransitRealtimeStopPropertyMapper( - transitService, - new Locale("en-US") - ); - - Map map = new HashMap<>(); - mapper.map(stop).forEach(o -> map.put(o.key(), o.value())); - - assertEquals("F:name", map.get("gtfsId")); - assertEquals("name", map.get("name")); - assertEquals("desc", map.get("desc")); - assertEquals(true, map.get("closedByServiceAlert")); - } } diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/VehicleParkingGroupsLayerTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/VehicleParkingGroupsLayerTest.java index 1ec7d042894..60ba9100f43 100644 --- a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/VehicleParkingGroupsLayerTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/VehicleParkingGroupsLayerTest.java @@ -144,7 +144,7 @@ public void digitransitVehicleParkingGroupPropertyMapperTest() { assertEquals("groupName", map.get("name").toString()); assertEquals( - "[{\"bicyclePlaces\":false,\"carPlaces\":true,\"name\":\"name\",\"id\":\"F:id\"}]", + "[{\"carPlaces\":true,\"bicyclePlaces\":false,\"id\":\"F:id\",\"name\":\"name\"}]", map.get("vehicleParking") ); } @@ -162,7 +162,7 @@ public void digitransitVehicleParkingGroupPropertyMapperTranslationTest() { assertEquals("groupDE", map.get("name").toString()); assertEquals( - "[{\"bicyclePlaces\":false,\"carPlaces\":true,\"name\":\"DE\",\"id\":\"F:id\"}]", + "[{\"carPlaces\":true,\"bicyclePlaces\":false,\"id\":\"F:id\",\"name\":\"DE\"}]", map.get("vehicleParking") ); } diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stations/DigitransitStationPropertyMapper.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stations/DigitransitStationPropertyMapper.java index a828cd37a7c..18b4a5f388d 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stations/DigitransitStationPropertyMapper.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stations/DigitransitStationPropertyMapper.java @@ -1,13 +1,14 @@ package org.opentripplanner.ext.vectortiles.layers.stations; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Collection; import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.stream.Collectors; -import org.json.simple.JSONArray; import org.opentripplanner.apis.support.mapping.PropertyMapper; import org.opentripplanner.framework.i18n.I18NStringMapper; +import org.opentripplanner.framework.json.ObjectMappers; import org.opentripplanner.inspector.vector.KeyValue; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.site.Station; @@ -16,6 +17,7 @@ public class DigitransitStationPropertyMapper extends PropertyMapper { + private static final ObjectMapper OBJECT_MAPPER = ObjectMappers.ignoringExtraFields(); private final TransitService transitService; private final I18NStringMapper i18NStringMapper; @@ -33,41 +35,47 @@ public static DigitransitStationPropertyMapper create( @Override public Collection map(Station station) { - var childStops = station.getChildStops(); - - return List.of( - new KeyValue("gtfsId", station.getId().toString()), - new KeyValue("name", i18NStringMapper.mapNonnullToApi(station.getName())), - new KeyValue( - "type", - childStops - .stream() - .flatMap(stop -> transitService.getPatternsForStop(stop).stream()) - .map(tripPattern -> tripPattern.getMode().name()) - .distinct() - .collect(Collectors.joining(",")) - ), - new KeyValue( - "stops", - JSONArray.toJSONString( - childStops.stream().map(StopLocation::getId).map(FeedScopedId::toString).toList() - ) - ), - new KeyValue( - "routes", - JSONArray.toJSONString( + try { + var childStops = station.getChildStops(); + return List.of( + new KeyValue("gtfsId", station.getId().toString()), + new KeyValue("name", i18NStringMapper.mapNonnullToApi(station.getName())), + new KeyValue( + "type", childStops .stream() - .flatMap(stop -> transitService.getRoutesForStop(stop).stream()) + .flatMap(stop -> transitService.getPatternsForStop(stop).stream()) + .map(tripPattern -> tripPattern.getMode().name()) .distinct() - .map(route -> - route.getShortName() == null - ? Map.of("mode", route.getMode().name()) - : Map.of("mode", route.getMode().name(), "shortName", route.getShortName()) - ) - .collect(Collectors.toList()) + .collect(Collectors.joining(",")) + ), + new KeyValue( + "stops", + OBJECT_MAPPER.writeValueAsString( + childStops.stream().map(StopLocation::getId).map(FeedScopedId::toString).toList() + ) + ), + new KeyValue( + "routes", + OBJECT_MAPPER.writeValueAsString( + childStops + .stream() + .flatMap(stop -> transitService.getRoutesForStop(stop).stream()) + .distinct() + .map(route -> { + var obj = OBJECT_MAPPER.createObjectNode(); + obj.put("mode", route.getMode().name()); + if (route.getShortName() != null) { + obj.put("shortName", route.getShortName()); + } + return obj; + }) + .toList() + ) ) - ) - ); + ); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } } } diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/DigitransitStopPropertyMapper.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/DigitransitStopPropertyMapper.java index 643ed63b7f8..d10e221b1d5 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/DigitransitStopPropertyMapper.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/DigitransitStopPropertyMapper.java @@ -1,16 +1,16 @@ package org.opentripplanner.ext.vectortiles.layers.stops; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; import org.opentripplanner.apis.support.mapping.PropertyMapper; -import org.opentripplanner.framework.collection.ListUtils; import org.opentripplanner.framework.i18n.I18NStringMapper; +import org.opentripplanner.framework.json.ObjectMappers; import org.opentripplanner.inspector.vector.KeyValue; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.RegularStop; @@ -18,6 +18,7 @@ public class DigitransitStopPropertyMapper extends PropertyMapper { + private static final ObjectMapper OBJECT_MAPPER = ObjectMappers.ignoringExtraFields(); private final TransitService transitService; private final I18NStringMapper i18NStringMapper; @@ -59,17 +60,20 @@ protected static Collection getBaseKeyValues( } protected static String getRoutes(TransitService transitService, RegularStop stop) { - return JSONArray.toJSONString( - transitService + try { + var objects = transitService .getRoutesForStop(stop) .stream() .map(route -> { - JSONObject routeObject = new JSONObject(); + var routeObject = OBJECT_MAPPER.createObjectNode(); routeObject.put("gtfsType", route.getGtfsType()); return routeObject; }) - .toList() - ); + .toList(); + return OBJECT_MAPPER.writeValueAsString(objects); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } } protected static String getType(TransitService transitService, RegularStop stop) { diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/DigitransitVehicleParkingGroupPropertyMapper.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/DigitransitVehicleParkingGroupPropertyMapper.java index 33f415c157a..efafc969619 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/DigitransitVehicleParkingGroupPropertyMapper.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/DigitransitVehicleParkingGroupPropertyMapper.java @@ -1,17 +1,19 @@ package org.opentripplanner.ext.vectortiles.layers.vehicleparkings; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Collection; import java.util.List; import java.util.Locale; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; import org.opentripplanner.apis.support.mapping.PropertyMapper; import org.opentripplanner.framework.i18n.I18NStringMapper; +import org.opentripplanner.framework.json.ObjectMappers; import org.opentripplanner.inspector.vector.KeyValue; public class DigitransitVehicleParkingGroupPropertyMapper extends PropertyMapper { + private static final ObjectMapper OBJECT_MAPPER = ObjectMappers.ignoringExtraFields(); private final I18NStringMapper i18NStringMapper; public DigitransitVehicleParkingGroupPropertyMapper(Locale locale) { @@ -24,25 +26,28 @@ public static DigitransitVehicleParkingGroupPropertyMapper create(Locale locale) @Override protected Collection map(VehicleParkingAndGroup parkingAndGroup) { - var group = parkingAndGroup.vehicleParkingGroup(); - String parking = JSONArray.toJSONString( - parkingAndGroup + try { + var group = parkingAndGroup.vehicleParkingGroup(); + var lots = parkingAndGroup .vehicleParking() .stream() .map(vehicleParkingPlace -> { - JSONObject parkingObject = new JSONObject(); + var parkingObject = OBJECT_MAPPER.createObjectNode(); parkingObject.put("carPlaces", vehicleParkingPlace.hasCarPlaces()); parkingObject.put("bicyclePlaces", vehicleParkingPlace.hasBicyclePlaces()); parkingObject.put("id", vehicleParkingPlace.getId().toString()); parkingObject.put("name", i18NStringMapper.mapToApi(vehicleParkingPlace.getName())); return parkingObject; }) - .toList() - ); - return List.of( - new KeyValue("id", group.id().toString()), - new KeyValue("name", i18NStringMapper.mapToApi(group.name())), - new KeyValue("vehicleParking", parking) - ); + .toList(); + var string = OBJECT_MAPPER.writeValueAsString(lots); + return List.of( + new KeyValue("id", group.id().toString()), + new KeyValue("name", i18NStringMapper.mapToApi(group.name())), + new KeyValue("vehicleParking", string) + ); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } } } diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/StadtnaviVehicleParkingPropertyMapper.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/StadtnaviVehicleParkingPropertyMapper.java index c938f9736fd..bccc2b4de4d 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/StadtnaviVehicleParkingPropertyMapper.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/StadtnaviVehicleParkingPropertyMapper.java @@ -1,11 +1,12 @@ package org.opentripplanner.ext.vectortiles.layers.vehicleparkings; +import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Collection; import java.util.List; import java.util.Locale; -import org.json.simple.JSONObject; import org.opentripplanner.apis.support.mapping.PropertyMapper; import org.opentripplanner.framework.i18n.I18NStringMapper; +import org.opentripplanner.framework.json.ObjectMappers; import org.opentripplanner.inspector.vector.KeyValue; import org.opentripplanner.model.calendar.openinghours.OsmOpeningHoursSupport; import org.opentripplanner.routing.vehicle_parking.VehicleParking; @@ -13,6 +14,7 @@ public class StadtnaviVehicleParkingPropertyMapper extends PropertyMapper { + private static final ObjectMapper OBJECT_MAPPER = ObjectMappers.ignoringExtraFields(); private final DigitransitVehicleParkingPropertyMapper digitransitMapper; private final I18NStringMapper i18NStringMapper; @@ -57,13 +59,13 @@ private static List mapPlaces(String key, VehicleParkingSpaces places) return List.of(); } - var json = new JSONObject(); + var json = OBJECT_MAPPER.createObjectNode(); json.put("bicyclePlaces", places.getBicycleSpaces()); json.put("carPlaces", places.getCarSpaces()); json.put("wheelchairAccessibleCarPlaces", places.getWheelchairAccessibleCarSpaces()); return List.of( - new KeyValue(key, JSONObject.toJSONString(json)), + new KeyValue(key, json.toString()), new KeyValue(subKey(key, "bicyclePlaces"), places.getBicycleSpaces()), new KeyValue(subKey(key, "carPlaces"), places.getCarSpaces()), new KeyValue( From 3c1bb2dd77079faead57f4c9d9997977e3338638 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 4 Apr 2024 16:56:10 +0200 Subject: [PATCH 038/121] Move expensive WGS84_XY constant setup into ElevationModule --- .../framework/geometry/GeometryUtils.java | 20 ------------------- .../module/ned/ElevationModule.java | 18 +++++++++++++++-- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/opentripplanner/framework/geometry/GeometryUtils.java b/src/main/java/org/opentripplanner/framework/geometry/GeometryUtils.java index cf634ad0e23..c02ff6151e2 100644 --- a/src/main/java/org/opentripplanner/framework/geometry/GeometryUtils.java +++ b/src/main/java/org/opentripplanner/framework/geometry/GeometryUtils.java @@ -10,8 +10,6 @@ import java.util.stream.Stream; import org.geojson.GeoJsonObject; import org.geojson.LngLatAlt; -import org.geotools.api.referencing.crs.CoordinateReferenceSystem; -import org.geotools.referencing.CRS; import org.locationtech.jts.algorithm.ConvexHull; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.CoordinateSequence; @@ -28,30 +26,12 @@ import org.locationtech.jts.linearref.LengthLocationMap; import org.locationtech.jts.linearref.LinearLocation; import org.locationtech.jts.linearref.LocationIndexedLine; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class GeometryUtils { - private static final Logger LOG = LoggerFactory.getLogger(GeometryUtils.class); - private static final CoordinateSequenceFactory csf = new PackedCoordinateSequenceFactory(); private static final GeometryFactory gf = new GeometryFactory(csf); - /** A shared copy of the WGS84 CRS with longitude-first axis order. */ - public static final CoordinateReferenceSystem WGS84_XY; - - static { - try { - WGS84_XY = CRS.getAuthorityFactory(true).createCoordinateReferenceSystem("EPSG:4326"); - } catch (Exception ex) { - LOG.error("Unable to create longitude-first WGS84 CRS", ex); - throw new RuntimeException( - "Could not create longitude-first WGS84 coordinate reference system." - ); - } - } - public static Geometry makeConvexHull( Collection collection, Function mapToCoordinate diff --git a/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java b/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java index 592d34fb543..6cf48d121d6 100644 --- a/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java +++ b/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java @@ -20,13 +20,14 @@ import java.util.concurrent.atomic.AtomicInteger; import org.geotools.api.coverage.Coverage; import org.geotools.api.coverage.PointOutsideCoverageException; +import org.geotools.api.referencing.crs.CoordinateReferenceSystem; import org.geotools.api.referencing.operation.TransformException; import org.geotools.geometry.Position2D; +import org.geotools.referencing.CRS; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.impl.PackedCoordinateSequence; import org.opentripplanner.framework.geometry.EncodedPolyline; -import org.opentripplanner.framework.geometry.GeometryUtils; import org.opentripplanner.framework.geometry.SphericalDistanceLibrary; import org.opentripplanner.framework.lang.IntUtils; import org.opentripplanner.framework.logging.ProgressTracker; @@ -61,6 +62,19 @@ public class ElevationModule implements GraphBuilderModule { private static final Logger LOG = LoggerFactory.getLogger(ElevationModule.class); + /** A shared copy of the WGS84 CRS with longitude-first axis order. */ + public static final CoordinateReferenceSystem WGS84_XY; + + static { + try { + WGS84_XY = CRS.getAuthorityFactory(true).createCoordinateReferenceSystem("EPSG:4326"); + } catch (Exception ex) { + LOG.error("Unable to create longitude-first WGS84 CRS", ex); + throw new RuntimeException( + "Could not create longitude-first WGS84 coordinate reference system." + ); + } + } /** The elevation data to be used in calculating elevations. */ private final ElevationGridCoverageFactory gridCoverageFactory; @@ -564,7 +578,7 @@ private double getElevation(Coverage coverage, double x, double y) // GeoTIFFs in various projections. Note that GeoTools defaults to strict EPSG axis ordering of (lat, long) // for DefaultGeographicCRS.WGS84, but OTP is using (long, lat) throughout and assumes unprojected DEM // rasters to also use (long, lat). - coverage.evaluate(new Position2D(GeometryUtils.WGS84_XY, x, y), values); + coverage.evaluate(new Position2D(WGS84_XY, x, y), values); } catch (PointOutsideCoverageException e) { nPointsOutsideDEM.incrementAndGet(); throw e; From 64ded27009af07e8be6d44ad57ca06b3767ac211 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 4 Apr 2024 20:42:28 +0200 Subject: [PATCH 039/121] Make field private --- .../graph_builder/module/ned/ElevationModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java b/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java index 6cf48d121d6..e224d1d6d0b 100644 --- a/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java +++ b/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java @@ -63,7 +63,7 @@ public class ElevationModule implements GraphBuilderModule { private static final Logger LOG = LoggerFactory.getLogger(ElevationModule.class); /** A shared copy of the WGS84 CRS with longitude-first axis order. */ - public static final CoordinateReferenceSystem WGS84_XY; + private static final CoordinateReferenceSystem WGS84_XY; static { try { From 0d046467064928f19d36da4d464542b753950a3d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 22:29:44 +0000 Subject: [PATCH 040/121] Update dependency org.apache.maven.plugins:maven-source-plugin to v3.3.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b1dec9cb960..46e04cc24d5 100644 --- a/pom.xml +++ b/pom.xml @@ -185,7 +185,7 @@ org.apache.maven.plugins maven-source-plugin - 3.3.0 + 3.3.1 attach-sources From 300a52ee3f217c141b27bb88906f365d2ceedb3c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 Apr 2024 03:26:52 +0000 Subject: [PATCH 041/121] Update google.dagger.version to v2.51.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 46e04cc24d5..b56c3b4c4fc 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 149 31.0 - 2.51 + 2.51.1 2.17.0 3.1.5 5.10.2 From db554c24e63ec23b70dedf5497772cae14956948 Mon Sep 17 00:00:00 2001 From: Vincent Paturet Date: Fri, 5 Apr 2024 10:50:01 +0200 Subject: [PATCH 042/121] Fix handling of null transport mode filter --- .../opentripplanner/apis/transmodel/mapping/FilterMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/opentripplanner/apis/transmodel/mapping/FilterMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/FilterMapper.java index 9141ce4c104..71d2691e47a 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/mapping/FilterMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/FilterMapper.java @@ -83,7 +83,7 @@ static void mapFilterOldWay( List tModes = new ArrayList<>(); if (GqlUtil.hasArgument(environment, "modes")) { Map modesInput = environment.getArgument("modes"); - if (modesInput.containsKey("transportModes")) { + if (modesInput.get("transportModes") != null) { List> transportModes = (List>) modesInput.get( "transportModes" ); From 24076e9090d2de75dfe8830233eedba91115642e Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 5 Apr 2024 19:24:23 +0300 Subject: [PATCH 043/121] Discourage walking when sidepaths are available --- .../openstreetmap/tagmapping/FinlandMapper.java | 7 +++++++ .../openstreetmap/tagmapping/FinlandMapperTest.java | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/main/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapper.java b/src/main/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapper.java index 9bafe133f2a..c42b8016d45 100644 --- a/src/main/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapper.java +++ b/src/main/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapper.java @@ -1,5 +1,6 @@ package org.opentripplanner.openstreetmap.tagmapping; +import static org.opentripplanner.openstreetmap.wayproperty.MixinPropertiesBuilder.ofWalkSafety; import static org.opentripplanner.openstreetmap.wayproperty.WayPropertiesBuilder.withModes; import static org.opentripplanner.street.model.StreetTraversalPermission.ALL; import static org.opentripplanner.street.model.StreetTraversalPermission.CAR; @@ -163,6 +164,12 @@ else if (speedLimit <= 16.65f) { props.setProperties("highway=service;tunnel=yes;access=destination", withModes(NONE)); props.setProperties("highway=service;access=destination", withModes(ALL).bicycleSafety(1.1)); + // Typically if this tag is used on a way, there is also a better option for walking. + // We don't need to set bicycle safety as cycling is not currently allowed on these ways. + props.setMixinProperties("bicycle=use_sidepath", ofWalkSafety(5)); + + props.setMixinProperties("foot=use_sidepath", ofWalkSafety(8)); + // Automobile speeds in Finland. // General speed limit is 80kph unless signs says otherwise. props.defaultCarSpeed = 22.22f; diff --git a/src/test/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapperTest.java b/src/test/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapperTest.java index a2f84873f20..ca3c059db51 100644 --- a/src/test/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapperTest.java +++ b/src/test/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapperTest.java @@ -162,6 +162,13 @@ public void testSafetyWithMixins() { wps.getDataForWay(wayWithMixinsAndCustomSafety).walkSafety().forward(), epsilon ); + + OSMWithTags wayWithBicycleSidePath = new OSMWithTags(); + wayWithBicycleSidePath.addTag("bicycle", "use_sidepath"); + assertEquals(8, wps.getDataForWay(wayWithBicycleSidePath).walkSafety().forward(), epsilon); + OSMWithTags wayWithFootSidePath = new OSMWithTags(); + wayWithFootSidePath.addTag("foot", "use_sidepath"); + assertEquals(12.8, wps.getDataForWay(wayWithFootSidePath).walkSafety().forward(), epsilon); } @Test From 1a05817acce744d027acacbf523db931f956c355 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 Apr 2024 18:17:45 +0000 Subject: [PATCH 044/121] Update jersey monorepo to v3.1.6 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ea68258aeed..6777893e2be 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 31.0 2.51 2.17.0 - 3.1.5 + 3.1.6 5.10.2 1.12.3 5.5.3 From 5871882a3b15a0d54bf7d4c5416fc13c6468e981 Mon Sep 17 00:00:00 2001 From: Vincent Paturet Date: Mon, 8 Apr 2024 11:37:22 +0200 Subject: [PATCH 045/121] Fix trip duplication in DSJ mapping --- .../opentripplanner/netex/mapping/TripPatternMapper.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapper.java b/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapper.java index 765a9b5c47f..d16cd71f103 100644 --- a/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapper.java +++ b/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapper.java @@ -392,9 +392,12 @@ private Trip mapTrip( JourneyPattern_VersionStructure journeyPattern, ServiceJourney serviceJourney ) { - return tripMapper.mapServiceJourney( - serviceJourney, - () -> findTripHeadsign(journeyPattern, serviceJourney) + return deduplicator.deduplicateObject( + Trip.class, + tripMapper.mapServiceJourney( + serviceJourney, + () -> findTripHeadsign(journeyPattern, serviceJourney) + ) ); } From da3271691eef87c49b60e8ee7aa29e30d1a14b71 Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Tue, 9 Apr 2024 09:00:22 +0000 Subject: [PATCH 046/121] Add changelog entry for #5789 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index e68122c6f07..021fe4b76de 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,6 +9,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Fix street routing on roundabout [#5732](https://github.com/opentripplanner/OpenTripPlanner/pull/5732) - Expose route sort order in GTFS API [#5764](https://github.com/opentripplanner/OpenTripPlanner/pull/5764) - Fix issue with cancellations on trip patterns that run after midnight [#5719](https://github.com/opentripplanner/OpenTripPlanner/pull/5719) +- Fix handling of null transport mode filter [#5789](https://github.com/opentripplanner/OpenTripPlanner/pull/5789) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.5.0 (2024-03-13) From f5c51bcd2c1c104d4acea620ab60c91a65d23053 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 9 Apr 2024 11:41:45 +0200 Subject: [PATCH 047/121] Add comment about moving constant --- .../graph_builder/module/ned/ElevationModule.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java b/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java index e224d1d6d0b..d0fc6da5adf 100644 --- a/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java +++ b/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java @@ -62,10 +62,17 @@ public class ElevationModule implements GraphBuilderModule { private static final Logger LOG = LoggerFactory.getLogger(ElevationModule.class); - /** A shared copy of the WGS84 CRS with longitude-first axis order. */ + /** + * A shared copy of the WGS84 CRS with longitude-first axis order. This constant used + * to be defined in a shared utility class but since it's slow to initialize, it was move here. + * See https://github.com/opentripplanner/OpenTripPlanner/pull/5786 + * */ private static final CoordinateReferenceSystem WGS84_XY; static { + // looking up the CRS is surprisingly expensive (~500ms) and should therefore not done + // in shared utility class + // https://github.com/opentripplanner/OpenTripPlanner/pull/5786 try { WGS84_XY = CRS.getAuthorityFactory(true).createCoordinateReferenceSystem("EPSG:4326"); } catch (Exception ex) { From 9e1bd4d5f851065f45fdf856f0c02433312464b5 Mon Sep 17 00:00:00 2001 From: Vincent Paturet Date: Tue, 9 Apr 2024 13:08:10 +0200 Subject: [PATCH 048/121] Fix typo --- .../opentripplanner/netex/mapping/TripPatternMapper.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapper.java b/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapper.java index d16cd71f103..740224b4489 100644 --- a/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapper.java +++ b/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapper.java @@ -67,7 +67,7 @@ class TripPatternMapper { private final ReadOnlyHierarchicalMap routeById; - private final Multimap serviceJourniesByPatternId = ArrayListMultimap.create(); + private final Multimap serviceJourneysByPatternId = ArrayListMultimap.create(); private final ReadOnlyHierarchicalMapById operatingDayById; @@ -152,12 +152,12 @@ class TripPatternMapper { this.serviceJourneyById = serviceJourneyById; // Index service journey by pattern id for (ServiceJourney sj : serviceJourneyById.localValues()) { - this.serviceJourniesByPatternId.put(sj.getJourneyPatternRef().getValue().getRef(), sj); + this.serviceJourneysByPatternId.put(sj.getJourneyPatternRef().getValue().getRef(), sj); } } Optional mapTripPattern(JourneyPattern_VersionStructure journeyPattern) { - Collection serviceJourneys = serviceJourniesByPatternId.get( + Collection serviceJourneys = serviceJourneysByPatternId.get( journeyPattern.getId() ); From 3a7a418c2b73b9df556a097a5adce6fb28ba36a5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 9 Apr 2024 14:14:44 +0200 Subject: [PATCH 049/121] Update src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java Co-authored-by: Andrew Byrd --- .../graph_builder/module/ned/ElevationModule.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java b/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java index d0fc6da5adf..288d41db73b 100644 --- a/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java +++ b/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java @@ -63,16 +63,15 @@ public class ElevationModule implements GraphBuilderModule { private static final Logger LOG = LoggerFactory.getLogger(ElevationModule.class); /** - * A shared copy of the WGS84 CRS with longitude-first axis order. This constant used - * to be defined in a shared utility class but since it's slow to initialize, it was move here. - * See https://github.com/opentripplanner/OpenTripPlanner/pull/5786 - * */ + * The WGS84 CRS with longitude-first axis order. The first time a CRS lookup is + * performed is surprisingly expensive (around 500ms), apparently due to initializing + * an HSQLDB JDBC connection. For this reason, the constant is defined in this + * narrower scope rather than a shared utility class, where it was seen to incur the + * initialization cost in a broader range of tests than is necessary. + */ private static final CoordinateReferenceSystem WGS84_XY; static { - // looking up the CRS is surprisingly expensive (~500ms) and should therefore not done - // in shared utility class - // https://github.com/opentripplanner/OpenTripPlanner/pull/5786 try { WGS84_XY = CRS.getAuthorityFactory(true).createCoordinateReferenceSystem("EPSG:4326"); } catch (Exception ex) { From 70bb4ee955197f8063aee6b943bdd666eb616d36 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 9 Apr 2024 14:46:30 +0200 Subject: [PATCH 050/121] Fix formatting --- .../graph_builder/module/ned/ElevationModule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java b/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java index 288d41db73b..6bcab049bd4 100644 --- a/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java +++ b/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java @@ -63,9 +63,9 @@ public class ElevationModule implements GraphBuilderModule { private static final Logger LOG = LoggerFactory.getLogger(ElevationModule.class); /** - * The WGS84 CRS with longitude-first axis order. The first time a CRS lookup is + * The WGS84 CRS with longitude-first axis order. The first time a CRS lookup is * performed is surprisingly expensive (around 500ms), apparently due to initializing - * an HSQLDB JDBC connection. For this reason, the constant is defined in this + * an HSQLDB JDBC connection. For this reason, the constant is defined in this * narrower scope rather than a shared utility class, where it was seen to incur the * initialization cost in a broader range of tests than is necessary. */ From 9d764b1d807e80e0c013b8bd8196d9c732624bc2 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 9 Apr 2024 15:32:17 +0200 Subject: [PATCH 051/121] Upgrade Codecov action and use token --- .github/workflows/cibuild.yml | 4 +++- .github/workflows/performance-test.yml | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cibuild.yml b/.github/workflows/cibuild.yml index 5a48da6bc44..2853c7ee00b 100644 --- a/.github/workflows/cibuild.yml +++ b/.github/workflows/cibuild.yml @@ -51,9 +51,11 @@ jobs: - name: Send coverage data to codecov.io if: github.repository_owner == 'opentripplanner' - uses: codecov/codecov-action@v3.1.1 + uses: codecov/codecov-action@v4 with: files: target/site/jacoco/jacoco.xml + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true - name: Deploy to Github Package Registry if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev-1.x' || github.ref == 'refs/heads/dev-2.x') diff --git a/.github/workflows/performance-test.yml b/.github/workflows/performance-test.yml index 1b8201a01ae..60b3e69610d 100644 --- a/.github/workflows/performance-test.yml +++ b/.github/workflows/performance-test.yml @@ -75,7 +75,7 @@ jobs: - name: Set up Maven if: matrix.profile == 'core' || github.ref == 'refs/heads/dev-2.x' - uses: stCarolas/setup-maven@v.4.5 + uses: stCarolas/setup-maven@v5 with: maven-version: 3.8.2 @@ -102,7 +102,7 @@ jobs: - name: Archive travel results file if: matrix.profile == 'core' || github.ref == 'refs/heads/dev-2.x' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ matrix.location }}-travelSearch-results.csv path: test/performance/${{ matrix.location }}/travelSearch-results.csv From bf11e9f916be86d5e903d10129a1874bac57c612 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Tue, 9 Apr 2024 17:06:24 +0300 Subject: [PATCH 052/121] Don't back cycling on use_sidepath and apply safety values in default mapper --- .../openstreetmap/model/OSMWay.java | 26 -------- .../openstreetmap/model/OSMWithTags.java | 8 +-- .../tagmapping/DefaultMapper.java | 3 + .../tagmapping/FinlandMapper.java | 2 - .../openstreetmap/model/OSMWayTest.java | 15 ----- .../openstreetmap/model/OSMWithTagsTest.java | 2 +- .../tagmapping/DefaultMapperTest.java | 42 +++++++++++++ .../tagmapping/FinlandMapperTest.java | 2 +- .../wayproperty/WayPropertySetTest.java | 59 ------------------- 9 files changed, 49 insertions(+), 110 deletions(-) diff --git a/src/main/java/org/opentripplanner/openstreetmap/model/OSMWay.java b/src/main/java/org/opentripplanner/openstreetmap/model/OSMWay.java index 1ce6c698f22..6e610f99fa3 100644 --- a/src/main/java/org/opentripplanner/openstreetmap/model/OSMWay.java +++ b/src/main/java/org/opentripplanner/openstreetmap/model/OSMWay.java @@ -105,20 +105,6 @@ public boolean isOneWayReverseBicycle() { return "-1".equals(oneWayBicycle) || isTagFalse("bicycle:forward"); } - /** - * Returns true if bikes must use sidepath in forward direction - */ - public boolean isForwardDirectionSidepath() { - return "use_sidepath".equals(getTag("bicycle:forward")); - } - - /** - * Returns true if bikes must use sidepath in reverse direction - */ - public boolean isReverseDirectionSidepath() { - return "use_sidepath".equals(getTag("bicycle:backward")); - } - /** * Some cycleways allow contraflow biking. */ @@ -184,18 +170,6 @@ public StreetTraversalPermissionPair splitPermissions(StreetTraversalPermission } } - //This needs to be after adding permissions for oneway:bicycle=no - //removes bicycle permission when bicycles need to use sidepath - //TAG: bicycle:forward=use_sidepath - if (isForwardDirectionSidepath()) { - permissionsFront = permissionsFront.remove(StreetTraversalPermission.BICYCLE); - } - - //TAG bicycle:backward=use_sidepath - if (isReverseDirectionSidepath()) { - permissionsBack = permissionsBack.remove(StreetTraversalPermission.BICYCLE); - } - if (isOpposableCycleway()) { permissionsBack = permissionsBack.add(StreetTraversalPermission.BICYCLE); } diff --git a/src/main/java/org/opentripplanner/openstreetmap/model/OSMWithTags.java b/src/main/java/org/opentripplanner/openstreetmap/model/OSMWithTags.java index 37757823362..e5feda76bc5 100644 --- a/src/main/java/org/opentripplanner/openstreetmap/model/OSMWithTags.java +++ b/src/main/java/org/opentripplanner/openstreetmap/model/OSMWithTags.java @@ -391,14 +391,10 @@ public boolean isVehicleExplicitlyAllowed() { /** * Returns true if bikes are explicitly denied access. *

- * bicycle is denied if bicycle:no, bicycle:dismount, bicycle:license or bicycle:use_sidepath + * bicycle is denied if bicycle:no, bicycle:dismount or bicycle:license. */ public boolean isBicycleExplicitlyDenied() { - return ( - isTagDeniedAccess("bicycle") || - "dismount".equals(getTag("bicycle")) || - "use_sidepath".equals(getTag("bicycle")) - ); + return (isTagDeniedAccess("bicycle") || "dismount".equals(getTag("bicycle"))); } /** diff --git a/src/main/java/org/opentripplanner/openstreetmap/tagmapping/DefaultMapper.java b/src/main/java/org/opentripplanner/openstreetmap/tagmapping/DefaultMapper.java index 1463313203d..9989c102030 100644 --- a/src/main/java/org/opentripplanner/openstreetmap/tagmapping/DefaultMapper.java +++ b/src/main/java/org/opentripplanner/openstreetmap/tagmapping/DefaultMapper.java @@ -624,6 +624,9 @@ public void populateProperties(WayPropertySet props) { props.setMixinProperties("foot=discouraged", ofWalkSafety(3)); props.setMixinProperties("bicycle=discouraged", ofBicycleSafety(3)); + props.setMixinProperties("foot=use_sidepath", ofWalkSafety(5)); + props.setMixinProperties("bicycle=use_sidepath", ofBicycleSafety(5)); + populateNotesAndNames(props); // slope overrides diff --git a/src/main/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapper.java b/src/main/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapper.java index c42b8016d45..5ea949e8d5c 100644 --- a/src/main/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapper.java +++ b/src/main/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapper.java @@ -168,8 +168,6 @@ else if (speedLimit <= 16.65f) { // We don't need to set bicycle safety as cycling is not currently allowed on these ways. props.setMixinProperties("bicycle=use_sidepath", ofWalkSafety(5)); - props.setMixinProperties("foot=use_sidepath", ofWalkSafety(8)); - // Automobile speeds in Finland. // General speed limit is 80kph unless signs says otherwise. props.defaultCarSpeed = 22.22f; diff --git a/src/test/java/org/opentripplanner/openstreetmap/model/OSMWayTest.java b/src/test/java/org/opentripplanner/openstreetmap/model/OSMWayTest.java index c316793ad8c..c0af4cf2701 100644 --- a/src/test/java/org/opentripplanner/openstreetmap/model/OSMWayTest.java +++ b/src/test/java/org/opentripplanner/openstreetmap/model/OSMWayTest.java @@ -92,21 +92,6 @@ void testIsOneWayBicycle() { assertTrue(way.isOneWayReverseBicycle()); } - @Test - void testIsOneDirectionSidepath() { - OSMWay way = new OSMWay(); - assertFalse(way.isForwardDirectionSidepath()); - assertFalse(way.isReverseDirectionSidepath()); - - way.addTag("bicycle:forward", "use_sidepath"); - assertTrue(way.isForwardDirectionSidepath()); - assertFalse(way.isReverseDirectionSidepath()); - - way.addTag("bicycle:backward", "use_sidepath"); - assertTrue(way.isForwardDirectionSidepath()); - assertTrue(way.isReverseDirectionSidepath()); - } - @Test void testIsOpposableCycleway() { OSMWay way = new OSMWay(); diff --git a/src/test/java/org/opentripplanner/openstreetmap/model/OSMWithTagsTest.java b/src/test/java/org/opentripplanner/openstreetmap/model/OSMWithTagsTest.java index ca5db77df12..aefd287cac8 100644 --- a/src/test/java/org/opentripplanner/openstreetmap/model/OSMWithTagsTest.java +++ b/src/test/java/org/opentripplanner/openstreetmap/model/OSMWithTagsTest.java @@ -136,7 +136,7 @@ void testBicycleDenied() { assertFalse(tags.isBicycleExplicitlyDenied(), "bicycle=" + allowedValue); } - for (var deniedValue : List.of("no", "dismount", "license", "use_sidepath")) { + for (var deniedValue : List.of("no", "dismount", "license")) { tags.addTag("bicycle", deniedValue); assertTrue(tags.isBicycleExplicitlyDenied(), "bicycle=" + deniedValue); } diff --git a/src/test/java/org/opentripplanner/openstreetmap/tagmapping/DefaultMapperTest.java b/src/test/java/org/opentripplanner/openstreetmap/tagmapping/DefaultMapperTest.java index 9a16f6a8e2e..2a8988dda61 100644 --- a/src/test/java/org/opentripplanner/openstreetmap/tagmapping/DefaultMapperTest.java +++ b/src/test/java/org/opentripplanner/openstreetmap/tagmapping/DefaultMapperTest.java @@ -147,6 +147,48 @@ void bicycleDiscouraged() { assertEquals(2.94, discouragedProps.bicycleSafety().forward(), epsilon); } + @Test + void footUseSidepath() { + var regular = WayTestData.pedestrianTunnel(); + var props = wps.getDataForWay(regular); + assertEquals(PEDESTRIAN_AND_BICYCLE, props.getPermission()); + assertEquals(1, props.walkSafety().forward()); + + var useSidepath = WayTestData.pedestrianTunnel().addTag("foot", "use_sidepath"); + var useSidepathProps = wps.getDataForWay(useSidepath); + assertEquals(PEDESTRIAN_AND_BICYCLE, useSidepathProps.getPermission()); + assertEquals(5, useSidepathProps.walkSafety().forward()); + } + + @Test + void bicycleUseSidepath() { + var regular = WayTestData.southeastLaBonitaWay(); + var props = wps.getDataForWay(regular); + assertEquals(ALL, props.getPermission()); + assertEquals(.98, props.bicycleSafety().forward()); + + var useSidepath = WayTestData.southeastLaBonitaWay().addTag("bicycle", "use_sidepath"); + var useSidepathProps = wps.getDataForWay(useSidepath); + assertEquals(ALL, useSidepathProps.getPermission()); + assertEquals(4.9, useSidepathProps.bicycleSafety().forward(), epsilon); + + var useSidepathForward = WayTestData + .southeastLaBonitaWay() + .addTag("bicycle:forward", "use_sidepath"); + var useSidepathForwardProps = wps.getDataForWay(useSidepathForward); + assertEquals(ALL, useSidepathForwardProps.getPermission()); + assertEquals(4.9, useSidepathForwardProps.bicycleSafety().forward(), epsilon); + assertEquals(0.98, useSidepathForwardProps.bicycleSafety().back(), epsilon); + + var useSidepathBackward = WayTestData + .southeastLaBonitaWay() + .addTag("bicycle:backward", "use_sidepath"); + var useSidepathBackwardProps = wps.getDataForWay(useSidepathBackward); + assertEquals(ALL, useSidepathBackwardProps.getPermission()); + assertEquals(0.98, useSidepathBackwardProps.bicycleSafety().forward(), epsilon); + assertEquals(4.9, useSidepathBackwardProps.bicycleSafety().back(), epsilon); + } + /** * Test that two values are within epsilon of each other. */ diff --git a/src/test/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapperTest.java b/src/test/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapperTest.java index ca3c059db51..4dd52195acb 100644 --- a/src/test/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapperTest.java +++ b/src/test/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapperTest.java @@ -168,7 +168,7 @@ public void testSafetyWithMixins() { assertEquals(8, wps.getDataForWay(wayWithBicycleSidePath).walkSafety().forward(), epsilon); OSMWithTags wayWithFootSidePath = new OSMWithTags(); wayWithFootSidePath.addTag("foot", "use_sidepath"); - assertEquals(12.8, wps.getDataForWay(wayWithFootSidePath).walkSafety().forward(), epsilon); + assertEquals(8, wps.getDataForWay(wayWithFootSidePath).walkSafety().forward(), epsilon); } @Test diff --git a/src/test/java/org/opentripplanner/openstreetmap/wayproperty/WayPropertySetTest.java b/src/test/java/org/opentripplanner/openstreetmap/wayproperty/WayPropertySetTest.java index e8f5b6e51d3..24360539b6f 100644 --- a/src/test/java/org/opentripplanner/openstreetmap/wayproperty/WayPropertySetTest.java +++ b/src/test/java/org/opentripplanner/openstreetmap/wayproperty/WayPropertySetTest.java @@ -256,65 +256,6 @@ void testMotorVehicleTagDeniedPermissions() { assertTrue(permissionPair.main().allowsNothing());*/ } - @Test - void testSidepathPermissions() { - OSMWay way = new OSMWay(); - way.addTag("bicycle", "use_sidepath"); - way.addTag("highway", "primary"); - way.addTag("lanes", "2"); - way.addTag("maxspeed", "70"); - way.addTag("oneway", "yes"); - var permissionPair = getWayProperties(way); - - assertFalse(permissionPair.main().allows(StreetTraversalPermission.BICYCLE)); - assertFalse(permissionPair.back().allows(StreetTraversalPermission.BICYCLE)); - - assertTrue(permissionPair.main().allows(StreetTraversalPermission.CAR)); - assertFalse(permissionPair.back().allows(StreetTraversalPermission.CAR)); - - way = new OSMWay(); - way.addTag("bicycle:forward", "use_sidepath"); - way.addTag("highway", "tertiary"); - permissionPair = getWayProperties(way); - - assertFalse(permissionPair.main().allows(StreetTraversalPermission.BICYCLE)); - assertTrue(permissionPair.back().allows(StreetTraversalPermission.BICYCLE)); - - assertTrue(permissionPair.main().allows(StreetTraversalPermission.CAR)); - assertTrue(permissionPair.back().allows(StreetTraversalPermission.CAR)); - - way = new OSMWay(); - way.addTag("bicycle:backward", "use_sidepath"); - way.addTag("highway", "tertiary"); - permissionPair = getWayProperties(way); - - assertTrue(permissionPair.main().allows(StreetTraversalPermission.BICYCLE)); - assertFalse(permissionPair.back().allows(StreetTraversalPermission.BICYCLE)); - - assertTrue(permissionPair.main().allows(StreetTraversalPermission.CAR)); - assertTrue(permissionPair.back().allows(StreetTraversalPermission.CAR)); - - way = new OSMWay(); - way.addTag("highway", "tertiary"); - way.addTag("oneway", "yes"); - way.addTag("oneway:bicycle", "no"); - permissionPair = getWayProperties(way); - - assertTrue(permissionPair.main().allows(StreetTraversalPermission.BICYCLE)); - assertTrue(permissionPair.back().allows(StreetTraversalPermission.BICYCLE)); - - assertTrue(permissionPair.main().allows(StreetTraversalPermission.CAR)); - assertFalse(permissionPair.back().allows(StreetTraversalPermission.CAR)); - - way.addTag("bicycle:forward", "use_sidepath"); - permissionPair = getWayProperties(way); - assertFalse(permissionPair.main().allows(StreetTraversalPermission.BICYCLE)); - assertTrue(permissionPair.back().allows(StreetTraversalPermission.BICYCLE)); - - assertTrue(permissionPair.main().allows(StreetTraversalPermission.CAR)); - assertFalse(permissionPair.back().allows(StreetTraversalPermission.CAR)); - } - private StreetTraversalPermissionPair getWayProperties(OSMWay way) { WayPropertySet wayPropertySet = new WayPropertySet(); WayProperties wayData = wayPropertySet.getDataForWay(way); From 1896c9991955cabe5332bc3e4cde736042f463a0 Mon Sep 17 00:00:00 2001 From: Vincent Paturet Date: Tue, 9 Apr 2024 16:12:31 +0200 Subject: [PATCH 053/121] Added unit test --- .../netex/mapping/NetexTestDataSample.java | 21 +++- .../netex/mapping/TripPatternMapperTest.java | 111 ++++++++++++++---- 2 files changed, 104 insertions(+), 28 deletions(-) diff --git a/src/test/java/org/opentripplanner/netex/mapping/NetexTestDataSample.java b/src/test/java/org/opentripplanner/netex/mapping/NetexTestDataSample.java index b8723fdbcf3..b72c9b05277 100644 --- a/src/test/java/org/opentripplanner/netex/mapping/NetexTestDataSample.java +++ b/src/test/java/org/opentripplanner/netex/mapping/NetexTestDataSample.java @@ -40,6 +40,7 @@ import org.rutebanken.netex.model.ScheduledStopPointRefStructure; import org.rutebanken.netex.model.ServiceAlterationEnumeration; import org.rutebanken.netex.model.ServiceJourney; +import org.rutebanken.netex.model.ServiceJourneyRefStructure; import org.rutebanken.netex.model.StopPointInJourneyPattern; import org.rutebanken.netex.model.StopPointInJourneyPatternRefStructure; import org.rutebanken.netex.model.TimetabledPassingTime; @@ -50,9 +51,11 @@ public class NetexTestDataSample { public static final String SERVICE_JOURNEY_ID = "RUT:ServiceJourney:1"; + public static final String DATED_SERVICE_JOURNEY_ID_1 = "RUT:DatedServiceJourney:1"; + public static final String DATED_SERVICE_JOURNEY_ID_2 = "RUT:DatedServiceJourney:2"; public static final List DATED_SERVICE_JOURNEY_ID = List.of( - "RUT:DatedServiceJourney:1", - "RUT:DatedServiceJourney:2" + DATED_SERVICE_JOURNEY_ID_1, + DATED_SERVICE_JOURNEY_ID_2 ); public static final List OPERATING_DAYS = List.of("2022-02-28", "2022-02-29"); private static final DayType EVERYDAY = new DayType() @@ -174,6 +177,11 @@ public NetexTestDataSample() { DatedServiceJourney datedServiceJourney = new DatedServiceJourney() .withId(DATED_SERVICE_JOURNEY_ID.get(i)) + .withJourneyRef( + List.of( + MappingSupport.createWrappedRef(SERVICE_JOURNEY_ID, ServiceJourneyRefStructure.class) + ) + ) .withServiceAlteration(ServiceAlterationEnumeration.PLANNED) .withOperatingDayRef(new OperatingDayRefStructure().withRef(operatingDay.getId())); @@ -218,6 +226,15 @@ public HierarchicalMapById getServiceJourneyById() { return serviceJourneyById; } + public DatedServiceJourney getDatedServiceJourneyById(String id) { + return datedServiceJourneyBySjId + .values() + .stream() + .filter(datedServiceJourney -> datedServiceJourney.getId().equals(id)) + .findFirst() + .orElse(null); + } + public ServiceJourney getServiceJourney() { return serviceJourneyById.lookup(SERVICE_JOURNEY_ID); } diff --git a/src/test/java/org/opentripplanner/netex/mapping/TripPatternMapperTest.java b/src/test/java/org/opentripplanner/netex/mapping/TripPatternMapperTest.java index 74448fb3638..95af8f623e5 100644 --- a/src/test/java/org/opentripplanner/netex/mapping/TripPatternMapperTest.java +++ b/src/test/java/org/opentripplanner/netex/mapping/TripPatternMapperTest.java @@ -1,9 +1,12 @@ package org.opentripplanner.netex.mapping; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; import com.google.common.collect.ArrayListMultimap; +import java.util.List; import java.util.Map; import java.util.Optional; import org.junit.jupiter.api.Test; @@ -19,17 +22,19 @@ import org.opentripplanner.transit.model.timetable.TripOnServiceDate; import org.opentripplanner.transit.model.timetable.TripTimes; import org.rutebanken.netex.model.DatedServiceJourney; +import org.rutebanken.netex.model.DatedServiceJourneyRefStructure; import org.rutebanken.netex.model.OperatingDay; +import org.rutebanken.netex.model.ServiceAlterationEnumeration; /** * @author Thomas Gran (Capra) - tgr@capraconsulting.no (29.11.2017) */ -public class TripPatternMapperTest { +class TripPatternMapperTest { private static final FeedScopedId SERVICE_ID = TransitModelForTest.id("S01"); @Test - public void testMapTripPattern() { + void testMapTripPattern() { NetexTestDataSample sample = new NetexTestDataSample(); TripPatternMapper tripPatternMapper = new TripPatternMapper( @@ -88,9 +93,85 @@ public void testMapTripPattern() { } @Test - public void testMapTripPattern_datedServiceJourney() { + void testMapTripPattern_datedServiceJourney() { NetexTestDataSample sample = new NetexTestDataSample(); + Optional res = mapTripPattern(sample); + assertTrue(res.isPresent()); + + var r = res.get(); + + assertEquals(2, r.tripOnServiceDates().size()); + + Trip trip = r.tripPattern().scheduledTripsAsStream().findFirst().get(); + + for (TripOnServiceDate tripOnServiceDate : r.tripOnServiceDates()) { + assertEquals(trip, tripOnServiceDate.getTrip()); + assertEquals(TripAlteration.PLANNED, tripOnServiceDate.getTripAlteration()); + assertEquals( + 1, + sample + .getOperatingDaysById() + .localValues() + .stream() + .map(OperatingDay::getId) + .filter(id -> id.equals(tripOnServiceDate.getServiceDate().toString())) + .count() + ); + } + } + + @Test + void testDatedServiceJourneyReplacement() { + NetexTestDataSample sample = new NetexTestDataSample(); + DatedServiceJourney dsjReplaced = sample.getDatedServiceJourneyById( + NetexTestDataSample.DATED_SERVICE_JOURNEY_ID_1 + ); + dsjReplaced.setServiceAlteration(ServiceAlterationEnumeration.REPLACED); + DatedServiceJourney dsjReplacing = sample.getDatedServiceJourneyById( + NetexTestDataSample.DATED_SERVICE_JOURNEY_ID_2 + ); + dsjReplacing.withJourneyRef( + List.of( + MappingSupport.createWrappedRef(dsjReplaced.getId(), DatedServiceJourneyRefStructure.class) + ) + ); + Optional res = mapTripPattern(sample); + + assertTrue(res.isPresent()); + var r = res.get(); + Optional replacedTripOnServiceDate = r + .tripOnServiceDates() + .stream() + .filter(tripOnServiceDate -> + NetexTestDataSample.DATED_SERVICE_JOURNEY_ID_1.equals(tripOnServiceDate.getId().getId()) + ) + .findFirst(); + + assertTrue(replacedTripOnServiceDate.isPresent()); + assertEquals(TripAlteration.REPLACED, replacedTripOnServiceDate.get().getTripAlteration()); + + Optional replacingTripOnServiceDate = r + .tripOnServiceDates() + .stream() + .filter(tripOnServiceDate -> + NetexTestDataSample.DATED_SERVICE_JOURNEY_ID_2.equals(tripOnServiceDate.getId().getId()) + ) + .findFirst(); + + assertTrue(replacingTripOnServiceDate.isPresent()); + assertEquals(TripAlteration.PLANNED, replacingTripOnServiceDate.get().getTripAlteration()); + assertFalse(replacingTripOnServiceDate.get().getReplacementFor().isEmpty()); + + // the replaced trip should refer to the same object (object identity) whether it is accessed + // directly from the replaced DSJ or indirectly through the replacing DSJ. + assertSame( + replacingTripOnServiceDate.get().getReplacementFor().getFirst().getTrip(), + replacedTripOnServiceDate.get().getTrip() + ); + } + + private static Optional mapTripPattern(NetexTestDataSample sample) { HierarchicalMapById datedServiceJourneys = new HierarchicalMapById<>(); datedServiceJourneys.addAll(sample.getDatedServiceJourneyBySjId().values()); @@ -121,28 +202,6 @@ public void testMapTripPattern_datedServiceJourney() { Optional res = tripPatternMapper.mapTripPattern( sample.getJourneyPattern() ); - - assertTrue(res.isPresent()); - - var r = res.get(); - - assertEquals(2, r.tripOnServiceDates().size()); - - Trip trip = r.tripPattern().scheduledTripsAsStream().findFirst().get(); - - for (TripOnServiceDate tripOnServiceDate : r.tripOnServiceDates()) { - assertEquals(trip, tripOnServiceDate.getTrip()); - assertEquals(TripAlteration.PLANNED, tripOnServiceDate.getTripAlteration()); - assertEquals( - 1, - sample - .getOperatingDaysById() - .localValues() - .stream() - .map(OperatingDay::getId) - .filter(id -> id.equals(tripOnServiceDate.getServiceDate().toString())) - .count() - ); - } + return res; } } From 05640381726c9ec7a7d122c2960a8e6752d91949 Mon Sep 17 00:00:00 2001 From: Bastian Silies Date: Tue, 9 Apr 2024 17:26:00 +0200 Subject: [PATCH 054/121] extract ferry-check --- .../module/islandpruning/PruneIslands.java | 17 +-- .../module/islandpruning/Subgraph.java | 27 +++- .../islandpruning/SubgraphOnlyFerryTest.java | 125 ++++++++++++++++++ 3 files changed, 151 insertions(+), 18 deletions(-) create mode 100644 src/test/java/org/opentripplanner/graph_builder/module/islandpruning/SubgraphOnlyFerryTest.java diff --git a/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/PruneIslands.java b/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/PruneIslands.java index ff88bebaa45..26349c0d803 100644 --- a/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/PruneIslands.java +++ b/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/PruneIslands.java @@ -10,7 +10,6 @@ import java.util.List; import java.util.Map; import java.util.Queue; -import java.util.Set; import java.util.stream.Collectors; import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.graph_builder.issues.GraphConnectivity; @@ -33,7 +32,6 @@ import org.opentripplanner.street.search.TraverseMode; import org.opentripplanner.street.search.request.StreetSearchRequest; import org.opentripplanner.street.search.state.State; -import org.opentripplanner.transit.model.basic.TransitMode; import org.opentripplanner.transit.service.TransitModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -252,16 +250,7 @@ private int processIslands( if (island.stopSize() > 0) { //for islands with stops islandsWithStops++; - boolean onlyFerry = true; - for (Iterator vIter = island.stopIterator(); vIter.hasNext();) { - TransitStopVertex v = (TransitStopVertex) vIter.next(); - Set modes = v.getModes(); - // test if stop has other transit modes than FERRY - if (modes.isEmpty() || !modes.contains(TransitMode.FERRY)) { - onlyFerry = false; - break; - } - } + boolean onlyFerry = island.hasOnlyFerryStops(); // do not remove real islands which have only ferry stops if (!onlyFerry && island.streetSize() < pruningThresholdWithStops * adaptivePruningFactor) { double sizeCoeff = (adaptivePruningFactor > 1.0) @@ -487,8 +476,8 @@ private boolean restrictOrRemove( // note: do not unlink stop if only CAR mode is pruned // maybe this needs more logic for flex routing cases List stopLabels = new ArrayList<>(); - for (Iterator vIter = island.stopIterator(); vIter.hasNext();) { - Vertex v = vIter.next(); + for (Iterator vIter = island.stopIterator(); vIter.hasNext();) { + TransitStopVertex v = vIter.next(); stopLabels.add(v.getLabel()); Collection edges = new ArrayList<>(v.getOutgoing()); edges.addAll(v.getIncoming()); diff --git a/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/Subgraph.java b/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/Subgraph.java index 019c1c12a19..8678f1700e2 100644 --- a/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/Subgraph.java +++ b/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/Subgraph.java @@ -17,11 +17,12 @@ import org.opentripplanner.street.model.vertex.OsmVertex; import org.opentripplanner.street.model.vertex.TransitStopVertex; import org.opentripplanner.street.model.vertex.Vertex; +import org.opentripplanner.transit.model.basic.TransitMode; class Subgraph { private final Set streetVertexSet; - private final Set stopsVertexSet; + private final Set stopsVertexSet; Subgraph() { streetVertexSet = new HashSet<>(); @@ -30,7 +31,7 @@ class Subgraph { void addVertex(Vertex vertex) { if (vertex instanceof TransitStopVertex) { - stopsVertexSet.add(vertex); + stopsVertexSet.add((TransitStopVertex) vertex); } else { streetVertexSet.add(vertex); } @@ -64,7 +65,7 @@ Iterator streetIterator() { return streetVertexSet.iterator(); } - Iterator stopIterator() { + Iterator stopIterator() { return stopsVertexSet.iterator(); } @@ -98,7 +99,7 @@ Iterator stopIterator() { Vertex vx = vIter.next(); envelope.expandToInclude(vx.getCoordinate()); } - for (Iterator vIter = stopIterator(); vIter.hasNext();) { + for (Iterator vIter = stopIterator(); vIter.hasNext();) { Vertex vx = vIter.next(); envelope.expandToInclude(vx.getCoordinate()); } @@ -127,4 +128,22 @@ Geometry getGeometry() { return new MultiPoint(points.toArray(new Point[0]), geometryFactory); } + + /** + * Checks whether the subgraph has only transit-stops for ferries + * + * @return true if only ferries stop at the subgraph and false if other or no other modes are + * stopping at the subgraph + */ + boolean hasOnlyFerryStops() { + for (Iterator vIter = this.stopIterator(); vIter.hasNext();) { + TransitStopVertex v = vIter.next(); + Set modes = v.getModes(); + // test if stop has other transit modes than FERRY + if (!modes.contains(TransitMode.FERRY)) { + return false; + } + } + return true; + } } diff --git a/src/test/java/org/opentripplanner/graph_builder/module/islandpruning/SubgraphOnlyFerryTest.java b/src/test/java/org/opentripplanner/graph_builder/module/islandpruning/SubgraphOnlyFerryTest.java new file mode 100644 index 00000000000..e93cfa61815 --- /dev/null +++ b/src/test/java/org/opentripplanner/graph_builder/module/islandpruning/SubgraphOnlyFerryTest.java @@ -0,0 +1,125 @@ +package org.opentripplanner.graph_builder.module.islandpruning; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.Set; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.opentripplanner.street.model.vertex.TransitStopVertex; +import org.opentripplanner.street.model.vertex.TransitStopVertexBuilder; +import org.opentripplanner.transit.model.basic.TransitMode; +import org.opentripplanner.transit.model.framework.FeedScopedId; +import org.opentripplanner.transit.model.site.RegularStop; + +class SubgraphOnlyFerryTest { + + private static RegularStop regularStop1; + private static RegularStop regularStop2; + + @BeforeAll + static void setUp() { + regularStop1 = + RegularStop + .of(new FeedScopedId("HH-GTFS", "TEST1"), () -> 0) + .withCoordinate(53.54948, 9.98455) + .build(); + regularStop2 = + RegularStop + .of(new FeedScopedId("HH-GTFS", "TEST2"), () -> 0) + .withCoordinate(53.55272, 9.99480) + .build(); + } + + @Test + void subgraphHasOnlyFerry() { + TransitStopVertex transitStopVertex = new TransitStopVertexBuilder() + .withStop(regularStop1) + .withModes(Set.of(TransitMode.FERRY)) + .build(); + + Subgraph subgraph = new Subgraph(); + subgraph.addVertex(transitStopVertex); + + assertTrue(subgraph.hasOnlyFerryStops()); + } + + @Test + void subgraphHasOnlyNoFerry() { + TransitStopVertex transitStopVertex1 = new TransitStopVertexBuilder() + .withStop(regularStop1) + .withModes(Set.of(TransitMode.BUS)) + .build(); + + Subgraph subgraph = new Subgraph(); + subgraph.addVertex(transitStopVertex1); + + assertFalse(subgraph.hasOnlyFerryStops()); + } + + @Test + void subgraphHasOnlyNoMode() { + TransitStopVertex transitStopVertex1 = new TransitStopVertexBuilder() + .withStop(regularStop1) + .withModes(Set.of()) + .build(); + + Subgraph subgraph = new Subgraph(); + subgraph.addVertex(transitStopVertex1); + + assertFalse(subgraph.hasOnlyFerryStops()); + } + + @Test + void subgraphHasOnlyFerryMoreStops() { + TransitStopVertex transitStopVertex1 = new TransitStopVertexBuilder() + .withStop(regularStop1) + .withModes(Set.of(TransitMode.FERRY)) + .build(); + TransitStopVertex transitStopVertex2 = new TransitStopVertexBuilder() + .withStop(regularStop2) + .withModes(Set.of(TransitMode.FERRY)) + .build(); + + Subgraph subgraph = new Subgraph(); + subgraph.addVertex(transitStopVertex1); + subgraph.addVertex(transitStopVertex2); + + assertTrue(subgraph.hasOnlyFerryStops()); + } + + @Test + void subgraphHasNotOnlyFerryMoreStops() { + TransitStopVertex transitStopVertex1 = new TransitStopVertexBuilder() + .withStop(regularStop1) + .withModes(Set.of(TransitMode.FERRY)) + .build(); + TransitStopVertex transitStopVertex2 = new TransitStopVertexBuilder() + .withStop(regularStop2) + .withModes(Set.of(TransitMode.BUS)) + .build(); + + Subgraph subgraph = new Subgraph(); + subgraph.addVertex(transitStopVertex1); + subgraph.addVertex(transitStopVertex2); + + assertFalse(subgraph.hasOnlyFerryStops()); + } + + @Test + void subgraphHasNoModeMoreStops() { + TransitStopVertex transitStopVertex1 = new TransitStopVertexBuilder() + .withStop(regularStop1) + .withModes(Set.of(TransitMode.FERRY)) + .build(); + TransitStopVertex transitStopVertex2 = new TransitStopVertexBuilder() + .withStop(regularStop2) + .withModes(Set.of()) + .build(); + + Subgraph subgraph = new Subgraph(); + subgraph.addVertex(transitStopVertex1); + subgraph.addVertex(transitStopVertex2); + + assertFalse(subgraph.hasOnlyFerryStops()); + } +} From ffbacb98306340f88d5caf8361ecbbac1db709ce Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 10 Apr 2024 07:16:38 +0200 Subject: [PATCH 055/121] Finetune renovate automerge config [ci skip] --- renovate.json5 | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/renovate.json5 b/renovate.json5 index 8a7f57e6764..89ff44c60e4 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -46,14 +46,20 @@ // noise, so we slow it down a bit { "matchPackageNames": [ - "org.entur.gbfs:gbfs-java-model", - "ch.qos.logback:logback-classic", - "io.github.git-commit-id:git-commit-id-maven-plugin" + "org.entur.gbfs:gbfs-java-model" ], "matchUpdateTypes": ["patch"], "schedule": "on the 18th day of the month", "automerge": true }, + { + "matchPackageNames": [ + "ch.qos.logback:logback-classic", + "io.github.git-commit-id:git-commit-id-maven-plugin" + ], + "schedule": "on the 19th day of the month", + "automerge": true + }, { // https://github.com/graphql-java-kickstart/renovate-config/blob/main/default.json "description": "GraphQL Java (ignoring snapshot builds)", From 8754908682182c2e33f64a231f965a1526ed1277 Mon Sep 17 00:00:00 2001 From: Vincent Paturet Date: Wed, 10 Apr 2024 08:37:29 +0200 Subject: [PATCH 056/121] Increase log severity for incompatible serialized leg reference --- .../model/plan/legreference/LegReferenceSerializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/opentripplanner/model/plan/legreference/LegReferenceSerializer.java b/src/main/java/org/opentripplanner/model/plan/legreference/LegReferenceSerializer.java index c5c38fd2506..0ceae6cb456 100644 --- a/src/main/java/org/opentripplanner/model/plan/legreference/LegReferenceSerializer.java +++ b/src/main/java/org/opentripplanner/model/plan/legreference/LegReferenceSerializer.java @@ -66,7 +66,7 @@ public static LegReference decode(String legReference) { var type = readEnum(in, LegReferenceType.class); return type.getDeserializer().read(in); } catch (IOException e) { - LOG.info( + LOG.warn( "Unable to decode leg reference (incompatible serialization format): '{}'", legReference, e From 146db257da81fa756b3fa2da1e48d9f4b485f6c7 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 10 Apr 2024 12:12:54 +0200 Subject: [PATCH 057/121] Add matrix badge [ci skip] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 318ed43be31..5e016c22bb2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ ## Overview [![Join the chat at https://gitter.im/opentripplanner/OpenTripPLanner](https://badges.gitter.im/opentripplanner/OpenTripPlanner.svg)](https://gitter.im/opentripplanner/OpenTripPlanner) +[![Matrix](https://img.shields.io/matrix/opentripplanner%3Amatrix.org?label=Matrix%20chat)](https://matrix.to/#/#opentripplanner_OpenTripPlanner:gitter.im) [![codecov](https://codecov.io/gh/opentripplanner/OpenTripPlanner/branch/dev-2.x/graph/badge.svg?token=ak4PbIKgZ1)](https://codecov.io/gh/opentripplanner/OpenTripPlanner) [![Commit activity](https://img.shields.io/github/commit-activity/y/opentripplanner/OpenTripPlanner)](https://github.com/opentripplanner/OpenTripPlanner/graphs/contributors) [![Docker Pulls](https://img.shields.io/docker/pulls/opentripplanner/opentripplanner)](https://hub.docker.com/r/opentripplanner/opentripplanner) From 9309737d1a18934eb8e47ab8c90c3a8e719cacd0 Mon Sep 17 00:00:00 2001 From: Bastian Silies Date: Thu, 11 Apr 2024 14:09:39 +0200 Subject: [PATCH 058/121] refactoring --- .../module/islandpruning/Subgraph.java | 8 +++--- .../islandpruning/SubgraphOnlyFerryTest.java | 25 +++++-------------- 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/Subgraph.java b/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/Subgraph.java index 8678f1700e2..55efe6cb3d8 100644 --- a/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/Subgraph.java +++ b/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/Subgraph.java @@ -99,8 +99,7 @@ Iterator stopIterator() { Vertex vx = vIter.next(); envelope.expandToInclude(vx.getCoordinate()); } - for (Iterator vIter = stopIterator(); vIter.hasNext();) { - Vertex vx = vIter.next(); + for (TransitStopVertex vx : stopsVertexSet) { envelope.expandToInclude(vx.getCoordinate()); } envelope.expandBy(searchRadiusDegrees / xscale, searchRadiusDegrees); @@ -132,12 +131,11 @@ Geometry getGeometry() { /** * Checks whether the subgraph has only transit-stops for ferries * - * @return true if only ferries stop at the subgraph and false if other or no other modes are + * @return true if only ferries stop at the subgraph and false if other or no modes are * stopping at the subgraph */ boolean hasOnlyFerryStops() { - for (Iterator vIter = this.stopIterator(); vIter.hasNext();) { - TransitStopVertex v = vIter.next(); + for (TransitStopVertex v : stopsVertexSet) { Set modes = v.getModes(); // test if stop has other transit modes than FERRY if (!modes.contains(TransitMode.FERRY)) { diff --git a/src/test/java/org/opentripplanner/graph_builder/module/islandpruning/SubgraphOnlyFerryTest.java b/src/test/java/org/opentripplanner/graph_builder/module/islandpruning/SubgraphOnlyFerryTest.java index e93cfa61815..26aaf12896b 100644 --- a/src/test/java/org/opentripplanner/graph_builder/module/islandpruning/SubgraphOnlyFerryTest.java +++ b/src/test/java/org/opentripplanner/graph_builder/module/islandpruning/SubgraphOnlyFerryTest.java @@ -1,34 +1,21 @@ package org.opentripplanner.graph_builder.module.islandpruning; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Set; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.opentripplanner.street.model.vertex.TransitStopVertex; import org.opentripplanner.street.model.vertex.TransitStopVertexBuilder; +import org.opentripplanner.transit.model._data.TransitModelForTest; import org.opentripplanner.transit.model.basic.TransitMode; -import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.site.RegularStop; class SubgraphOnlyFerryTest { - private static RegularStop regularStop1; - private static RegularStop regularStop2; - - @BeforeAll - static void setUp() { - regularStop1 = - RegularStop - .of(new FeedScopedId("HH-GTFS", "TEST1"), () -> 0) - .withCoordinate(53.54948, 9.98455) - .build(); - regularStop2 = - RegularStop - .of(new FeedScopedId("HH-GTFS", "TEST2"), () -> 0) - .withCoordinate(53.55272, 9.99480) - .build(); - } + private static final TransitModelForTest TEST_MODEL = TransitModelForTest.of(); + private static final RegularStop regularStop1 = TEST_MODEL.stop("TEST-1").build(); + private static final RegularStop regularStop2 = TEST_MODEL.stop("TEST-2").build(); @Test void subgraphHasOnlyFerry() { From 69dca4ee82fc7b8fd96c610b176e40d750007841 Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Thu, 11 Apr 2024 12:43:48 +0000 Subject: [PATCH 059/121] Add changelog entry for #5790 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 021fe4b76de..0252f984fb7 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -10,6 +10,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Expose route sort order in GTFS API [#5764](https://github.com/opentripplanner/OpenTripPlanner/pull/5764) - Fix issue with cancellations on trip patterns that run after midnight [#5719](https://github.com/opentripplanner/OpenTripPlanner/pull/5719) - Fix handling of null transport mode filter [#5789](https://github.com/opentripplanner/OpenTripPlanner/pull/5789) +- Discourage instead of ban cycling on use_sidepath ways and do the same for walking on foot=use_sidepath [#5790](https://github.com/opentripplanner/OpenTripPlanner/pull/5790) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.5.0 (2024-03-13) From 8230308f02c8f99e3df7b7419ec4126f312d41ca Mon Sep 17 00:00:00 2001 From: Bastian Silies Date: Thu, 11 Apr 2024 15:26:13 +0200 Subject: [PATCH 060/121] use pattern variable --- .../graph_builder/module/islandpruning/Subgraph.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/Subgraph.java b/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/Subgraph.java index 55efe6cb3d8..94dcfaaf131 100644 --- a/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/Subgraph.java +++ b/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/Subgraph.java @@ -30,8 +30,8 @@ class Subgraph { } void addVertex(Vertex vertex) { - if (vertex instanceof TransitStopVertex) { - stopsVertexSet.add((TransitStopVertex) vertex); + if (vertex instanceof TransitStopVertex transitStopVertex) { + stopsVertexSet.add(transitStopVertex); } else { streetVertexSet.add(vertex); } From bbbe74c9b89bdf75ffc3fd8aa2749b3ace934316 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 11 Apr 2024 18:14:51 +0200 Subject: [PATCH 061/121] Implement hashCode for Money --- .../java/org/opentripplanner/transit/model/basic/Money.java | 5 +++++ .../java/org/opentripplanner/routing/core/MoneyTest.java | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/org/opentripplanner/transit/model/basic/Money.java b/src/main/java/org/opentripplanner/transit/model/basic/Money.java index e44994d1105..35278d8fbd8 100644 --- a/src/main/java/org/opentripplanner/transit/model/basic/Money.java +++ b/src/main/java/org/opentripplanner/transit/model/basic/Money.java @@ -206,4 +206,9 @@ public boolean equals(Object obj) { return false; } } + + @Override + public int hashCode() { + return Objects.hash(currency, amount); + } } diff --git a/src/test/java/org/opentripplanner/routing/core/MoneyTest.java b/src/test/java/org/opentripplanner/routing/core/MoneyTest.java index 5f197708f1d..01392e64493 100644 --- a/src/test/java/org/opentripplanner/routing/core/MoneyTest.java +++ b/src/test/java/org/opentripplanner/routing/core/MoneyTest.java @@ -102,4 +102,9 @@ void greaterThan() { void serializable() { assertInstanceOf(Serializable.class, oneDollar); } + + @Test + void equalHashCode() { + assertEquals(Money.usDollars(5).hashCode(), Money.usDollars(5).hashCode()); + } } From 2bd35ccc869fc1869d968f40cdca71438435f1b1 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 11 Apr 2024 23:43:26 +0200 Subject: [PATCH 062/121] Update GPG plugin less often [ci skip] --- renovate.json5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/renovate.json5 b/renovate.json5 index 89ff44c60e4..d24a1e5cf3f 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -55,7 +55,8 @@ { "matchPackageNames": [ "ch.qos.logback:logback-classic", - "io.github.git-commit-id:git-commit-id-maven-plugin" + "io.github.git-commit-id:git-commit-id-maven-plugin", + "org.apache.maven.plugins:maven-gpg-plugin" ], "schedule": "on the 19th day of the month", "automerge": true @@ -116,7 +117,6 @@ "org.apache.commons:commons-compress", // only used by tests // maven plugins "org.codehaus.mojo:build-helper-maven-plugin", - "org.apache.maven.plugins:maven-gpg-plugin", "org.apache.maven.plugins:maven-source-plugin", "com.hubspot.maven.plugins:prettier-maven-plugin", "com.google.cloud.tools:jib-maven-plugin", From 150170f88e39829e98087a41c9f06a47e15e9dc2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 11 Apr 2024 21:44:29 +0000 Subject: [PATCH 063/121] Update dependency com.tngtech.archunit:archunit to v1.3.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 31f7f72f184..ce9e914e687 100644 --- a/pom.xml +++ b/pom.xml @@ -693,7 +693,7 @@ com.tngtech.archunit archunit - 1.2.1 + 1.3.0 test From b1e26a8c14a190a9f12a8649f7479b160a3c5370 Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Fri, 12 Apr 2024 08:14:42 +0000 Subject: [PATCH 064/121] Add changelog entry for #5782 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 0252f984fb7..206d1b64e7f 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -11,6 +11,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Fix issue with cancellations on trip patterns that run after midnight [#5719](https://github.com/opentripplanner/OpenTripPlanner/pull/5719) - Fix handling of null transport mode filter [#5789](https://github.com/opentripplanner/OpenTripPlanner/pull/5789) - Discourage instead of ban cycling on use_sidepath ways and do the same for walking on foot=use_sidepath [#5790](https://github.com/opentripplanner/OpenTripPlanner/pull/5790) +- Prune islands with mode-less stop vertices [#5782](https://github.com/opentripplanner/OpenTripPlanner/pull/5782) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.5.0 (2024-03-13) From 75e515b464c0bc01f4d0eccb484eac43f0bf785d Mon Sep 17 00:00:00 2001 From: Eivind Morris Bakke Date: Fri, 12 Apr 2024 14:48:35 +0200 Subject: [PATCH 065/121] Overwrites directMode when it is not set in the request. (#5779) Defaulting it to walk when it was not set caused issues when the user expected no results because transportModes are defined. --- .../apis/transmodel/mapping/RequestModesMapper.java | 7 +++---- .../transmodel/mapping/RequestModesMapperTest.java | 11 +++++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapper.java index 59259905944..e7a13dcacc9 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapper.java @@ -15,7 +15,7 @@ class RequestModesMapper { * Maps GraphQL Modes input type to RequestModes. *

* This only maps access, egress, direct & transfer modes. Transport modes are set using filters. - * Default modes are WALK for access, egress, direct & transfer. + * Default modes are WALK for access, egress & transfer. */ static RequestModes mapRequestModes(Map modesInput) { RequestModesBuilder mBuilder = RequestModes.of(); @@ -28,9 +28,8 @@ static RequestModes mapRequestModes(Map modesInput) { if (modesInput.containsKey(egressModeKey)) { mBuilder.withEgressMode((StreetMode) modesInput.get(egressModeKey)); } - if (modesInput.containsKey(directModeKey)) { - mBuilder.withDirectMode((StreetMode) modesInput.get(directModeKey)); - } + // An unset directMode should overwrite the walk default, so we don't check for existence first. + mBuilder.withDirectMode((StreetMode) modesInput.get(directModeKey)); return mBuilder.build(); } diff --git a/src/test/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapperTest.java b/src/test/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapperTest.java index 160014213d3..b8d08c7d7f5 100644 --- a/src/test/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapperTest.java +++ b/src/test/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapperTest.java @@ -13,9 +13,11 @@ class RequestModesMapperTest { void testMapRequestModesEmptyMapReturnsDefaults() { Map inputModes = Map.of(); + RequestModes wantModes = RequestModes.of().withDirectMode(null).build(); + RequestModes mappedModes = RequestModesMapper.mapRequestModes(inputModes); - assertEquals(RequestModes.of().build(), mappedModes); + assertEquals(wantModes, mappedModes); } @Test @@ -26,6 +28,7 @@ void testMapRequestModesAccessSetReturnsDefaultsForOthers() { .of() .withAccessMode(StreetMode.BIKE) .withTransferMode(StreetMode.BIKE) + .withDirectMode(null) .build(); RequestModes mappedModes = RequestModesMapper.mapRequestModes(inputModes); @@ -37,7 +40,11 @@ void testMapRequestModesAccessSetReturnsDefaultsForOthers() { void testMapRequestModesEgressSetReturnsDefaultsForOthers() { Map inputModes = Map.of("egressMode", StreetMode.CAR); - RequestModes wantModes = RequestModes.of().withEgressMode(StreetMode.CAR).build(); + RequestModes wantModes = RequestModes + .of() + .withEgressMode(StreetMode.CAR) + .withDirectMode(null) + .build(); RequestModes mappedModes = RequestModesMapper.mapRequestModes(inputModes); From f3b8c93f9a40cd42a4c02bf94377fa9e5cbb8cbc Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Fri, 12 Apr 2024 12:48:53 +0000 Subject: [PATCH 066/121] Add changelog entry for #5779 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 206d1b64e7f..704ce4787c0 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -12,6 +12,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Fix handling of null transport mode filter [#5789](https://github.com/opentripplanner/OpenTripPlanner/pull/5789) - Discourage instead of ban cycling on use_sidepath ways and do the same for walking on foot=use_sidepath [#5790](https://github.com/opentripplanner/OpenTripPlanner/pull/5790) - Prune islands with mode-less stop vertices [#5782](https://github.com/opentripplanner/OpenTripPlanner/pull/5782) +- Overwrite default WALK directMode when it is not set in the request, but modes is set [#5779](https://github.com/opentripplanner/OpenTripPlanner/pull/5779) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.5.0 (2024-03-13) From 1e1659a5dc5480acbd1d70e60027b0f4d9cb4e00 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 13 Apr 2024 11:36:06 +0000 Subject: [PATCH 067/121] Update dependency @testing-library/react to v15 --- client-next/package-lock.json | 135 ++++------------------------------ client-next/package.json | 2 +- 2 files changed, 16 insertions(+), 121 deletions(-) diff --git a/client-next/package-lock.json b/client-next/package-lock.json index d3b8c10754b..6ac0e07e20f 100644 --- a/client-next/package-lock.json +++ b/client-next/package-lock.json @@ -23,7 +23,7 @@ "@graphql-codegen/client-preset": "4.2.5", "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.4.1", - "@testing-library/react": "14.2.2", + "@testing-library/react": "15.0.2", "@types/react": "18.2.73", "@types/react-dom": "18.2.23", "@typescript-eslint/eslint-plugin": "7.5.0", @@ -3353,36 +3353,36 @@ } }, "node_modules/@testing-library/dom": { - "version": "9.3.4", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", - "integrity": "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.0.0.tgz", + "integrity": "sha512-PmJPnogldqoVFf+EwbHvbBJ98MmqASV8kLrBYgsDNxQcFMeIS7JFL48sfyXvuMtgmWO/wMhh25odr+8VhDmn4g==", "dev": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", - "aria-query": "5.1.3", + "aria-query": "5.3.0", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "pretty-format": "^27.0.2" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/@testing-library/react": { - "version": "14.2.2", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.2.2.tgz", - "integrity": "sha512-SOUuM2ysCvjUWBXTNfQ/ztmnKDmqaiPV3SvoIuyxMUca45rbSWWAT/qB8CUs/JQ/ux/8JFs9DNdFQ3f6jH3crA==", + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-15.0.2.tgz", + "integrity": "sha512-5mzIpuytB1ctpyywvyaY2TAAUQVCZIGqwiqFQf6u9lvj/SJQepGUzNV18Xpk+NLCaCE2j7CWrZE0tEf9xLZYiQ==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^9.0.0", + "@testing-library/dom": "^10.0.0", "@types/react-dom": "^18.0.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "react": "^18.0.0", @@ -4232,12 +4232,12 @@ "dev": true }, "node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, "dependencies": { - "deep-equal": "^2.0.5" + "dequal": "^2.0.3" } }, "node_modules/arr-union": { @@ -5284,38 +5284,6 @@ "node": ">=6" } }, - "node_modules/deep-equal": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", - "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.5", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.2", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -5613,26 +5581,6 @@ "node": ">= 0.4" } }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/es-iterator-helpers": { "version": "1.0.18", "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz", @@ -5986,15 +5934,6 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" } }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dev": true, - "dependencies": { - "dequal": "^2.0.3" - } - }, "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -7311,22 +7250,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-array-buffer": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", @@ -8744,22 +8667,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-is": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -10164,18 +10071,6 @@ "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", "dev": true }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", diff --git a/client-next/package.json b/client-next/package.json index d3f583057d8..e5019ecb088 100644 --- a/client-next/package.json +++ b/client-next/package.json @@ -32,7 +32,7 @@ "@graphql-codegen/client-preset": "4.2.5", "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.4.1", - "@testing-library/react": "14.2.2", + "@testing-library/react": "15.0.2", "@types/react": "18.2.73", "@types/react-dom": "18.2.23", "@typescript-eslint/eslint-plugin": "7.5.0", From 86af4f85a5e86e5fd8de638c9cd413e1367f559c Mon Sep 17 00:00:00 2001 From: OTP Bot Date: Mon, 15 Apr 2024 05:43:52 +0000 Subject: [PATCH 068/121] Upgrade debug client to version 2024/04/2024-04-15T05:43 --- src/client/debug-client-preview/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/debug-client-preview/index.html b/src/client/debug-client-preview/index.html index 3973571de30..317fbed5a11 100644 --- a/src/client/debug-client-preview/index.html +++ b/src/client/debug-client-preview/index.html @@ -5,8 +5,8 @@ OTP Debug Client - - + +

From dc95c7bc37ee30da551ab5e0e1b1fd33a0972647 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 05:44:44 +0000 Subject: [PATCH 069/121] Update dependency org.entur.gbfs:gbfs-java-model to v3.1.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ce9e914e687..be2f70a0edd 100644 --- a/pom.xml +++ b/pom.xml @@ -674,7 +674,7 @@ org.entur.gbfs gbfs-java-model - 3.0.26 + 3.1.1 From 31341fa7f30fb78d97d397f6350d05b054fba901 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 15 Apr 2024 07:52:39 +0200 Subject: [PATCH 070/121] Automerge maven-jar-plugin [ci skip] --- renovate.json5 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/renovate.json5 b/renovate.json5 index d24a1e5cf3f..b3472c1a0d1 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -121,7 +121,8 @@ "com.hubspot.maven.plugins:prettier-maven-plugin", "com.google.cloud.tools:jib-maven-plugin", "org.apache.maven.plugins:maven-shade-plugin", - "org.apache.maven.plugins:maven-compiler-plugin" + "org.apache.maven.plugins:maven-compiler-plugin", + "org.apache.maven.plugins:maven-jar-plugin" ], "matchPackagePrefixes": [ "org.junit.jupiter:", From af101e0558401555d199a82114fe82403aac8c33 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 13 Apr 2024 11:35:35 +0000 Subject: [PATCH 071/121] Update dependency org.apache.maven.plugins:maven-jar-plugin to v3.4.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ce9e914e687..0dbec37943a 100644 --- a/pom.xml +++ b/pom.xml @@ -158,7 +158,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.3.0 + 3.4.0 From b1ed4fffe80281836c9c4362c851e24edd56700f Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 12 Feb 2024 17:59:06 +0100 Subject: [PATCH 072/121] Add flex duration factors and offsets --- .../gtfs/mapping/StopTimeMapper.java | 16 +++++++ .../org/opentripplanner/model/StopTime.java | 47 ++++++++++--------- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java index fc75236f4e4..2c01dda3e1b 100644 --- a/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java +++ b/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java @@ -1,5 +1,8 @@ package org.opentripplanner.gtfs.mapping; +import static org.onebusaway.gtfs.model.StopTime.MISSING_VALUE; + +import java.time.Duration; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -102,6 +105,19 @@ private StopTime doMap(org.onebusaway.gtfs.model.StopTime rhs) { lhs.setFarePeriodId(rhs.getFarePeriodId()); lhs.setFlexWindowStart(rhs.getStartPickupDropOffWindow()); lhs.setFlexWindowEnd(rhs.getEndPickupDropOffWindow()); + if(rhs.getMeanDurationOffset() != MISSING_VALUE) { + lhs.setMeanDurationFactor(rhs.getMeanDurationFactor()); + } + if(rhs.getMeanDurationOffset() != MISSING_VALUE) { + lhs.setMeanDurationOffset(Duration.ofSeconds((long) rhs.getMeanDurationOffset())); + } + if(rhs.getSafeDurationFactor() != MISSING_VALUE){ + lhs.setSafeDurationFactor(rhs.getSafeDurationFactor()); + } + if(rhs.getSafeDurationOffset()!= MISSING_VALUE){ + lhs.setSafeDurationOffset(Duration.ofSeconds((long) rhs.getSafeDurationOffset())); + } + lhs.setFlexContinuousPickup( PickDropMapper.mapFlexContinuousPickDrop(rhs.getContinuousPickup()) ); diff --git a/src/main/java/org/opentripplanner/model/StopTime.java b/src/main/java/org/opentripplanner/model/StopTime.java index 2ae04484426..8320e532c2c 100644 --- a/src/main/java/org/opentripplanner/model/StopTime.java +++ b/src/main/java/org/opentripplanner/model/StopTime.java @@ -1,6 +1,7 @@ /* This file is based on code copied from project OneBusAway, see the LICENSE file for further information. */ package org.opentripplanner.model; +import java.time.Duration; import java.util.List; import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.framework.time.TimeUtils; @@ -50,6 +51,14 @@ public final class StopTime implements Comparable { private int flexWindowEnd = MISSING_VALUE; + private double meanDurationFactor = MISSING_VALUE; + + private Duration meanDurationOffset = Duration.ZERO; + + private double safeDurationFactor = MISSING_VALUE; + + private Duration safeDurationOffset = Duration.ZERO; + // Disabled by default private PickDrop flexContinuousPickup = PickDrop.NONE; @@ -62,28 +71,6 @@ public final class StopTime implements Comparable { public StopTime() {} - public StopTime(StopTime st) { - this.trip = st.trip; - this.stop = st.stop; - this.arrivalTime = st.arrivalTime; - this.departureTime = st.departureTime; - this.timepoint = st.timepoint; - this.stopSequence = st.stopSequence; - this.stopHeadsign = st.stopHeadsign; - this.routeShortName = st.routeShortName; - this.pickupType = st.pickupType; - this.dropOffType = st.dropOffType; - this.shapeDistTraveled = st.shapeDistTraveled; - this.farePeriodId = st.farePeriodId; - this.flexWindowStart = st.flexWindowStart; - this.flexWindowEnd = st.flexWindowEnd; - this.flexContinuousPickup = st.flexContinuousPickup; - this.flexContinuousDropOff = st.flexContinuousDropOff; - this.dropOffBookingInfo = st.dropOffBookingInfo; - this.pickupBookingInfo = st.pickupBookingInfo; - this.headsignVias = st.headsignVias; - } - /** * The id is used to navigate/link StopTime to other entities (Map from StopTime.id -> Entity.id). * There is no need to navigate in the opposite direction. The StopTime id is NOT stored in a @@ -310,6 +297,22 @@ public String toString() { ); } + public void setMeanDurationFactor(double meanDurationFactor) { + this.meanDurationFactor = meanDurationFactor; + } + + public void setMeanDurationOffset(Duration meanDurationOffset) { + this.meanDurationOffset = meanDurationOffset; + } + + public void setSafeDurationOffset(Duration safeDurationOffset) { + this.safeDurationOffset = safeDurationOffset; + } + + public void setSafeDurationFactor(double safeDurationFactor) { + this.safeDurationFactor = safeDurationFactor; + } + private static int getAvailableTime(int... times) { for (var time : times) { if (time != MISSING_VALUE) { From 95527bbac94835a4032e43a34eb5872bed8bbb25 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 14 Feb 2024 17:23:12 +0100 Subject: [PATCH 073/121] Add initial implementation of flex duration factors --- .../DurationFactorCalculator.java | 26 +++++++++++++++++++ .../ext/flex/flexpathcalculator/FlexPath.java | 6 +++++ .../ext/flex/trip/StopTimeWindow.java | 13 ++++++++++ .../ext/flex/trip/UnscheduledTrip.java | 12 +++++---- .../gtfs/mapping/StopTimeMapper.java | 8 +++--- .../org/opentripplanner/model/StopTime.java | 15 +++++++++++ 6 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java new file mode 100644 index 00000000000..c4bc23848d7 --- /dev/null +++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java @@ -0,0 +1,26 @@ +package org.opentripplanner.ext.flex.flexpathcalculator; + +import java.time.Duration; +import javax.annotation.Nullable; +import org.opentripplanner.street.model.vertex.Vertex; + +public class DurationFactorCalculator implements FlexPathCalculator { + + private final FlexPathCalculator underlying; + + public DurationFactorCalculator(FlexPathCalculator underlying) { + this.underlying = underlying; + } + + @Nullable + @Override + public FlexPath calculateFlexPath(Vertex fromv, Vertex tov, int fromStopIndex, int toStopIndex) { + var path = underlying.calculateFlexPath(fromv, tov, fromStopIndex, toStopIndex); + + if (path == null) { + return null; + } else { + return path.withDurationFactors(1.5f, Duration.ofMinutes(10)); + } + } +} diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java index 5c5557890d6..c36a59524d1 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java +++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java @@ -1,5 +1,6 @@ package org.opentripplanner.ext.flex.flexpathcalculator; +import java.time.Duration; import java.util.function.Supplier; import org.locationtech.jts.geom.LineString; @@ -32,4 +33,9 @@ public LineString getGeometry() { } return geometry; } + + public FlexPath withDurationFactors(float factor, Duration offset) { + int updatedDuration = (int) ((durationSeconds * factor) + offset.toSeconds()); + return new FlexPath(distanceMeters, updatedDuration, geometrySupplier); + } } diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/StopTimeWindow.java b/src/ext/java/org/opentripplanner/ext/flex/trip/StopTimeWindow.java index 5b7ebbbc575..821fe290cbb 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/StopTimeWindow.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/StopTimeWindow.java @@ -3,6 +3,7 @@ import static org.opentripplanner.model.StopTime.MISSING_VALUE; import java.io.Serializable; +import java.util.OptionalDouble; import org.opentripplanner.framework.lang.IntRange; import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.StopTime; @@ -18,6 +19,8 @@ class StopTimeWindow implements Serializable { private final PickDrop pickupType; private final PickDrop dropOffType; + private final double meanDurationFactor; + StopTimeWindow(StopTime st) { stop = st.getStop(); @@ -32,6 +35,12 @@ class StopTimeWindow implements Serializable { // Do not allow for pickup/dropoff if times are not available pickupType = start == MISSING_VALUE ? PickDrop.NONE : st.getPickupType(); dropOffType = end == MISSING_VALUE ? PickDrop.NONE : st.getDropOffType(); + + if (st.meanDurationFactor().isPresent()) { + meanDurationFactor = st.meanDurationFactor().getAsDouble(); + } else { + meanDurationFactor = 1; + } } public StopLocation stop() { @@ -58,6 +67,10 @@ public IntRange timeWindow() { return IntRange.ofInclusive(start, end); } + public double meanDurationFactor() { + return meanDurationFactor; + } + private static int getAvailableTime(int... times) { for (var time : times) { if (time != MISSING_VALUE) { diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java index c5968507676..10b00b6ab98 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java @@ -14,6 +14,7 @@ import java.util.stream.Stream; import javax.annotation.Nonnull; import org.opentripplanner.ext.flex.FlexServiceDate; +import org.opentripplanner.ext.flex.flexpathcalculator.DurationFactorCalculator; import org.opentripplanner.ext.flex.flexpathcalculator.FlexPathCalculator; import org.opentripplanner.ext.flex.template.FlexAccessTemplate; import org.opentripplanner.ext.flex.template.FlexEgressTemplate; @@ -81,8 +82,6 @@ public static UnscheduledTripBuilder of(FeedScopedId id) { * - One or more stop times with a flexible time window but no fixed stop in between them */ public static boolean isUnscheduledTrip(List stopTimes) { - Predicate hasFlexWindow = st -> - st.getFlexWindowStart() != MISSING_VALUE || st.getFlexWindowEnd() != MISSING_VALUE; Predicate hasContinuousStops = stopTime -> stopTime.getFlexContinuousDropOff() != NONE || stopTime.getFlexContinuousPickup() != NONE; if (stopTimes.isEmpty()) { @@ -90,9 +89,9 @@ public static boolean isUnscheduledTrip(List stopTimes) { } else if (stopTimes.stream().anyMatch(hasContinuousStops)) { return false; } else if (N_STOPS.contains(stopTimes.size())) { - return stopTimes.stream().anyMatch(hasFlexWindow); + return stopTimes.stream().anyMatch(StopTime::hasFlexWindow); } else { - return stopTimes.stream().allMatch(hasFlexWindow); + return stopTimes.stream().allMatch(StopTime::hasFlexWindow); } } @@ -120,6 +119,9 @@ public Stream getFlexAccessTemplates( } else { indices = IntStream.range(fromIndex + 1, lastIndexInTrip + 1); } + + var updatedCalculator = new DurationFactorCalculator(calculator); + // check for every stop after fromIndex if you can alight, if so return a template return indices // if you cannot alight at an index, the trip is not possible @@ -137,7 +139,7 @@ public Stream getFlexAccessTemplates( alightStop.index, alightStop.stop, date, - calculator, + updatedCalculator, config ) ); diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java index 2c01dda3e1b..0a1f6269e4f 100644 --- a/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java +++ b/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java @@ -105,16 +105,16 @@ private StopTime doMap(org.onebusaway.gtfs.model.StopTime rhs) { lhs.setFarePeriodId(rhs.getFarePeriodId()); lhs.setFlexWindowStart(rhs.getStartPickupDropOffWindow()); lhs.setFlexWindowEnd(rhs.getEndPickupDropOffWindow()); - if(rhs.getMeanDurationOffset() != MISSING_VALUE) { + if (rhs.getMeanDurationOffset() != MISSING_VALUE) { lhs.setMeanDurationFactor(rhs.getMeanDurationFactor()); } - if(rhs.getMeanDurationOffset() != MISSING_VALUE) { + if (rhs.getMeanDurationOffset() != MISSING_VALUE) { lhs.setMeanDurationOffset(Duration.ofSeconds((long) rhs.getMeanDurationOffset())); } - if(rhs.getSafeDurationFactor() != MISSING_VALUE){ + if (rhs.getSafeDurationFactor() != MISSING_VALUE) { lhs.setSafeDurationFactor(rhs.getSafeDurationFactor()); } - if(rhs.getSafeDurationOffset()!= MISSING_VALUE){ + if (rhs.getSafeDurationOffset() != MISSING_VALUE) { lhs.setSafeDurationOffset(Duration.ofSeconds((long) rhs.getSafeDurationOffset())); } diff --git a/src/main/java/org/opentripplanner/model/StopTime.java b/src/main/java/org/opentripplanner/model/StopTime.java index 8320e532c2c..64045bbbbfe 100644 --- a/src/main/java/org/opentripplanner/model/StopTime.java +++ b/src/main/java/org/opentripplanner/model/StopTime.java @@ -3,6 +3,7 @@ import java.time.Duration; import java.util.List; +import java.util.OptionalDouble; import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.framework.time.TimeUtils; import org.opentripplanner.transit.model.site.StopLocation; @@ -313,6 +314,13 @@ public void setSafeDurationFactor(double safeDurationFactor) { this.safeDurationFactor = safeDurationFactor; } + public OptionalDouble meanDurationFactor() { + if (meanDurationFactor == MISSING_VALUE) { + return OptionalDouble.empty(); + } + return OptionalDouble.of(meanDurationFactor); + } + private static int getAvailableTime(int... times) { for (var time : times) { if (time != MISSING_VALUE) { @@ -322,4 +330,11 @@ private static int getAvailableTime(int... times) { return MISSING_VALUE; } + + /** + * Does this stop time define a flex window? + */ + public boolean hasFlexWindow() { + return flexWindowStart != MISSING_VALUE || flexWindowEnd != MISSING_VALUE; + } } From ea0960aa70e7cceff521777fd9ebb9f69ea50e75 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 15 Mar 2024 09:27:24 +0100 Subject: [PATCH 074/121] Remove stop-time-based factors --- .../ext/flex/trip/StopTimeWindow.java | 13 -------- .../gtfs/mapping/StopTimeMapper.java | 15 --------- .../org/opentripplanner/model/StopTime.java | 33 ------------------- 3 files changed, 61 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/StopTimeWindow.java b/src/ext/java/org/opentripplanner/ext/flex/trip/StopTimeWindow.java index 821fe290cbb..5b7ebbbc575 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/StopTimeWindow.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/StopTimeWindow.java @@ -3,7 +3,6 @@ import static org.opentripplanner.model.StopTime.MISSING_VALUE; import java.io.Serializable; -import java.util.OptionalDouble; import org.opentripplanner.framework.lang.IntRange; import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.StopTime; @@ -19,8 +18,6 @@ class StopTimeWindow implements Serializable { private final PickDrop pickupType; private final PickDrop dropOffType; - private final double meanDurationFactor; - StopTimeWindow(StopTime st) { stop = st.getStop(); @@ -35,12 +32,6 @@ class StopTimeWindow implements Serializable { // Do not allow for pickup/dropoff if times are not available pickupType = start == MISSING_VALUE ? PickDrop.NONE : st.getPickupType(); dropOffType = end == MISSING_VALUE ? PickDrop.NONE : st.getDropOffType(); - - if (st.meanDurationFactor().isPresent()) { - meanDurationFactor = st.meanDurationFactor().getAsDouble(); - } else { - meanDurationFactor = 1; - } } public StopLocation stop() { @@ -67,10 +58,6 @@ public IntRange timeWindow() { return IntRange.ofInclusive(start, end); } - public double meanDurationFactor() { - return meanDurationFactor; - } - private static int getAvailableTime(int... times) { for (var time : times) { if (time != MISSING_VALUE) { diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java index 0a1f6269e4f..67b250c5061 100644 --- a/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java +++ b/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java @@ -1,8 +1,5 @@ package org.opentripplanner.gtfs.mapping; -import static org.onebusaway.gtfs.model.StopTime.MISSING_VALUE; - -import java.time.Duration; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -105,18 +102,6 @@ private StopTime doMap(org.onebusaway.gtfs.model.StopTime rhs) { lhs.setFarePeriodId(rhs.getFarePeriodId()); lhs.setFlexWindowStart(rhs.getStartPickupDropOffWindow()); lhs.setFlexWindowEnd(rhs.getEndPickupDropOffWindow()); - if (rhs.getMeanDurationOffset() != MISSING_VALUE) { - lhs.setMeanDurationFactor(rhs.getMeanDurationFactor()); - } - if (rhs.getMeanDurationOffset() != MISSING_VALUE) { - lhs.setMeanDurationOffset(Duration.ofSeconds((long) rhs.getMeanDurationOffset())); - } - if (rhs.getSafeDurationFactor() != MISSING_VALUE) { - lhs.setSafeDurationFactor(rhs.getSafeDurationFactor()); - } - if (rhs.getSafeDurationOffset() != MISSING_VALUE) { - lhs.setSafeDurationOffset(Duration.ofSeconds((long) rhs.getSafeDurationOffset())); - } lhs.setFlexContinuousPickup( PickDropMapper.mapFlexContinuousPickDrop(rhs.getContinuousPickup()) diff --git a/src/main/java/org/opentripplanner/model/StopTime.java b/src/main/java/org/opentripplanner/model/StopTime.java index 64045bbbbfe..e753b8d2885 100644 --- a/src/main/java/org/opentripplanner/model/StopTime.java +++ b/src/main/java/org/opentripplanner/model/StopTime.java @@ -1,9 +1,7 @@ /* This file is based on code copied from project OneBusAway, see the LICENSE file for further information. */ package org.opentripplanner.model; -import java.time.Duration; import java.util.List; -import java.util.OptionalDouble; import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.framework.time.TimeUtils; import org.opentripplanner.transit.model.site.StopLocation; @@ -52,14 +50,6 @@ public final class StopTime implements Comparable { private int flexWindowEnd = MISSING_VALUE; - private double meanDurationFactor = MISSING_VALUE; - - private Duration meanDurationOffset = Duration.ZERO; - - private double safeDurationFactor = MISSING_VALUE; - - private Duration safeDurationOffset = Duration.ZERO; - // Disabled by default private PickDrop flexContinuousPickup = PickDrop.NONE; @@ -298,29 +288,6 @@ public String toString() { ); } - public void setMeanDurationFactor(double meanDurationFactor) { - this.meanDurationFactor = meanDurationFactor; - } - - public void setMeanDurationOffset(Duration meanDurationOffset) { - this.meanDurationOffset = meanDurationOffset; - } - - public void setSafeDurationOffset(Duration safeDurationOffset) { - this.safeDurationOffset = safeDurationOffset; - } - - public void setSafeDurationFactor(double safeDurationFactor) { - this.safeDurationFactor = safeDurationFactor; - } - - public OptionalDouble meanDurationFactor() { - if (meanDurationFactor == MISSING_VALUE) { - return OptionalDouble.empty(); - } - return OptionalDouble.of(meanDurationFactor); - } - private static int getAvailableTime(int... times) { for (var time : times) { if (time != MISSING_VALUE) { From a0eb06655a65deb18005d9ba5f2441c072d3fa59 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 15 Mar 2024 10:29:47 +0100 Subject: [PATCH 075/121] Move factors into calcultor --- .../DurationFactorCalculator.java | 14 +++++++++----- .../ext/flex/trip/UnscheduledTrip.java | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java index c4bc23848d7..24a4d665fe6 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java +++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java @@ -6,21 +6,25 @@ public class DurationFactorCalculator implements FlexPathCalculator { - private final FlexPathCalculator underlying; + private final FlexPathCalculator delegate; + private final float factor; + private final Duration offset; - public DurationFactorCalculator(FlexPathCalculator underlying) { - this.underlying = underlying; + public DurationFactorCalculator(FlexPathCalculator delegate, float factor, Duration offset) { + this.delegate = delegate; + this.factor = factor; + this.offset = offset; } @Nullable @Override public FlexPath calculateFlexPath(Vertex fromv, Vertex tov, int fromStopIndex, int toStopIndex) { - var path = underlying.calculateFlexPath(fromv, tov, fromStopIndex, toStopIndex); + var path = delegate.calculateFlexPath(fromv, tov, fromStopIndex, toStopIndex); if (path == null) { return null; } else { - return path.withDurationFactors(1.5f, Duration.ofMinutes(10)); + return path.withDurationFactors(factor, offset); } } } diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java index 10b00b6ab98..e2ab49045d6 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java @@ -3,6 +3,7 @@ import static org.opentripplanner.model.PickDrop.NONE; import static org.opentripplanner.model.StopTime.MISSING_VALUE; +import java.time.Duration; import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -120,7 +121,7 @@ public Stream getFlexAccessTemplates( indices = IntStream.range(fromIndex + 1, lastIndexInTrip + 1); } - var updatedCalculator = new DurationFactorCalculator(calculator); + var updatedCalculator = new DurationFactorCalculator(calculator, 1.5f, Duration.ofMinutes(20)); // check for every stop after fromIndex if you can alight, if so return a template return indices From cc7601275a2ba2551028b40d229da7afd799188c Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 15 Mar 2024 14:24:04 +0100 Subject: [PATCH 076/121] Encapsulate factors, add parsing --- .../ext/flex/FlexTripsMapper.java | 9 ++++++- .../DurationFactorCalculator.java | 12 ++++----- .../ext/flex/flexpathcalculator/FlexPath.java | 6 ++--- .../ext/flex/trip/FlexDurationFactors.java | 27 +++++++++++++++++++ .../ext/flex/trip/UnscheduledTrip.java | 15 +++++++++-- .../ext/flex/trip/UnscheduledTripBuilder.java | 10 +++++++ .../GTFSToOtpTransitServiceMapper.java | 1 + .../gtfs/mapping/TripMapper.java | 26 ++++++++++++++++-- .../model/impl/OtpTransitServiceBuilder.java | 9 +++++++ 9 files changed, 100 insertions(+), 15 deletions(-) create mode 100644 src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationFactors.java diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java index f5ab34cce49..d4918e8ed33 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; +import org.opentripplanner.ext.flex.trip.FlexDurationFactors; import org.opentripplanner.ext.flex.trip.FlexTrip; import org.opentripplanner.ext.flex.trip.ScheduledDeviatedTrip; import org.opentripplanner.ext.flex.trip.UnscheduledTrip; @@ -34,10 +35,16 @@ public class FlexTripsMapper { for (Trip trip : stopTimesByTrip.keys()) { /* Fetch the stop times for this trip. Copy the list since it's immutable. */ List stopTimes = new ArrayList<>(stopTimesByTrip.get(trip)); + var factors = builder.getFlexDurationFactors().getOrDefault(trip, FlexDurationFactors.ZERO); if (UnscheduledTrip.isUnscheduledTrip(stopTimes)) { result.add( - UnscheduledTrip.of(trip.getId()).withTrip(trip).withStopTimes(stopTimes).build() + UnscheduledTrip + .of(trip.getId()) + .withTrip(trip) + .withStopTimes(stopTimes) + .withDurationFactors(factors) + .build() ); } else if (ScheduledDeviatedTrip.isScheduledFlexTrip(stopTimes)) { result.add( diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java index 24a4d665fe6..3e5a6b1db79 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java +++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java @@ -1,19 +1,17 @@ package org.opentripplanner.ext.flex.flexpathcalculator; -import java.time.Duration; import javax.annotation.Nullable; +import org.opentripplanner.ext.flex.trip.FlexDurationFactors; import org.opentripplanner.street.model.vertex.Vertex; public class DurationFactorCalculator implements FlexPathCalculator { private final FlexPathCalculator delegate; - private final float factor; - private final Duration offset; + private final FlexDurationFactors factors; - public DurationFactorCalculator(FlexPathCalculator delegate, float factor, Duration offset) { + public DurationFactorCalculator(FlexPathCalculator delegate, FlexDurationFactors factors) { this.delegate = delegate; - this.factor = factor; - this.offset = offset; + this.factors = factors; } @Nullable @@ -24,7 +22,7 @@ public FlexPath calculateFlexPath(Vertex fromv, Vertex tov, int fromStopIndex, i if (path == null) { return null; } else { - return path.withDurationFactors(factor, offset); + return path.withDurationFactors(factors); } } } diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java index c36a59524d1..7ba3aad43d4 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java +++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java @@ -1,8 +1,8 @@ package org.opentripplanner.ext.flex.flexpathcalculator; -import java.time.Duration; import java.util.function.Supplier; import org.locationtech.jts.geom.LineString; +import org.opentripplanner.ext.flex.trip.FlexDurationFactors; /** * This class contains the results from a FlexPathCalculator. @@ -34,8 +34,8 @@ public LineString getGeometry() { return geometry; } - public FlexPath withDurationFactors(float factor, Duration offset) { - int updatedDuration = (int) ((durationSeconds * factor) + offset.toSeconds()); + public FlexPath withDurationFactors(FlexDurationFactors factors) { + int updatedDuration = (int) ((durationSeconds * factors.factor()) + factors.offsetInSeconds()); return new FlexPath(distanceMeters, updatedDuration, geometrySupplier); } } diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationFactors.java b/src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationFactors.java new file mode 100644 index 00000000000..41b610730d4 --- /dev/null +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationFactors.java @@ -0,0 +1,27 @@ +package org.opentripplanner.ext.flex.trip; + +import java.time.Duration; + +public class FlexDurationFactors { + + public static FlexDurationFactors ZERO = new FlexDurationFactors(Duration.ZERO, 1); + private final int offset; + private final float factor; + + public FlexDurationFactors(Duration offset, float factor) { + this.offset = (int) offset.toSeconds(); + this.factor = factor; + } + + public float factor() { + return factor; + } + + public int offsetInSeconds() { + return offset; + } + + boolean nonZero() { + return offset != 0 && factor != 1.0; + } +} diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java index e2ab49045d6..9c71696c02b 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java @@ -3,9 +3,9 @@ import static org.opentripplanner.model.PickDrop.NONE; import static org.opentripplanner.model.StopTime.MISSING_VALUE; -import java.time.Duration; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Function; @@ -52,6 +52,8 @@ public class UnscheduledTrip extends FlexTrip stopTimes = builder.stopTimes(); @@ -69,6 +71,7 @@ public UnscheduledTrip(UnscheduledTripBuilder builder) { this.dropOffBookingInfos[i] = stopTimes.get(0).getDropOffBookingInfo(); this.pickupBookingInfos[i] = stopTimes.get(0).getPickupBookingInfo(); } + this.duractionFactors = Objects.requireNonNull(builder.durationFactors()); } public static UnscheduledTripBuilder of(FeedScopedId id) { @@ -121,7 +124,7 @@ public Stream getFlexAccessTemplates( indices = IntStream.range(fromIndex + 1, lastIndexInTrip + 1); } - var updatedCalculator = new DurationFactorCalculator(calculator, 1.5f, Duration.ofMinutes(20)); + final var updatedCalculator = flexPathCalculator(calculator); // check for every stop after fromIndex if you can alight, if so return a template return indices @@ -146,6 +149,14 @@ public Stream getFlexAccessTemplates( ); } + private FlexPathCalculator flexPathCalculator(FlexPathCalculator calculator) { + if (duractionFactors.nonZero()) { + return new DurationFactorCalculator(calculator, duractionFactors); + } else { + return calculator; + } + } + @Override public Stream getFlexEgressTemplates( NearbyStop egress, diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java index 678b7fcce5e..e2d296d8154 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java @@ -8,6 +8,7 @@ public class UnscheduledTripBuilder extends FlexTripBuilder { private List stopTimes; + private FlexDurationFactors durationFactors = FlexDurationFactors.ZERO; UnscheduledTripBuilder(FeedScopedId id) { super(id); @@ -29,6 +30,15 @@ public List stopTimes() { return stopTimes; } + public UnscheduledTripBuilder withDurationFactors(FlexDurationFactors factors) { + this.durationFactors = factors; + return this; + } + + public FlexDurationFactors durationFactors() { + return durationFactors; + } + @Override UnscheduledTripBuilder instance() { return this; diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java index 4d5fe6bd051..15a4c2e28b7 100644 --- a/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java +++ b/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java @@ -171,6 +171,7 @@ public void mapStopTripAndRouteDataIntoBuilder() { builder.getPathways().addAll(pathwayMapper.map(data.getAllPathways())); builder.getStopTimesSortedByTrip().addAll(stopTimeMapper.map(data.getAllStopTimes())); + builder.getFlexDurationFactors().putAll(tripMapper.flexDurationFactors()); builder.getTripsById().addAll(tripMapper.map(data.getAllTrips())); fareRulesBuilder.fareAttributes().addAll(fareAttributeMapper.map(data.getAllFareAttributes())); diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java index a80ae035ed1..77d6eb879b0 100644 --- a/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java +++ b/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java @@ -1,8 +1,11 @@ package org.opentripplanner.gtfs.mapping; +import java.time.Duration; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.Optional; +import org.opentripplanner.ext.flex.trip.FlexDurationFactors; import org.opentripplanner.framework.collection.MapUtils; import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.transit.model.timetable.Trip; @@ -12,9 +15,10 @@ class TripMapper { private final RouteMapper routeMapper; private final DirectionMapper directionMapper; - private TranslationHelper translationHelper; + private final TranslationHelper translationHelper; private final Map mappedTrips = new HashMap<>(); + private final Map flexDurationFactors = new HashMap<>(); TripMapper( RouteMapper routeMapper, @@ -38,6 +42,13 @@ Collection getMappedTrips() { return mappedTrips.values(); } + /** + * The map of flex duration factors per flex trip. + */ + Map flexDurationFactors() { + return flexDurationFactors; + } + private Trip doMap(org.onebusaway.gtfs.model.Trip rhs) { var lhs = Trip.of(AgencyAndIdMapper.mapAgencyAndId(rhs.getId())); @@ -62,6 +73,17 @@ private Trip doMap(org.onebusaway.gtfs.model.Trip rhs) { lhs.withBikesAllowed(BikeAccessMapper.mapForTrip(rhs)); lhs.withGtfsFareId(rhs.getFareId()); - return lhs.build(); + var trip = lhs.build(); + mapFlexDurationFactots(rhs).ifPresent(f -> flexDurationFactors.put(trip, f)); + return trip; + } + + private Optional mapFlexDurationFactots(org.onebusaway.gtfs.model.Trip rhs) { + if (rhs.getMeanDurationFactor() == null && rhs.getMeanDurationOffset() == null) { + return Optional.empty(); + } else { + var offset = Duration.ofSeconds(rhs.getMeanDurationOffset().longValue()); + return Optional.of(new FlexDurationFactors(offset, rhs.getMeanDurationFactor().floatValue())); + } } } diff --git a/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java b/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java index 382d6042a05..e4d0d76cbe3 100644 --- a/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java +++ b/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java @@ -3,10 +3,13 @@ import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; +import org.opentripplanner.ext.flex.trip.FlexDurationFactors; import org.opentripplanner.ext.flex.trip.FlexTrip; import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.gtfs.mapping.StaySeatedNotAllowed; @@ -92,6 +95,8 @@ public class OtpTransitServiceBuilder { private final TripStopTimes stopTimesByTrip = new TripStopTimes(); + private final Map flexDurationFactors = new HashMap<>(); + private final EntityById fareZonesById = new DefaultEntityById<>(); private final List transfers = new ArrayList<>(); @@ -209,6 +214,10 @@ public TripStopTimes getStopTimesSortedByTrip() { return stopTimesByTrip; } + public Map getFlexDurationFactors() { + return flexDurationFactors; + } + public EntityById getFareZonesById() { return fareZonesById; } From dca331bff6144a4d51902bcfe78115bac00c40ee Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 15 Mar 2024 15:07:31 +0100 Subject: [PATCH 077/121] Make factors serializable --- .../ext/flex/FlexTripsMapper.java | 2 +- .../ext/flex/trip/FlexDurationFactors.java | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java index d4918e8ed33..819b51f9df2 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java @@ -35,9 +35,9 @@ public class FlexTripsMapper { for (Trip trip : stopTimesByTrip.keys()) { /* Fetch the stop times for this trip. Copy the list since it's immutable. */ List stopTimes = new ArrayList<>(stopTimesByTrip.get(trip)); - var factors = builder.getFlexDurationFactors().getOrDefault(trip, FlexDurationFactors.ZERO); if (UnscheduledTrip.isUnscheduledTrip(stopTimes)) { + var factors = builder.getFlexDurationFactors().getOrDefault(trip, FlexDurationFactors.ZERO); result.add( UnscheduledTrip .of(trip.getId()) diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationFactors.java b/src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationFactors.java index 41b610730d4..adcb25dc1e4 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationFactors.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationFactors.java @@ -1,15 +1,21 @@ package org.opentripplanner.ext.flex.trip; +import java.io.Serializable; import java.time.Duration; +import org.opentripplanner.framework.time.DurationUtils; +import org.opentripplanner.framework.tostring.ToStringBuilder; -public class FlexDurationFactors { +public class FlexDurationFactors implements Serializable { public static FlexDurationFactors ZERO = new FlexDurationFactors(Duration.ZERO, 1); private final int offset; private final float factor; public FlexDurationFactors(Duration offset, float factor) { - this.offset = (int) offset.toSeconds(); + if (factor < 0.1) { + throw new IllegalArgumentException("Flex duration factor must not be less than 0.1"); + } + this.offset = (int) DurationUtils.requireNonNegative(offset).toSeconds(); this.factor = factor; } @@ -24,4 +30,13 @@ public int offsetInSeconds() { boolean nonZero() { return offset != 0 && factor != 1.0; } + + @Override + public String toString() { + return ToStringBuilder + .of(FlexDurationFactors.class) + .addNum("factor", factor) + .addDurationSec("offset", offset) + .toString(); + } } From 721845e1b7287a8186b4abdf517501b51474ded7 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 5 Apr 2024 12:28:37 +0200 Subject: [PATCH 078/121] Use safe instead of mean values --- .../mapping/GTFSToOtpTransitServiceMapper.java | 2 +- .../opentripplanner/gtfs/mapping/TripMapper.java | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java index 15a4c2e28b7..4ee1cdcf1d7 100644 --- a/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java +++ b/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java @@ -171,7 +171,7 @@ public void mapStopTripAndRouteDataIntoBuilder() { builder.getPathways().addAll(pathwayMapper.map(data.getAllPathways())); builder.getStopTimesSortedByTrip().addAll(stopTimeMapper.map(data.getAllStopTimes())); - builder.getFlexDurationFactors().putAll(tripMapper.flexDurationFactors()); + builder.getFlexDurationFactors().putAll(tripMapper.flexSafeDurationFactors()); builder.getTripsById().addAll(tripMapper.map(data.getAllTrips())); fareRulesBuilder.fareAttributes().addAll(fareAttributeMapper.map(data.getAllFareAttributes())); diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java index 77d6eb879b0..0164e7d77f9 100644 --- a/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java +++ b/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java @@ -18,7 +18,7 @@ class TripMapper { private final TranslationHelper translationHelper; private final Map mappedTrips = new HashMap<>(); - private final Map flexDurationFactors = new HashMap<>(); + private final Map flexSafeDurationFactors = new HashMap<>(); TripMapper( RouteMapper routeMapper, @@ -45,8 +45,8 @@ Collection getMappedTrips() { /** * The map of flex duration factors per flex trip. */ - Map flexDurationFactors() { - return flexDurationFactors; + Map flexSafeDurationFactors() { + return flexSafeDurationFactors; } private Trip doMap(org.onebusaway.gtfs.model.Trip rhs) { @@ -74,16 +74,16 @@ private Trip doMap(org.onebusaway.gtfs.model.Trip rhs) { lhs.withGtfsFareId(rhs.getFareId()); var trip = lhs.build(); - mapFlexDurationFactots(rhs).ifPresent(f -> flexDurationFactors.put(trip, f)); + mapSafeDurationFactors(rhs).ifPresent(f -> flexSafeDurationFactors.put(trip, f)); return trip; } - private Optional mapFlexDurationFactots(org.onebusaway.gtfs.model.Trip rhs) { - if (rhs.getMeanDurationFactor() == null && rhs.getMeanDurationOffset() == null) { + private Optional mapSafeDurationFactors(org.onebusaway.gtfs.model.Trip rhs) { + if (rhs.getSafeDurationFactor() == null && rhs.getSafeDurationOffset() == null) { return Optional.empty(); } else { - var offset = Duration.ofSeconds(rhs.getMeanDurationOffset().longValue()); - return Optional.of(new FlexDurationFactors(offset, rhs.getMeanDurationFactor().floatValue())); + var offset = Duration.ofSeconds(rhs.getSafeDurationOffset().longValue()); + return Optional.of(new FlexDurationFactors(offset, rhs.getSafeDurationFactor().floatValue())); } } } From abcfa935489f7dfdc735ec92e7dead8cd7ca4f1c Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 5 Apr 2024 12:32:15 +0200 Subject: [PATCH 079/121] Use correct booking info instances --- .../org/opentripplanner/ext/flex/trip/UnscheduledTrip.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java index 9c71696c02b..712a446c7ed 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java @@ -68,8 +68,8 @@ public UnscheduledTrip(UnscheduledTripBuilder builder) { for (int i = 0; i < size; i++) { this.stopTimes[i] = new StopTimeWindow(stopTimes.get(i)); - this.dropOffBookingInfos[i] = stopTimes.get(0).getDropOffBookingInfo(); - this.pickupBookingInfos[i] = stopTimes.get(0).getPickupBookingInfo(); + this.dropOffBookingInfos[i] = stopTimes.get(i).getDropOffBookingInfo(); + this.pickupBookingInfos[i] = stopTimes.get(i).getPickupBookingInfo(); } this.duractionFactors = Objects.requireNonNull(builder.durationFactors()); } From 5066052c4452afdc15f10896f4c01ee510415dab Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 5 Apr 2024 16:05:31 +0200 Subject: [PATCH 080/121] Implement duration modifier for ScheduledDeviated trip --- .../ext/flex/FlexTripsMapper.java | 14 ++++--- .../DurationFactorCalculator.java | 6 +-- .../ext/flex/flexpathcalculator/FlexPath.java | 4 +- .../ScheduledFlexPathCalculator.java | 9 +++-- ...Factors.java => FlexDurationModifier.java} | 14 ++++--- .../ext/flex/trip/ScheduledDeviatedTrip.java | 39 +++++++++++++++++-- .../trip/ScheduledDeviatedTripBuilder.java | 10 +++++ .../ext/flex/trip/UnscheduledTrip.java | 8 ++-- .../ext/flex/trip/UnscheduledTripBuilder.java | 10 ++--- .../gtfs/mapping/TripMapper.java | 14 ++++--- .../model/impl/OtpTransitServiceBuilder.java | 7 ++-- 11 files changed, 96 insertions(+), 39 deletions(-) rename src/ext/java/org/opentripplanner/ext/flex/trip/{FlexDurationFactors.java => FlexDurationModifier.java} (68%) diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java index 819b51f9df2..5881bc798a8 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java @@ -4,7 +4,7 @@ import java.util.ArrayList; import java.util.List; -import org.opentripplanner.ext.flex.trip.FlexDurationFactors; +import org.opentripplanner.ext.flex.trip.FlexDurationModifier; import org.opentripplanner.ext.flex.trip.FlexTrip; import org.opentripplanner.ext.flex.trip.ScheduledDeviatedTrip; import org.opentripplanner.ext.flex.trip.UnscheduledTrip; @@ -35,20 +35,24 @@ public class FlexTripsMapper { for (Trip trip : stopTimesByTrip.keys()) { /* Fetch the stop times for this trip. Copy the list since it's immutable. */ List stopTimes = new ArrayList<>(stopTimesByTrip.get(trip)); - + var modifier = builder.getFlexDurationFactors().getOrDefault(trip, FlexDurationModifier.NONE); if (UnscheduledTrip.isUnscheduledTrip(stopTimes)) { - var factors = builder.getFlexDurationFactors().getOrDefault(trip, FlexDurationFactors.ZERO); result.add( UnscheduledTrip .of(trip.getId()) .withTrip(trip) .withStopTimes(stopTimes) - .withDurationFactors(factors) + .withDurationModifier(modifier) .build() ); } else if (ScheduledDeviatedTrip.isScheduledFlexTrip(stopTimes)) { result.add( - ScheduledDeviatedTrip.of(trip.getId()).withTrip(trip).withStopTimes(stopTimes).build() + ScheduledDeviatedTrip + .of(trip.getId()) + .withTrip(trip) + .withStopTimes(stopTimes) + .withDurationModifier(modifier) + .build() ); } else if (hasContinuousStops(stopTimes) && FlexTrip.containsFlexStops(stopTimes)) { store.add( diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java index 3e5a6b1db79..e0873fab187 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java +++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java @@ -1,15 +1,15 @@ package org.opentripplanner.ext.flex.flexpathcalculator; import javax.annotation.Nullable; -import org.opentripplanner.ext.flex.trip.FlexDurationFactors; +import org.opentripplanner.ext.flex.trip.FlexDurationModifier; import org.opentripplanner.street.model.vertex.Vertex; public class DurationFactorCalculator implements FlexPathCalculator { private final FlexPathCalculator delegate; - private final FlexDurationFactors factors; + private final FlexDurationModifier factors; - public DurationFactorCalculator(FlexPathCalculator delegate, FlexDurationFactors factors) { + public DurationFactorCalculator(FlexPathCalculator delegate, FlexDurationModifier factors) { this.delegate = delegate; this.factors = factors; } diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java index 7ba3aad43d4..22752726ae7 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java +++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java @@ -2,7 +2,7 @@ import java.util.function.Supplier; import org.locationtech.jts.geom.LineString; -import org.opentripplanner.ext.flex.trip.FlexDurationFactors; +import org.opentripplanner.ext.flex.trip.FlexDurationModifier; /** * This class contains the results from a FlexPathCalculator. @@ -34,7 +34,7 @@ public LineString getGeometry() { return geometry; } - public FlexPath withDurationFactors(FlexDurationFactors factors) { + public FlexPath withDurationFactors(FlexDurationModifier factors) { int updatedDuration = (int) ((durationSeconds * factors.factor()) + factors.offsetInSeconds()); return new FlexPath(distanceMeters, updatedDuration, geometrySupplier); } diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/ScheduledFlexPathCalculator.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/ScheduledFlexPathCalculator.java index 7d953abc4fd..cd5228dada5 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/ScheduledFlexPathCalculator.java +++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/ScheduledFlexPathCalculator.java @@ -20,7 +20,7 @@ public ScheduledFlexPathCalculator(FlexPathCalculator flexPathCalculator, FlexTr @Override public FlexPath calculateFlexPath(Vertex fromv, Vertex tov, int fromStopIndex, int toStopIndex) { - FlexPath flexPath = flexPathCalculator.calculateFlexPath( + final var flexPath = flexPathCalculator.calculateFlexPath( fromv, tov, fromStopIndex, @@ -29,7 +29,6 @@ public FlexPath calculateFlexPath(Vertex fromv, Vertex tov, int fromStopIndex, i if (flexPath == null) { return null; } - int distance = flexPath.distanceMeters; int departureTime = trip.earliestDepartureTime( Integer.MIN_VALUE, fromStopIndex, @@ -50,6 +49,10 @@ public FlexPath calculateFlexPath(Vertex fromv, Vertex tov, int fromStopIndex, i if (departureTime >= arrivalTime) { return null; } - return new FlexPath(distance, arrivalTime - departureTime, flexPath::getGeometry); + return new FlexPath( + flexPath.distanceMeters, + arrivalTime - departureTime, + flexPath::getGeometry + ); } } diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationFactors.java b/src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationModifier.java similarity index 68% rename from src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationFactors.java rename to src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationModifier.java index adcb25dc1e4..60f795d7280 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationFactors.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationModifier.java @@ -5,13 +5,13 @@ import org.opentripplanner.framework.time.DurationUtils; import org.opentripplanner.framework.tostring.ToStringBuilder; -public class FlexDurationFactors implements Serializable { +public class FlexDurationModifier implements Serializable { - public static FlexDurationFactors ZERO = new FlexDurationFactors(Duration.ZERO, 1); + public static FlexDurationModifier NONE = new FlexDurationModifier(Duration.ZERO, 1); private final int offset; private final float factor; - public FlexDurationFactors(Duration offset, float factor) { + public FlexDurationModifier(Duration offset, float factor) { if (factor < 0.1) { throw new IllegalArgumentException("Flex duration factor must not be less than 0.1"); } @@ -27,14 +27,18 @@ public int offsetInSeconds() { return offset; } - boolean nonZero() { + /** + * Check if this instance actually modifies the duration or simply passes it back without + * change. + */ + boolean modifies() { return offset != 0 && factor != 1.0; } @Override public String toString() { return ToStringBuilder - .of(FlexDurationFactors.class) + .of(FlexDurationModifier.class) .addNum("factor", factor) .addDurationSec("offset", offset) .toString(); diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java index e16e1e5e1f7..33a064e610c 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java @@ -1,5 +1,7 @@ package org.opentripplanner.ext.flex.trip; +import static org.opentripplanner.ext.flex.trip.ScheduledDeviatedTrip.TimeType.FIXED_TIME; +import static org.opentripplanner.ext.flex.trip.ScheduledDeviatedTrip.TimeType.FLEXIBLE_TIME; import static org.opentripplanner.model.PickDrop.NONE; import static org.opentripplanner.model.StopTime.MISSING_VALUE; @@ -15,6 +17,7 @@ import java.util.stream.Stream; import javax.annotation.Nonnull; import org.opentripplanner.ext.flex.FlexServiceDate; +import org.opentripplanner.ext.flex.flexpathcalculator.DurationFactorCalculator; import org.opentripplanner.ext.flex.flexpathcalculator.FlexPathCalculator; import org.opentripplanner.ext.flex.flexpathcalculator.ScheduledFlexPathCalculator; import org.opentripplanner.ext.flex.template.FlexAccessTemplate; @@ -42,6 +45,8 @@ public class ScheduledDeviatedTrip private final BookingInfo[] dropOffBookingInfos; private final BookingInfo[] pickupBookingInfos; + private final FlexDurationModifier durationModifier; + ScheduledDeviatedTrip(ScheduledDeviatedTripBuilder builder) { super(builder); List stopTimes = builder.stopTimes(); @@ -59,6 +64,7 @@ public class ScheduledDeviatedTrip this.dropOffBookingInfos[i] = stopTimes.get(i).getDropOffBookingInfo(); this.pickupBookingInfos[i] = stopTimes.get(i).getPickupBookingInfo(); } + this.durationModifier = builder.durationModifier(); } public static ScheduledDeviatedTripBuilder of(FeedScopedId id) { @@ -104,7 +110,7 @@ public Stream getFlexAccessTemplates( toIndex, stop, date, - scheduledCalculator, + getCalculator(fromIndex, toIndex, scheduledCalculator), config ) ); @@ -114,6 +120,25 @@ public Stream getFlexAccessTemplates( return res.stream(); } + /** + * If any of the stops involved in the path computation, then apply the duration factors. + * If both from and to have a fixed time, then don't apply the factors. + */ + private FlexPathCalculator getCalculator( + int fromIndex, + int toIndex, + FlexPathCalculator scheduledCalculator + ) { + final boolean usesFlexWindow = + stopTimes[fromIndex].timeType == FLEXIBLE_TIME || + stopTimes[toIndex].timeType == FLEXIBLE_TIME; + if (usesFlexWindow && durationModifier.modifies()) { + return new DurationFactorCalculator(scheduledCalculator, FlexDurationModifier.NONE); + } else { + return scheduledCalculator; + } + } + @Override public Stream getFlexEgressTemplates( NearbyStop egress, @@ -144,7 +169,7 @@ public Stream getFlexEgressTemplates( toIndex, stop, date, - scheduledCalculator, + getCalculator(fromIndex, toIndex, scheduledCalculator), config ) ); @@ -176,7 +201,7 @@ public int earliestDepartureTime(int stopIndex) { @Override public int latestArrivalTime( int arrivalTime, - int fromStopIndex, + int ignored, int toStopIndex, int flexTripDurationSeconds ) { @@ -297,10 +322,13 @@ private static class ScheduledDeviatedStopTime implements Serializable { private final int arrivalTime; private final PickDrop pickupType; private final PickDrop dropOffType; + private final TimeType timeType; private ScheduledDeviatedStopTime(StopTime st) { this.stop = st.getStop(); + this.timeType = st.hasFlexWindow() ? FLEXIBLE_TIME : FIXED_TIME; + // Store the time the user is guaranteed to arrive at latest this.arrivalTime = st.getLatestPossibleArrivalTime(); // Store the time the user needs to be ready for pickup @@ -315,4 +343,9 @@ private ScheduledDeviatedStopTime(StopTime st) { this.dropOffType = arrivalTime == MISSING_VALUE ? PickDrop.NONE : st.getDropOffType(); } } + + enum TimeType { + FIXED_TIME, + FLEXIBLE_TIME, + } } diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripBuilder.java b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripBuilder.java index 4033bbe7c59..3a33ebd50ec 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripBuilder.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripBuilder.java @@ -8,6 +8,7 @@ public class ScheduledDeviatedTripBuilder extends FlexTripBuilder { private List stopTimes; + private FlexDurationModifier durationModifier = FlexDurationModifier.NONE; ScheduledDeviatedTripBuilder(FeedScopedId id) { super(id); @@ -29,6 +30,15 @@ public List stopTimes() { return stopTimes; } + public FlexDurationModifier durationModifier() { + return durationModifier; + } + + public ScheduledDeviatedTripBuilder withDurationModifier(FlexDurationModifier modifier) { + this.durationModifier = modifier; + return this; + } + @Override ScheduledDeviatedTripBuilder instance() { return this; diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java index 712a446c7ed..d85c6b72c27 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java @@ -52,7 +52,7 @@ public class UnscheduledTrip extends FlexTrip getFlexAccessTemplates( } private FlexPathCalculator flexPathCalculator(FlexPathCalculator calculator) { - if (duractionFactors.nonZero()) { - return new DurationFactorCalculator(calculator, duractionFactors); + if (durationModifier.modifies()) { + return new DurationFactorCalculator(calculator, durationModifier); } else { return calculator; } diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java index e2d296d8154..7e2132ed036 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java @@ -8,7 +8,7 @@ public class UnscheduledTripBuilder extends FlexTripBuilder { private List stopTimes; - private FlexDurationFactors durationFactors = FlexDurationFactors.ZERO; + private FlexDurationModifier durationModifier = FlexDurationModifier.NONE; UnscheduledTripBuilder(FeedScopedId id) { super(id); @@ -30,13 +30,13 @@ public List stopTimes() { return stopTimes; } - public UnscheduledTripBuilder withDurationFactors(FlexDurationFactors factors) { - this.durationFactors = factors; + public UnscheduledTripBuilder withDurationModifier(FlexDurationModifier factors) { + this.durationModifier = factors; return this; } - public FlexDurationFactors durationFactors() { - return durationFactors; + public FlexDurationModifier durationModifier() { + return durationModifier; } @Override diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java index 0164e7d77f9..03ef077d319 100644 --- a/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java +++ b/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java @@ -5,7 +5,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; -import org.opentripplanner.ext.flex.trip.FlexDurationFactors; +import org.opentripplanner.ext.flex.trip.FlexDurationModifier; import org.opentripplanner.framework.collection.MapUtils; import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.transit.model.timetable.Trip; @@ -18,7 +18,7 @@ class TripMapper { private final TranslationHelper translationHelper; private final Map mappedTrips = new HashMap<>(); - private final Map flexSafeDurationFactors = new HashMap<>(); + private final Map flexSafeDurationFactors = new HashMap<>(); TripMapper( RouteMapper routeMapper, @@ -45,7 +45,7 @@ Collection getMappedTrips() { /** * The map of flex duration factors per flex trip. */ - Map flexSafeDurationFactors() { + Map flexSafeDurationFactors() { return flexSafeDurationFactors; } @@ -78,12 +78,16 @@ private Trip doMap(org.onebusaway.gtfs.model.Trip rhs) { return trip; } - private Optional mapSafeDurationFactors(org.onebusaway.gtfs.model.Trip rhs) { + private Optional mapSafeDurationFactors( + org.onebusaway.gtfs.model.Trip rhs + ) { if (rhs.getSafeDurationFactor() == null && rhs.getSafeDurationOffset() == null) { return Optional.empty(); } else { var offset = Duration.ofSeconds(rhs.getSafeDurationOffset().longValue()); - return Optional.of(new FlexDurationFactors(offset, rhs.getSafeDurationFactor().floatValue())); + return Optional.of( + new FlexDurationModifier(offset, rhs.getSafeDurationFactor().floatValue()) + ); } } } diff --git a/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java b/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java index e4d0d76cbe3..5811fe042c3 100644 --- a/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java +++ b/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java @@ -7,9 +7,8 @@ import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; -import org.opentripplanner.ext.flex.trip.FlexDurationFactors; +import org.opentripplanner.ext.flex.trip.FlexDurationModifier; import org.opentripplanner.ext.flex.trip.FlexTrip; import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.gtfs.mapping.StaySeatedNotAllowed; @@ -95,7 +94,7 @@ public class OtpTransitServiceBuilder { private final TripStopTimes stopTimesByTrip = new TripStopTimes(); - private final Map flexDurationFactors = new HashMap<>(); + private final Map flexDurationFactors = new HashMap<>(); private final EntityById fareZonesById = new DefaultEntityById<>(); @@ -214,7 +213,7 @@ public TripStopTimes getStopTimesSortedByTrip() { return stopTimesByTrip; } - public Map getFlexDurationFactors() { + public Map getFlexDurationFactors() { return flexDurationFactors; } From 90b15cd8684da65bb5bf2e1d984d00bc53129cdc Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sat, 6 Apr 2024 22:13:08 +0200 Subject: [PATCH 081/121] Rename and test --- .../DurationModifierCalculatorTest.java | 35 +++++++++++++++++ .../flex/flexpathcalculator/FlexPathTest.java | 39 +++++++++++++++++++ .../ext/flex/FlexTripsMapper.java | 4 +- ...r.java => DurationModifierCalculator.java} | 10 ++--- .../ext/flex/flexpathcalculator/FlexPath.java | 11 ++++-- ...ionModifier.java => DurationModifier.java} | 8 ++-- .../ext/flex/trip/ScheduledDeviatedTrip.java | 6 +-- .../trip/ScheduledDeviatedTripBuilder.java | 6 +-- .../ext/flex/trip/UnscheduledTrip.java | 6 +-- .../ext/flex/trip/UnscheduledTripBuilder.java | 6 +-- .../gtfs/mapping/TripMapper.java | 14 +++---- .../model/impl/OtpTransitServiceBuilder.java | 6 +-- .../_support/geometry/Polygons.java | 4 +- 13 files changed, 115 insertions(+), 40 deletions(-) create mode 100644 src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculatorTest.java create mode 100644 src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathTest.java rename src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/{DurationFactorCalculator.java => DurationModifierCalculator.java} (62%) rename src/ext/java/org/opentripplanner/ext/flex/trip/{FlexDurationModifier.java => DurationModifier.java} (79%) diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculatorTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculatorTest.java new file mode 100644 index 00000000000..fd81344893b --- /dev/null +++ b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculatorTest.java @@ -0,0 +1,35 @@ +package org.opentripplanner.ext.flex.flexpathcalculator; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.time.Duration; +import org.junit.jupiter.api.Test; +import org.opentripplanner.ext.flex.trip.DurationModifier; +import org.opentripplanner.framework.geometry.GeometryUtils; +import org.opentripplanner.street.model._data.StreetModelForTest; + +class DurationModifierCalculatorTest { + + private static final int THIRTY_MINS_IN_SECONDS = (int) Duration.ofMinutes(30).toSeconds(); + + @Test + void calculate() { + FlexPathCalculator delegate = (fromv, tov, fromStopIndex, toStopIndex) -> + new FlexPath(10_000, THIRTY_MINS_IN_SECONDS, () -> GeometryUtils.makeLineString(1, 1, 2, 2)); + + var mod = new DurationModifier(Duration.ofMinutes(10), 1.5f); + var calc = new DurationModifierCalculator(delegate, mod); + var path = calc.calculateFlexPath(StreetModelForTest.V1, StreetModelForTest.V2, 0, 5); + assertEquals(3300, path.durationSeconds); + } + + @Test + void nullValue() { + FlexPathCalculator delegate = (fromv, tov, fromStopIndex, toStopIndex) -> null; + var mod = new DurationModifier(Duration.ofMinutes(10), 1.5f); + var calc = new DurationModifierCalculator(delegate, mod); + var path = calc.calculateFlexPath(StreetModelForTest.V1, StreetModelForTest.V2, 0, 5); + assertNull(path); + } +} diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathTest.java new file mode 100644 index 00000000000..9bee310573b --- /dev/null +++ b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathTest.java @@ -0,0 +1,39 @@ +package org.opentripplanner.ext.flex.flexpathcalculator; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.time.Duration; +import java.util.List; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.locationtech.jts.geom.LineString; +import org.opentripplanner.ext.flex.trip.DurationModifier; +import org.opentripplanner.framework.geometry.GeometryUtils; + +class FlexPathTest { + + private static final int THIRTY_MINS_IN_SECONDS = (int) Duration.ofMinutes(30).toSeconds(); + private static final LineString LINE_STRING = GeometryUtils.makeLineString(1, 1, 2, 2); + private static final FlexPath PATH = new FlexPath( + 10_000, + THIRTY_MINS_IN_SECONDS, + () -> LINE_STRING + ); + + static List cases() { + return List.of( + Arguments.of(DurationModifier.NONE, THIRTY_MINS_IN_SECONDS), + Arguments.of(new DurationModifier(Duration.ofMinutes(10), 1), 2400), + Arguments.of(new DurationModifier(Duration.ofMinutes(10), 1.5f), 3300), + Arguments.of(new DurationModifier(Duration.ZERO, 3), 5400) + ); + } + + @ParameterizedTest + @MethodSource("cases") + void calculate(DurationModifier mod, int expectedSeconds) { + var modified = PATH.withDurationModifier(mod); + assertEquals(expectedSeconds, modified.durationSeconds); + } +} diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java index 5881bc798a8..e6cad4d3e40 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java @@ -4,7 +4,7 @@ import java.util.ArrayList; import java.util.List; -import org.opentripplanner.ext.flex.trip.FlexDurationModifier; +import org.opentripplanner.ext.flex.trip.DurationModifier; import org.opentripplanner.ext.flex.trip.FlexTrip; import org.opentripplanner.ext.flex.trip.ScheduledDeviatedTrip; import org.opentripplanner.ext.flex.trip.UnscheduledTrip; @@ -35,7 +35,7 @@ public class FlexTripsMapper { for (Trip trip : stopTimesByTrip.keys()) { /* Fetch the stop times for this trip. Copy the list since it's immutable. */ List stopTimes = new ArrayList<>(stopTimesByTrip.get(trip)); - var modifier = builder.getFlexDurationFactors().getOrDefault(trip, FlexDurationModifier.NONE); + var modifier = builder.getFlexDurationFactors().getOrDefault(trip, DurationModifier.NONE); if (UnscheduledTrip.isUnscheduledTrip(stopTimes)) { result.add( UnscheduledTrip diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculator.java similarity index 62% rename from src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java rename to src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculator.java index e0873fab187..643c2bb7b6f 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationFactorCalculator.java +++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculator.java @@ -1,15 +1,15 @@ package org.opentripplanner.ext.flex.flexpathcalculator; import javax.annotation.Nullable; -import org.opentripplanner.ext.flex.trip.FlexDurationModifier; +import org.opentripplanner.ext.flex.trip.DurationModifier; import org.opentripplanner.street.model.vertex.Vertex; -public class DurationFactorCalculator implements FlexPathCalculator { +public class DurationModifierCalculator implements FlexPathCalculator { private final FlexPathCalculator delegate; - private final FlexDurationModifier factors; + private final DurationModifier factors; - public DurationFactorCalculator(FlexPathCalculator delegate, FlexDurationModifier factors) { + public DurationModifierCalculator(FlexPathCalculator delegate, DurationModifier factors) { this.delegate = delegate; this.factors = factors; } @@ -22,7 +22,7 @@ public FlexPath calculateFlexPath(Vertex fromv, Vertex tov, int fromStopIndex, i if (path == null) { return null; } else { - return path.withDurationFactors(factors); + return path.withDurationModifier(factors); } } } diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java index 22752726ae7..54c11198b19 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java +++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java @@ -1,12 +1,14 @@ package org.opentripplanner.ext.flex.flexpathcalculator; import java.util.function.Supplier; +import javax.annotation.concurrent.Immutable; import org.locationtech.jts.geom.LineString; -import org.opentripplanner.ext.flex.trip.FlexDurationModifier; +import org.opentripplanner.ext.flex.trip.DurationModifier; /** * This class contains the results from a FlexPathCalculator. */ +@Immutable public class FlexPath { private final Supplier geometrySupplier; @@ -34,8 +36,11 @@ public LineString getGeometry() { return geometry; } - public FlexPath withDurationFactors(FlexDurationModifier factors) { - int updatedDuration = (int) ((durationSeconds * factors.factor()) + factors.offsetInSeconds()); + /** + * Returns an (immutable) copy of this path with the duration modified. + */ + public FlexPath withDurationModifier(DurationModifier mod) { + int updatedDuration = (int) ((durationSeconds * mod.factor()) + mod.offsetInSeconds()); return new FlexPath(distanceMeters, updatedDuration, geometrySupplier); } } diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationModifier.java b/src/ext/java/org/opentripplanner/ext/flex/trip/DurationModifier.java similarity index 79% rename from src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationModifier.java rename to src/ext/java/org/opentripplanner/ext/flex/trip/DurationModifier.java index 60f795d7280..b9abdd843ff 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/FlexDurationModifier.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/DurationModifier.java @@ -5,13 +5,13 @@ import org.opentripplanner.framework.time.DurationUtils; import org.opentripplanner.framework.tostring.ToStringBuilder; -public class FlexDurationModifier implements Serializable { +public class DurationModifier implements Serializable { - public static FlexDurationModifier NONE = new FlexDurationModifier(Duration.ZERO, 1); + public static DurationModifier NONE = new DurationModifier(Duration.ZERO, 1); private final int offset; private final float factor; - public FlexDurationModifier(Duration offset, float factor) { + public DurationModifier(Duration offset, float factor) { if (factor < 0.1) { throw new IllegalArgumentException("Flex duration factor must not be less than 0.1"); } @@ -38,7 +38,7 @@ boolean modifies() { @Override public String toString() { return ToStringBuilder - .of(FlexDurationModifier.class) + .of(DurationModifier.class) .addNum("factor", factor) .addDurationSec("offset", offset) .toString(); diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java index 33a064e610c..553fd2959a5 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java @@ -17,7 +17,7 @@ import java.util.stream.Stream; import javax.annotation.Nonnull; import org.opentripplanner.ext.flex.FlexServiceDate; -import org.opentripplanner.ext.flex.flexpathcalculator.DurationFactorCalculator; +import org.opentripplanner.ext.flex.flexpathcalculator.DurationModifierCalculator; import org.opentripplanner.ext.flex.flexpathcalculator.FlexPathCalculator; import org.opentripplanner.ext.flex.flexpathcalculator.ScheduledFlexPathCalculator; import org.opentripplanner.ext.flex.template.FlexAccessTemplate; @@ -45,7 +45,7 @@ public class ScheduledDeviatedTrip private final BookingInfo[] dropOffBookingInfos; private final BookingInfo[] pickupBookingInfos; - private final FlexDurationModifier durationModifier; + private final DurationModifier durationModifier; ScheduledDeviatedTrip(ScheduledDeviatedTripBuilder builder) { super(builder); @@ -133,7 +133,7 @@ private FlexPathCalculator getCalculator( stopTimes[fromIndex].timeType == FLEXIBLE_TIME || stopTimes[toIndex].timeType == FLEXIBLE_TIME; if (usesFlexWindow && durationModifier.modifies()) { - return new DurationFactorCalculator(scheduledCalculator, FlexDurationModifier.NONE); + return new DurationModifierCalculator(scheduledCalculator, durationModifier); } else { return scheduledCalculator; } diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripBuilder.java b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripBuilder.java index 3a33ebd50ec..3bd89ef2e02 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripBuilder.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripBuilder.java @@ -8,7 +8,7 @@ public class ScheduledDeviatedTripBuilder extends FlexTripBuilder { private List stopTimes; - private FlexDurationModifier durationModifier = FlexDurationModifier.NONE; + private DurationModifier durationModifier = DurationModifier.NONE; ScheduledDeviatedTripBuilder(FeedScopedId id) { super(id); @@ -30,11 +30,11 @@ public List stopTimes() { return stopTimes; } - public FlexDurationModifier durationModifier() { + public DurationModifier durationModifier() { return durationModifier; } - public ScheduledDeviatedTripBuilder withDurationModifier(FlexDurationModifier modifier) { + public ScheduledDeviatedTripBuilder withDurationModifier(DurationModifier modifier) { this.durationModifier = modifier; return this; } diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java index d85c6b72c27..d8e942d0c98 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java @@ -15,7 +15,7 @@ import java.util.stream.Stream; import javax.annotation.Nonnull; import org.opentripplanner.ext.flex.FlexServiceDate; -import org.opentripplanner.ext.flex.flexpathcalculator.DurationFactorCalculator; +import org.opentripplanner.ext.flex.flexpathcalculator.DurationModifierCalculator; import org.opentripplanner.ext.flex.flexpathcalculator.FlexPathCalculator; import org.opentripplanner.ext.flex.template.FlexAccessTemplate; import org.opentripplanner.ext.flex.template.FlexEgressTemplate; @@ -52,7 +52,7 @@ public class UnscheduledTrip extends FlexTrip getFlexAccessTemplates( private FlexPathCalculator flexPathCalculator(FlexPathCalculator calculator) { if (durationModifier.modifies()) { - return new DurationFactorCalculator(calculator, durationModifier); + return new DurationModifierCalculator(calculator, durationModifier); } else { return calculator; } diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java index 7e2132ed036..7b4617048a6 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java @@ -8,7 +8,7 @@ public class UnscheduledTripBuilder extends FlexTripBuilder { private List stopTimes; - private FlexDurationModifier durationModifier = FlexDurationModifier.NONE; + private DurationModifier durationModifier = DurationModifier.NONE; UnscheduledTripBuilder(FeedScopedId id) { super(id); @@ -30,12 +30,12 @@ public List stopTimes() { return stopTimes; } - public UnscheduledTripBuilder withDurationModifier(FlexDurationModifier factors) { + public UnscheduledTripBuilder withDurationModifier(DurationModifier factors) { this.durationModifier = factors; return this; } - public FlexDurationModifier durationModifier() { + public DurationModifier durationModifier() { return durationModifier; } diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java index 03ef077d319..cc6e44343e6 100644 --- a/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java +++ b/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java @@ -5,7 +5,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; -import org.opentripplanner.ext.flex.trip.FlexDurationModifier; +import org.opentripplanner.ext.flex.trip.DurationModifier; import org.opentripplanner.framework.collection.MapUtils; import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.transit.model.timetable.Trip; @@ -18,7 +18,7 @@ class TripMapper { private final TranslationHelper translationHelper; private final Map mappedTrips = new HashMap<>(); - private final Map flexSafeDurationFactors = new HashMap<>(); + private final Map flexSafeDurationFactors = new HashMap<>(); TripMapper( RouteMapper routeMapper, @@ -45,7 +45,7 @@ Collection getMappedTrips() { /** * The map of flex duration factors per flex trip. */ - Map flexSafeDurationFactors() { + Map flexSafeDurationFactors() { return flexSafeDurationFactors; } @@ -78,16 +78,12 @@ private Trip doMap(org.onebusaway.gtfs.model.Trip rhs) { return trip; } - private Optional mapSafeDurationFactors( - org.onebusaway.gtfs.model.Trip rhs - ) { + private Optional mapSafeDurationFactors(org.onebusaway.gtfs.model.Trip rhs) { if (rhs.getSafeDurationFactor() == null && rhs.getSafeDurationOffset() == null) { return Optional.empty(); } else { var offset = Duration.ofSeconds(rhs.getSafeDurationOffset().longValue()); - return Optional.of( - new FlexDurationModifier(offset, rhs.getSafeDurationFactor().floatValue()) - ); + return Optional.of(new DurationModifier(offset, rhs.getSafeDurationFactor().floatValue())); } } } diff --git a/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java b/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java index 5811fe042c3..16b7bf22388 100644 --- a/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java +++ b/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java @@ -8,7 +8,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.opentripplanner.ext.flex.trip.FlexDurationModifier; +import org.opentripplanner.ext.flex.trip.DurationModifier; import org.opentripplanner.ext.flex.trip.FlexTrip; import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.gtfs.mapping.StaySeatedNotAllowed; @@ -94,7 +94,7 @@ public class OtpTransitServiceBuilder { private final TripStopTimes stopTimesByTrip = new TripStopTimes(); - private final Map flexDurationFactors = new HashMap<>(); + private final Map flexDurationFactors = new HashMap<>(); private final EntityById fareZonesById = new DefaultEntityById<>(); @@ -213,7 +213,7 @@ public TripStopTimes getStopTimesSortedByTrip() { return stopTimesByTrip; } - public Map getFlexDurationFactors() { + public Map getFlexDurationFactors() { return flexDurationFactors; } diff --git a/src/test/java/org/opentripplanner/_support/geometry/Polygons.java b/src/test/java/org/opentripplanner/_support/geometry/Polygons.java index a386d8a27e1..ee110ab4f4f 100644 --- a/src/test/java/org/opentripplanner/_support/geometry/Polygons.java +++ b/src/test/java/org/opentripplanner/_support/geometry/Polygons.java @@ -20,7 +20,7 @@ public class Polygons { } ); - public static Polygon OSLO = FAC.createPolygon( + public static final Polygon OSLO = FAC.createPolygon( new Coordinate[] { Coordinates.of(59.961055202323195, 10.62535658370308), Coordinates.of(59.889009435700416, 10.62535658370308), @@ -29,7 +29,7 @@ public class Polygons { Coordinates.of(59.961055202323195, 10.62535658370308), } ); - public static Polygon OSLO_FROGNER_PARK = FAC.createPolygon( + public static final Polygon OSLO_FROGNER_PARK = FAC.createPolygon( new Coordinate[] { Coordinates.of(59.92939032560119, 10.69770054003061), Coordinates.of(59.929138466684975, 10.695210909925208), From 41b2e505dc14d981fa1c15f4ae203494a7c0a301 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 8 Apr 2024 00:03:09 +0200 Subject: [PATCH 082/121] Extract class for building flex stop times --- .../ext/flex/FlexStopTimesForTest.java | 49 +++++++++++++++++++ .../DurationModifierCalculatorTest.java | 4 +- .../flex/flexpathcalculator/FlexPathTest.java | 6 +-- .../ScheduledFlexPathCalculatorTest.java | 38 ++++++++++++++ .../ext/flex/trip/UnscheduledTripTest.java | 42 +++------------- .../ext/flex/FlexibleTransitLeg.java | 1 + .../_support/geometry/LineStrings.java | 9 ++++ 7 files changed, 108 insertions(+), 41 deletions(-) create mode 100644 src/ext-test/java/org/opentripplanner/ext/flex/FlexStopTimesForTest.java create mode 100644 src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/ScheduledFlexPathCalculatorTest.java create mode 100644 src/test/java/org/opentripplanner/_support/geometry/LineStrings.java diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/FlexStopTimesForTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/FlexStopTimesForTest.java new file mode 100644 index 00000000000..d76382999a2 --- /dev/null +++ b/src/ext-test/java/org/opentripplanner/ext/flex/FlexStopTimesForTest.java @@ -0,0 +1,49 @@ +package org.opentripplanner.ext.flex; + +import static org.opentripplanner.model.StopTime.MISSING_VALUE; + +import org.opentripplanner._support.geometry.Polygons; +import org.opentripplanner.framework.time.TimeUtils; +import org.opentripplanner.model.StopTime; +import org.opentripplanner.transit.model._data.TransitModelForTest; +import org.opentripplanner.transit.model.site.RegularStop; +import org.opentripplanner.transit.model.site.StopLocation; + +public class FlexStopTimesForTest { + + private static final TransitModelForTest TEST_MODEL = TransitModelForTest.of(); + private static final StopLocation AREA_STOP = TEST_MODEL.areaStopForTest("area", Polygons.BERLIN); + private static final RegularStop REGULAR_STOP = TEST_MODEL.stop("stop").build(); + + public static StopTime area(String startTime, String endTime) { + return area(AREA_STOP, endTime, startTime); + } + + public static StopTime area(StopLocation areaStop, String endTime, String startTime) { + var stopTime = new StopTime(); + stopTime.setStop(areaStop); + stopTime.setFlexWindowStart(TimeUtils.time(startTime)); + stopTime.setFlexWindowEnd(TimeUtils.time(endTime)); + return stopTime; + } + + public static StopTime regularArrival(String arrivalTime) { + return regularStopTime(TimeUtils.time(arrivalTime), MISSING_VALUE); + } + + public static StopTime regularStopTime(String arrivalTime, String departureTime) { + return regularStopTime(TimeUtils.time(arrivalTime), TimeUtils.time(departureTime)); + } + + public static StopTime regularStopTime(int arrivalTime, int departureTime) { + var stopTime = new StopTime(); + stopTime.setStop(REGULAR_STOP); + stopTime.setArrivalTime(arrivalTime); + stopTime.setDepartureTime(departureTime); + return stopTime; + } + + public static StopTime regularDeparture(String departureTime) { + return regularStopTime(MISSING_VALUE, TimeUtils.time(departureTime)); + } +} diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculatorTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculatorTest.java index fd81344893b..f610cbe09c4 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculatorTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculatorTest.java @@ -5,8 +5,8 @@ import java.time.Duration; import org.junit.jupiter.api.Test; +import org.opentripplanner._support.geometry.LineStrings; import org.opentripplanner.ext.flex.trip.DurationModifier; -import org.opentripplanner.framework.geometry.GeometryUtils; import org.opentripplanner.street.model._data.StreetModelForTest; class DurationModifierCalculatorTest { @@ -16,7 +16,7 @@ class DurationModifierCalculatorTest { @Test void calculate() { FlexPathCalculator delegate = (fromv, tov, fromStopIndex, toStopIndex) -> - new FlexPath(10_000, THIRTY_MINS_IN_SECONDS, () -> GeometryUtils.makeLineString(1, 1, 2, 2)); + new FlexPath(10_000, THIRTY_MINS_IN_SECONDS, () -> LineStrings.SIMPLE); var mod = new DurationModifier(Duration.ofMinutes(10), 1.5f); var calc = new DurationModifierCalculator(delegate, mod); diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathTest.java index 9bee310573b..6a4c79ca2cc 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathTest.java @@ -7,18 +7,16 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.locationtech.jts.geom.LineString; +import org.opentripplanner._support.geometry.LineStrings; import org.opentripplanner.ext.flex.trip.DurationModifier; -import org.opentripplanner.framework.geometry.GeometryUtils; class FlexPathTest { private static final int THIRTY_MINS_IN_SECONDS = (int) Duration.ofMinutes(30).toSeconds(); - private static final LineString LINE_STRING = GeometryUtils.makeLineString(1, 1, 2, 2); private static final FlexPath PATH = new FlexPath( 10_000, THIRTY_MINS_IN_SECONDS, - () -> LINE_STRING + () -> LineStrings.SIMPLE ); static List cases() { diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/ScheduledFlexPathCalculatorTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/ScheduledFlexPathCalculatorTest.java new file mode 100644 index 00000000000..70f39af2420 --- /dev/null +++ b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/ScheduledFlexPathCalculatorTest.java @@ -0,0 +1,38 @@ +package org.opentripplanner.ext.flex.flexpathcalculator; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.ext.flex.FlexStopTimesForTest.area; +import static org.opentripplanner.ext.flex.FlexStopTimesForTest.regularStopTime; +import static org.opentripplanner.street.model._data.StreetModelForTest.V1; +import static org.opentripplanner.street.model._data.StreetModelForTest.V2; +import static org.opentripplanner.transit.model._data.TransitModelForTest.id; + +import java.time.Duration; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.opentripplanner._support.geometry.LineStrings; +import org.opentripplanner.ext.flex.trip.ScheduledDeviatedTrip; + +class ScheduledFlexPathCalculatorTest { + + private static final ScheduledDeviatedTrip TRIP = ScheduledDeviatedTrip + .of(id("123")) + .withStopTimes( + List.of( + regularStopTime("10:00", "10:01"), + area("10:10", "10:20"), + regularStopTime("10:25", "10:26"), + area("10:40", "10:50") + ) + ) + .build(); + + @Test + void calculateTime() { + var c = (FlexPathCalculator) (fromv, tov, fromStopIndex, toStopIndex) -> + new FlexPath(10_000, (int) Duration.ofMinutes(10).toSeconds(), () -> LineStrings.SIMPLE); + var calc = new ScheduledFlexPathCalculator(c, TRIP); + var path = calc.calculateFlexPath(V1, V2, 0, 1); + assertEquals(Duration.ofMinutes(19), Duration.ofSeconds(path.durationSeconds)); + } +} diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledTripTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledTripTest.java index fabe534ff23..bfcd9bad565 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledTripTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledTripTest.java @@ -3,6 +3,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.opentripplanner.ext.flex.FlexStopTimesForTest.area; import static org.opentripplanner.ext.flex.trip.UnscheduledTrip.isUnscheduledTrip; import static org.opentripplanner.ext.flex.trip.UnscheduledTripTest.TestCase.tc; import static org.opentripplanner.model.PickDrop.NONE; @@ -22,6 +23,7 @@ import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner._support.geometry.Polygons; import org.opentripplanner.ext.flex.FlexServiceDate; +import org.opentripplanner.ext.flex.FlexStopTimesForTest; import org.opentripplanner.ext.flex.flexpathcalculator.DirectFlexPathCalculator; import org.opentripplanner.ext.flex.template.FlexAccessTemplate; import org.opentripplanner.ext.flex.template.FlexEgressTemplate; @@ -48,11 +50,10 @@ class UnscheduledTripTest { private static final int T15_00 = TimeUtils.hm2time(15, 0); private static final TransitModelForTest TEST_MODEL = TransitModelForTest.of(); + private static final StopLocation AREA_STOP = TEST_MODEL.areaStopForTest("area", Polygons.BERLIN); private static final RegularStop REGULAR_STOP = TEST_MODEL.stop("stop").build(); - private static final StopLocation AREA_STOP = TEST_MODEL.areaStopForTest("area", Polygons.BERLIN); - @Nested class IsUnscheduledTrip { @@ -196,7 +197,7 @@ void testUnscheduledFeederTripToScheduledStop() { static Stream testRegularStopToAreaEarliestDepartureTimeTestCases() { // REGULAR-STOP to AREA - (10:00-14:00) => (14:00) - var tc = tc(regularDeparture("10:00"), area("10:00", "14:00")); + var tc = tc(FlexStopTimesForTest.regularDeparture("10:00"), area("10:00", "14:00")); return Stream.of( tc .expected("Requested departure time is before flex service departure time", "10:00") @@ -245,7 +246,7 @@ void testRegularStopToAreaEarliestDepartureTime(TestCase tc) { static Stream testAreaToRegularStopEarliestDepartureTestCases() { // AREA TO REGULAR-STOP - (10:00-14:00) => (14:00) - var tc = tc(area("10:00", "14:00"), regularArrival("14:00")); + var tc = tc(area("10:00", "14:00"), FlexStopTimesForTest.regularArrival("14:00")); return Stream.of( tc .expected( @@ -366,7 +367,7 @@ void testAreaToAreaEarliestDepartureTime(TestCase tc) { static Stream testRegularStopToAreaLatestArrivalTimeTestCases() { // REGULAR-STOP to AREA - (10:00-14:00) => (14:00) - var tc = tc(regularDeparture("10:00"), area("10:00", "14:00")); + var tc = tc(FlexStopTimesForTest.regularDeparture("10:00"), area("10:00", "14:00")); return Stream.of( tc .expectedNotFound("Requested arrival time is before flex service arrival window start") @@ -421,7 +422,7 @@ void testRegularStopToAreaLatestArrivalTime(TestCase tc) { static Stream testAreaToRegularStopLatestArrivalTimeTestCases() { // AREA TO REGULAR-STOP - (10:00-14:00) => (14:00) - var tc = tc(area("10:00", "14:00"), regularArrival("14:00")); + var tc = tc(area("10:00", "14:00"), FlexStopTimesForTest.regularArrival("14:00")); return Stream.of( tc .expectedNotFound("Requested arrival time is before flex service arrival window start") @@ -661,35 +662,6 @@ private static String timeToString(int time) { return TimeUtils.timeToStrCompact(time, MISSING_VALUE, "MISSING_VALUE"); } - private static StopTime area(String startTime, String endTime) { - return area(AREA_STOP, endTime, startTime); - } - - @Nonnull - private static StopTime area(StopLocation areaStop, String endTime, String startTime) { - var stopTime = new StopTime(); - stopTime.setStop(areaStop); - stopTime.setFlexWindowStart(TimeUtils.time(startTime)); - stopTime.setFlexWindowEnd(TimeUtils.time(endTime)); - return stopTime; - } - - private static StopTime regularDeparture(String departureTime) { - return regularStopTime(MISSING_VALUE, TimeUtils.time(departureTime)); - } - - private static StopTime regularArrival(String arrivalTime) { - return regularStopTime(TimeUtils.time(arrivalTime), MISSING_VALUE); - } - - private static StopTime regularStopTime(int arrivalTime, int departureTime) { - var stopTime = new StopTime(); - stopTime.setStop(REGULAR_STOP); - stopTime.setArrivalTime(arrivalTime); - stopTime.setDepartureTime(departureTime); - return stopTime; - } - @Nonnull private static NearbyStop nearbyStop(AreaStop stop) { return new NearbyStop(stop, 1000, List.of(), null); diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java index fac1118556f..b9e10e29214 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java @@ -196,6 +196,7 @@ public int getGeneralizedCost() { return generalizedCost; } + @Override public void addAlert(TransitAlert alert) { transitAlerts.add(alert); } diff --git a/src/test/java/org/opentripplanner/_support/geometry/LineStrings.java b/src/test/java/org/opentripplanner/_support/geometry/LineStrings.java new file mode 100644 index 00000000000..515f161be92 --- /dev/null +++ b/src/test/java/org/opentripplanner/_support/geometry/LineStrings.java @@ -0,0 +1,9 @@ +package org.opentripplanner._support.geometry; + +import org.locationtech.jts.geom.LineString; +import org.opentripplanner.framework.geometry.GeometryUtils; + +public class LineStrings { + + public static final LineString SIMPLE = GeometryUtils.makeLineString(0, 0, 1, 1); +} From dec30cd3c95d788e2bb7691ec2ae73c611adcc00 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 9 Apr 2024 09:57:06 +0200 Subject: [PATCH 083/121] Remove durationModifier to ScheduledDeviatedTrip --- .../ext/flex/FlexTripsMapper.java | 3 +-- .../ext/flex/trip/ScheduledDeviatedTrip.java | 27 ++----------------- .../trip/ScheduledDeviatedTripBuilder.java | 10 ------- 3 files changed, 3 insertions(+), 37 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java index e6cad4d3e40..b4123a3b556 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java @@ -35,8 +35,8 @@ public class FlexTripsMapper { for (Trip trip : stopTimesByTrip.keys()) { /* Fetch the stop times for this trip. Copy the list since it's immutable. */ List stopTimes = new ArrayList<>(stopTimesByTrip.get(trip)); - var modifier = builder.getFlexDurationFactors().getOrDefault(trip, DurationModifier.NONE); if (UnscheduledTrip.isUnscheduledTrip(stopTimes)) { + var modifier = builder.getFlexDurationFactors().getOrDefault(trip, DurationModifier.NONE); result.add( UnscheduledTrip .of(trip.getId()) @@ -51,7 +51,6 @@ public class FlexTripsMapper { .of(trip.getId()) .withTrip(trip) .withStopTimes(stopTimes) - .withDurationModifier(modifier) .build() ); } else if (hasContinuousStops(stopTimes) && FlexTrip.containsFlexStops(stopTimes)) { diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java index 553fd2959a5..84982c837dc 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java @@ -17,7 +17,6 @@ import java.util.stream.Stream; import javax.annotation.Nonnull; import org.opentripplanner.ext.flex.FlexServiceDate; -import org.opentripplanner.ext.flex.flexpathcalculator.DurationModifierCalculator; import org.opentripplanner.ext.flex.flexpathcalculator.FlexPathCalculator; import org.opentripplanner.ext.flex.flexpathcalculator.ScheduledFlexPathCalculator; import org.opentripplanner.ext.flex.template.FlexAccessTemplate; @@ -45,8 +44,6 @@ public class ScheduledDeviatedTrip private final BookingInfo[] dropOffBookingInfos; private final BookingInfo[] pickupBookingInfos; - private final DurationModifier durationModifier; - ScheduledDeviatedTrip(ScheduledDeviatedTripBuilder builder) { super(builder); List stopTimes = builder.stopTimes(); @@ -64,7 +61,6 @@ public class ScheduledDeviatedTrip this.dropOffBookingInfos[i] = stopTimes.get(i).getDropOffBookingInfo(); this.pickupBookingInfos[i] = stopTimes.get(i).getPickupBookingInfo(); } - this.durationModifier = builder.durationModifier(); } public static ScheduledDeviatedTripBuilder of(FeedScopedId id) { @@ -110,7 +106,7 @@ public Stream getFlexAccessTemplates( toIndex, stop, date, - getCalculator(fromIndex, toIndex, scheduledCalculator), + scheduledCalculator, config ) ); @@ -120,25 +116,6 @@ public Stream getFlexAccessTemplates( return res.stream(); } - /** - * If any of the stops involved in the path computation, then apply the duration factors. - * If both from and to have a fixed time, then don't apply the factors. - */ - private FlexPathCalculator getCalculator( - int fromIndex, - int toIndex, - FlexPathCalculator scheduledCalculator - ) { - final boolean usesFlexWindow = - stopTimes[fromIndex].timeType == FLEXIBLE_TIME || - stopTimes[toIndex].timeType == FLEXIBLE_TIME; - if (usesFlexWindow && durationModifier.modifies()) { - return new DurationModifierCalculator(scheduledCalculator, durationModifier); - } else { - return scheduledCalculator; - } - } - @Override public Stream getFlexEgressTemplates( NearbyStop egress, @@ -169,7 +146,7 @@ public Stream getFlexEgressTemplates( toIndex, stop, date, - getCalculator(fromIndex, toIndex, scheduledCalculator), + scheduledCalculator, config ) ); diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripBuilder.java b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripBuilder.java index 3bd89ef2e02..4033bbe7c59 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripBuilder.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripBuilder.java @@ -8,7 +8,6 @@ public class ScheduledDeviatedTripBuilder extends FlexTripBuilder { private List stopTimes; - private DurationModifier durationModifier = DurationModifier.NONE; ScheduledDeviatedTripBuilder(FeedScopedId id) { super(id); @@ -30,15 +29,6 @@ public List stopTimes() { return stopTimes; } - public DurationModifier durationModifier() { - return durationModifier; - } - - public ScheduledDeviatedTripBuilder withDurationModifier(DurationModifier modifier) { - this.durationModifier = modifier; - return this; - } - @Override ScheduledDeviatedTripBuilder instance() { return this; From 354c96839897497b91615971e40775b5d3e3fafa Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 9 Apr 2024 12:37:01 +0200 Subject: [PATCH 084/121] Add test and docs for DurationModifier --- .../ext/flex/trip/DurationModifierTest.java | 20 +++++++++++++++++++ .../ext/flex/trip/DurationModifier.java | 7 +++++++ 2 files changed, 27 insertions(+) create mode 100644 src/ext-test/java/org/opentripplanner/ext/flex/trip/DurationModifierTest.java diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/trip/DurationModifierTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/trip/DurationModifierTest.java new file mode 100644 index 00000000000..c6f4e75f7c5 --- /dev/null +++ b/src/ext-test/java/org/opentripplanner/ext/flex/trip/DurationModifierTest.java @@ -0,0 +1,20 @@ +package org.opentripplanner.ext.flex.trip; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.Duration; +import org.junit.jupiter.api.Test; + +class DurationModifierTest { + + @Test + void doesNotModify() { + assertFalse(DurationModifier.NONE.modifies()); + } + + @Test + void modifies() { + assertTrue(new DurationModifier(Duration.ofMinutes(1), 1.5f).modifies()); + } +} \ No newline at end of file diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/DurationModifier.java b/src/ext/java/org/opentripplanner/ext/flex/trip/DurationModifier.java index b9abdd843ff..4832a7cc9bc 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/DurationModifier.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/DurationModifier.java @@ -5,12 +5,19 @@ import org.opentripplanner.framework.time.DurationUtils; import org.opentripplanner.framework.tostring.ToStringBuilder; +/** + * A modifier to influence the A*-calculated driving time of flex trips. + */ public class DurationModifier implements Serializable { public static DurationModifier NONE = new DurationModifier(Duration.ZERO, 1); private final int offset; private final float factor; + /** + * @param offset A fixed offset to add to the driving time. + * @param factor A factor to multiply the driving time with. + */ public DurationModifier(Duration offset, float factor) { if (factor < 0.1) { throw new IllegalArgumentException("Flex duration factor must not be less than 0.1"); From 991406ed25845660bd0a25e972e86c66227b7409 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 9 Apr 2024 13:42:44 +0200 Subject: [PATCH 085/121] Cleanup, tests and documentation --- doc-templates/Flex.md | 4 +- docs/sandbox/Flex.md | 4 +- .../flex/flexpathcalculator/FlexPathTest.java | 1 + .../ext/flex/trip/DurationModifierTest.java | 2 +- .../trip/UnscheduledDrivingDurationTest.java | 44 ++++++++++++++++++ .../ext/flex/trip/UnscheduledTripTest.java | 11 ++--- .../ext/flex/FlexTripsMapper.java | 6 +-- .../DurationModifierCalculator.java | 4 ++ .../ext/flex/trip/ScheduledDeviatedTrip.java | 10 ----- .../ext/flex/trip/UnscheduledTrip.java | 6 ++- .../GTFSToOtpTransitServiceMapper.java | 2 +- .../gtfs/mapping/TripMapper.java | 10 ++--- .../gtfs/mapping/TripMapperTest.java | 45 ++++++++++++++----- 13 files changed, 107 insertions(+), 42 deletions(-) create mode 100644 src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledDrivingDurationTest.java diff --git a/doc-templates/Flex.md b/doc-templates/Flex.md index 2015e898cae..50512f66133 100644 --- a/doc-templates/Flex.md +++ b/doc-templates/Flex.md @@ -10,8 +10,8 @@ To enable this turn on `FlexRouting` as a feature in `otp-config.json`. -The GTFS feeds should conform to the -[GTFS-Flex v2 draft PR](https://github.com/google/transit/pull/388) +The GTFS feeds must conform to the final, approved version of the draft which has been +merged into the [mainline specification](https://gtfs.org/schedule/reference/) in March 2024. ## Configuration diff --git a/docs/sandbox/Flex.md b/docs/sandbox/Flex.md index 61d15851a56..277e4e617f2 100644 --- a/docs/sandbox/Flex.md +++ b/docs/sandbox/Flex.md @@ -10,8 +10,8 @@ To enable this turn on `FlexRouting` as a feature in `otp-config.json`. -The GTFS feeds should conform to the -[GTFS-Flex v2 draft PR](https://github.com/google/transit/pull/388) +The GTFS feeds must conform to the final, approved version of the draft which has been +merged into the [mainline specification](https://gtfs.org/schedule/reference/) in March 2024. ## Configuration diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathTest.java index 6a4c79ca2cc..b79093e26c5 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathTest.java @@ -33,5 +33,6 @@ static List cases() { void calculate(DurationModifier mod, int expectedSeconds) { var modified = PATH.withDurationModifier(mod); assertEquals(expectedSeconds, modified.durationSeconds); + assertEquals(LineStrings.SIMPLE, modified.getGeometry()); } } diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/trip/DurationModifierTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/trip/DurationModifierTest.java index c6f4e75f7c5..05fb9965935 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/trip/DurationModifierTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/trip/DurationModifierTest.java @@ -17,4 +17,4 @@ void doesNotModify() { void modifies() { assertTrue(new DurationModifier(Duration.ofMinutes(1), 1.5f).modifies()); } -} \ No newline at end of file +} diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledDrivingDurationTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledDrivingDurationTest.java new file mode 100644 index 00000000000..45d8c5be624 --- /dev/null +++ b/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledDrivingDurationTest.java @@ -0,0 +1,44 @@ +package org.opentripplanner.ext.flex.trip; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.street.model._data.StreetModelForTest.V1; +import static org.opentripplanner.street.model._data.StreetModelForTest.V2; +import static org.opentripplanner.transit.model._data.TransitModelForTest.id; + +import java.time.Duration; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.opentripplanner._support.geometry.LineStrings; +import org.opentripplanner.ext.flex.FlexStopTimesForTest; +import org.opentripplanner.ext.flex.flexpathcalculator.FlexPath; +import org.opentripplanner.ext.flex.flexpathcalculator.FlexPathCalculator; +import org.opentripplanner.model.StopTime; + +class UnscheduledDrivingDurationTest { + + static final FlexPathCalculator STATIC_CALCULATOR = (fromv, tov, fromStopIndex, toStopIndex) -> + new FlexPath(10_000, (int) Duration.ofMinutes(10).toSeconds(), () -> LineStrings.SIMPLE); + private static final StopTime STOP_TIME = FlexStopTimesForTest.area("10:00", "18:00"); + + @Test + void noModifier() { + var trip = UnscheduledTrip.of(id("1")).withStopTimes(List.of(STOP_TIME)).build(); + + var calculator = trip.flexPathCalculator(STATIC_CALCULATOR); + var path = calculator.calculateFlexPath(V1, V2, 0, 0); + assertEquals(600, path.durationSeconds); + } + + @Test + void withModifier() { + var trip = UnscheduledTrip + .of(id("1")) + .withStopTimes(List.of(STOP_TIME)) + .withDurationModifier(new DurationModifier(Duration.ofMinutes(2), 1.5f)) + .build(); + + var calculator = trip.flexPathCalculator(STATIC_CALCULATOR); + var path = calculator.calculateFlexPath(V1, V2, 0, 0); + assertEquals(1020, path.durationSeconds); + } +} diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledTripTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledTripTest.java index bfcd9bad565..80bda31fabf 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledTripTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledTripTest.java @@ -4,6 +4,8 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.opentripplanner.ext.flex.FlexStopTimesForTest.area; +import static org.opentripplanner.ext.flex.FlexStopTimesForTest.regularArrival; +import static org.opentripplanner.ext.flex.FlexStopTimesForTest.regularDeparture; import static org.opentripplanner.ext.flex.trip.UnscheduledTrip.isUnscheduledTrip; import static org.opentripplanner.ext.flex.trip.UnscheduledTripTest.TestCase.tc; import static org.opentripplanner.model.PickDrop.NONE; @@ -23,7 +25,6 @@ import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner._support.geometry.Polygons; import org.opentripplanner.ext.flex.FlexServiceDate; -import org.opentripplanner.ext.flex.FlexStopTimesForTest; import org.opentripplanner.ext.flex.flexpathcalculator.DirectFlexPathCalculator; import org.opentripplanner.ext.flex.template.FlexAccessTemplate; import org.opentripplanner.ext.flex.template.FlexEgressTemplate; @@ -197,7 +198,7 @@ void testUnscheduledFeederTripToScheduledStop() { static Stream testRegularStopToAreaEarliestDepartureTimeTestCases() { // REGULAR-STOP to AREA - (10:00-14:00) => (14:00) - var tc = tc(FlexStopTimesForTest.regularDeparture("10:00"), area("10:00", "14:00")); + var tc = tc(regularDeparture("10:00"), area("10:00", "14:00")); return Stream.of( tc .expected("Requested departure time is before flex service departure time", "10:00") @@ -246,7 +247,7 @@ void testRegularStopToAreaEarliestDepartureTime(TestCase tc) { static Stream testAreaToRegularStopEarliestDepartureTestCases() { // AREA TO REGULAR-STOP - (10:00-14:00) => (14:00) - var tc = tc(area("10:00", "14:00"), FlexStopTimesForTest.regularArrival("14:00")); + var tc = tc(area("10:00", "14:00"), regularArrival("14:00")); return Stream.of( tc .expected( @@ -367,7 +368,7 @@ void testAreaToAreaEarliestDepartureTime(TestCase tc) { static Stream testRegularStopToAreaLatestArrivalTimeTestCases() { // REGULAR-STOP to AREA - (10:00-14:00) => (14:00) - var tc = tc(FlexStopTimesForTest.regularDeparture("10:00"), area("10:00", "14:00")); + var tc = tc(regularDeparture("10:00"), area("10:00", "14:00")); return Stream.of( tc .expectedNotFound("Requested arrival time is before flex service arrival window start") @@ -422,7 +423,7 @@ void testRegularStopToAreaLatestArrivalTime(TestCase tc) { static Stream testAreaToRegularStopLatestArrivalTimeTestCases() { // AREA TO REGULAR-STOP - (10:00-14:00) => (14:00) - var tc = tc(area("10:00", "14:00"), FlexStopTimesForTest.regularArrival("14:00")); + var tc = tc(area("10:00", "14:00"), regularArrival("14:00")); return Stream.of( tc .expectedNotFound("Requested arrival time is before flex service arrival window start") diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java index b4123a3b556..bb2ed2764f6 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java @@ -47,11 +47,7 @@ public class FlexTripsMapper { ); } else if (ScheduledDeviatedTrip.isScheduledFlexTrip(stopTimes)) { result.add( - ScheduledDeviatedTrip - .of(trip.getId()) - .withTrip(trip) - .withStopTimes(stopTimes) - .build() + ScheduledDeviatedTrip.of(trip.getId()).withTrip(trip).withStopTimes(stopTimes).build() ); } else if (hasContinuousStops(stopTimes) && FlexTrip.containsFlexStops(stopTimes)) { store.add( diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculator.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculator.java index 643c2bb7b6f..158e6a933c7 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculator.java +++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculator.java @@ -4,6 +4,10 @@ import org.opentripplanner.ext.flex.trip.DurationModifier; import org.opentripplanner.street.model.vertex.Vertex; +/** + * A calculator to delegates the main computation to another instance and applies a duration + * modifier afterward. + */ public class DurationModifierCalculator implements FlexPathCalculator { private final FlexPathCalculator delegate; diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java index 84982c837dc..0026d98c964 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java @@ -1,7 +1,5 @@ package org.opentripplanner.ext.flex.trip; -import static org.opentripplanner.ext.flex.trip.ScheduledDeviatedTrip.TimeType.FIXED_TIME; -import static org.opentripplanner.ext.flex.trip.ScheduledDeviatedTrip.TimeType.FLEXIBLE_TIME; import static org.opentripplanner.model.PickDrop.NONE; import static org.opentripplanner.model.StopTime.MISSING_VALUE; @@ -299,13 +297,10 @@ private static class ScheduledDeviatedStopTime implements Serializable { private final int arrivalTime; private final PickDrop pickupType; private final PickDrop dropOffType; - private final TimeType timeType; private ScheduledDeviatedStopTime(StopTime st) { this.stop = st.getStop(); - this.timeType = st.hasFlexWindow() ? FLEXIBLE_TIME : FIXED_TIME; - // Store the time the user is guaranteed to arrive at latest this.arrivalTime = st.getLatestPossibleArrivalTime(); // Store the time the user needs to be ready for pickup @@ -320,9 +315,4 @@ private ScheduledDeviatedStopTime(StopTime st) { this.dropOffType = arrivalTime == MISSING_VALUE ? PickDrop.NONE : st.getDropOffType(); } } - - enum TimeType { - FIXED_TIME, - FLEXIBLE_TIME, - } } diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java index d8e942d0c98..bc3bd52cc4c 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java @@ -149,7 +149,11 @@ public Stream getFlexAccessTemplates( ); } - private FlexPathCalculator flexPathCalculator(FlexPathCalculator calculator) { + /** + * Get the correct {@link FlexPathCalculator} depending on the {@code durationModified}. + * If the modifier doesn't actually modify, we don't + */ + protected FlexPathCalculator flexPathCalculator(FlexPathCalculator calculator) { if (durationModifier.modifies()) { return new DurationModifierCalculator(calculator, durationModifier); } else { diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java index 4ee1cdcf1d7..24db367f829 100644 --- a/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java +++ b/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java @@ -171,7 +171,7 @@ public void mapStopTripAndRouteDataIntoBuilder() { builder.getPathways().addAll(pathwayMapper.map(data.getAllPathways())); builder.getStopTimesSortedByTrip().addAll(stopTimeMapper.map(data.getAllStopTimes())); - builder.getFlexDurationFactors().putAll(tripMapper.flexSafeDurationFactors()); + builder.getFlexDurationFactors().putAll(tripMapper.flexSafeDurationModifiers()); builder.getTripsById().addAll(tripMapper.map(data.getAllTrips())); fareRulesBuilder.fareAttributes().addAll(fareAttributeMapper.map(data.getAllFareAttributes())); diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java index cc6e44343e6..ec7d1379ca0 100644 --- a/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java +++ b/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java @@ -18,7 +18,7 @@ class TripMapper { private final TranslationHelper translationHelper; private final Map mappedTrips = new HashMap<>(); - private final Map flexSafeDurationFactors = new HashMap<>(); + private final Map flexSafeDurationModifiers = new HashMap<>(); TripMapper( RouteMapper routeMapper, @@ -45,8 +45,8 @@ Collection getMappedTrips() { /** * The map of flex duration factors per flex trip. */ - Map flexSafeDurationFactors() { - return flexSafeDurationFactors; + Map flexSafeDurationModifiers() { + return flexSafeDurationModifiers; } private Trip doMap(org.onebusaway.gtfs.model.Trip rhs) { @@ -74,11 +74,11 @@ private Trip doMap(org.onebusaway.gtfs.model.Trip rhs) { lhs.withGtfsFareId(rhs.getFareId()); var trip = lhs.build(); - mapSafeDurationFactors(rhs).ifPresent(f -> flexSafeDurationFactors.put(trip, f)); + mapSafeDurationModifier(rhs).ifPresent(f -> flexSafeDurationModifiers.put(trip, f)); return trip; } - private Optional mapSafeDurationFactors(org.onebusaway.gtfs.model.Trip rhs) { + private Optional mapSafeDurationModifier(org.onebusaway.gtfs.model.Trip rhs) { if (rhs.getSafeDurationFactor() == null && rhs.getSafeDurationOffset() == null) { return Optional.empty(); } else { diff --git a/src/test/java/org/opentripplanner/gtfs/mapping/TripMapperTest.java b/src/test/java/org/opentripplanner/gtfs/mapping/TripMapperTest.java index 4f0c70f22d2..141c1d5bf6b 100644 --- a/src/test/java/org/opentripplanner/gtfs/mapping/TripMapperTest.java +++ b/src/test/java/org/opentripplanner/gtfs/mapping/TripMapperTest.java @@ -33,11 +33,15 @@ public class TripMapperTest { public static final DataImportIssueStore ISSUE_STORE = DataImportIssueStore.NOOP; - private final TripMapper subject = new TripMapper( - new RouteMapper(new AgencyMapper(FEED_ID), ISSUE_STORE, new TranslationHelper()), - new DirectionMapper(ISSUE_STORE), - new TranslationHelper() - ); + private final TripMapper subject = defaultTripMapper(); + + private static TripMapper defaultTripMapper() { + return new TripMapper( + new RouteMapper(new AgencyMapper(FEED_ID), ISSUE_STORE, new TranslationHelper()), + new DirectionMapper(ISSUE_STORE), + new TranslationHelper() + ); + } static { GtfsTestData data = new GtfsTestData(); @@ -56,14 +60,14 @@ public class TripMapperTest { } @Test - public void testMapCollection() throws Exception { + void testMapCollection() throws Exception { assertNull(subject.map((Collection) null)); assertTrue(subject.map(Collections.emptyList()).isEmpty()); assertEquals(1, subject.map(Collections.singleton(TRIP)).size()); } @Test - public void testMap() throws Exception { + void testMap() throws Exception { org.opentripplanner.transit.model.timetable.Trip result = subject.map(TRIP); assertEquals("A:1", result.getId().toString()); @@ -80,7 +84,7 @@ public void testMap() throws Exception { } @Test - public void testMapWithNulls() throws Exception { + void testMapWithNulls() throws Exception { Trip input = new Trip(); input.setId(AGENCY_AND_ID); input.setRoute(new GtfsTestData().route); @@ -101,12 +105,33 @@ public void testMapWithNulls() throws Exception { assertEquals(BikeAccess.UNKNOWN, result.getBikesAllowed()); } - /** Mapping the same object twice, should return the the same instance. */ + /** Mapping the same object twice, should return the same instance. */ @Test - public void testMapCache() throws Exception { + void testMapCache() throws Exception { org.opentripplanner.transit.model.timetable.Trip result1 = subject.map(TRIP); org.opentripplanner.transit.model.timetable.Trip result2 = subject.map(TRIP); assertSame(result1, result2); } + + @Test + void noFlexDurationModifier() { + var mapper = defaultTripMapper(); + mapper.map(TRIP); + assertTrue(mapper.flexSafeDurationModifiers().isEmpty()); + } + + @Test + void flexDurationModifier() { + var flexTrip = new Trip(); + flexTrip.setId(new AgencyAndId("1", "1")); + flexTrip.setSafeDurationFactor(1.5); + flexTrip.setSafeDurationOffset(600d); + flexTrip.setRoute(new GtfsTestData().route); + var mapper = defaultTripMapper(); + var mapped = mapper.map(flexTrip); + var mod = mapper.flexSafeDurationModifiers().get(mapped); + assertEquals(1.5f, mod.factor()); + assertEquals(600, mod.offsetInSeconds()); + } } From 591296b9d7d9b900e016e7dccc67cb9ee5119a66 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 01:20:50 +0000 Subject: [PATCH 086/121] Update Debug UI dependencies (non-major) --- client-next/package-lock.json | 251 ++++++++++++++++------------------ client-next/package.json | 16 +-- 2 files changed, 123 insertions(+), 144 deletions(-) diff --git a/client-next/package-lock.json b/client-next/package-lock.json index 6ac0e07e20f..08a9146ceb1 100644 --- a/client-next/package-lock.json +++ b/client-next/package-lock.json @@ -24,12 +24,12 @@ "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.4.1", "@testing-library/react": "15.0.2", - "@types/react": "18.2.73", - "@types/react-dom": "18.2.23", - "@typescript-eslint/eslint-plugin": "7.5.0", - "@typescript-eslint/parser": "7.5.0", + "@types/react": "18.2.79", + "@types/react-dom": "18.2.25", + "@typescript-eslint/eslint-plugin": "7.7.0", + "@typescript-eslint/parser": "7.7.0", "@vitejs/plugin-react": "4.2.1", - "@vitest/coverage-v8": "1.4.0", + "@vitest/coverage-v8": "1.5.0", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "2.29.1", @@ -39,9 +39,9 @@ "eslint-plugin-react-refresh": "0.4.6", "jsdom": "24.0.0", "prettier": "3.2.5", - "typescript": "5.4.3", - "vite": "5.2.7", - "vitest": "1.4.0" + "typescript": "5.4.5", + "vite": "5.2.8", + "vitest": "1.5.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -3455,12 +3455,6 @@ "@types/geojson": "*" } }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true - }, "node_modules/@types/js-yaml": { "version": "4.0.9", "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", @@ -3528,18 +3522,18 @@ "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "node_modules/@types/react": { - "version": "18.2.73", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.73.tgz", - "integrity": "sha512-XcGdod0Jjv84HOC7N5ziY3x+qL0AfmubvKOZ9hJjJ2yd5EE+KYjWhdOjt387e9HPheHkdggF9atTifMRtyAaRA==", + "version": "18.2.79", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.79.tgz", + "integrity": "sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.2.23", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.23.tgz", - "integrity": "sha512-ZQ71wgGOTmDYpnav2knkjr3qXdAFu0vsk8Ci5w3pGAIdj7/kKAyn+VsQDhXsmzzzepAiI9leWMmubXz690AI/A==", + "version": "18.2.25", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.25.tgz", + "integrity": "sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==", "dev": true, "dependencies": { "@types/react": "*" @@ -3582,22 +3576,22 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.5.0.tgz", - "integrity": "sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz", + "integrity": "sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.5.0", - "@typescript-eslint/type-utils": "7.5.0", - "@typescript-eslint/utils": "7.5.0", - "@typescript-eslint/visitor-keys": "7.5.0", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/type-utils": "7.7.0", + "@typescript-eslint/utils": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", "debug": "^4.3.4", "graphemer": "^1.4.0", - "ignore": "^5.2.4", + "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3650,15 +3644,15 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.5.0.tgz", - "integrity": "sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.0.tgz", + "integrity": "sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.5.0", - "@typescript-eslint/types": "7.5.0", - "@typescript-eslint/typescript-estree": "7.5.0", - "@typescript-eslint/visitor-keys": "7.5.0", + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/typescript-estree": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", "debug": "^4.3.4" }, "engines": { @@ -3678,13 +3672,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.5.0.tgz", - "integrity": "sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz", + "integrity": "sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.5.0", - "@typescript-eslint/visitor-keys": "7.5.0" + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3695,15 +3689,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.5.0.tgz", - "integrity": "sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz", + "integrity": "sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.5.0", - "@typescript-eslint/utils": "7.5.0", + "@typescript-eslint/typescript-estree": "7.7.0", + "@typescript-eslint/utils": "7.7.0", "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^1.3.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3722,9 +3716,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.5.0.tgz", - "integrity": "sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.0.tgz", + "integrity": "sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3735,19 +3729,19 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.5.0.tgz", - "integrity": "sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz", + "integrity": "sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.5.0", - "@typescript-eslint/visitor-keys": "7.5.0", + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3796,18 +3790,18 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.5.0.tgz", - "integrity": "sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.0.tgz", + "integrity": "sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.5.0", - "@typescript-eslint/types": "7.5.0", - "@typescript-eslint/typescript-estree": "7.5.0", - "semver": "^7.5.4" + "@types/json-schema": "^7.0.15", + "@types/semver": "^7.5.8", + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/typescript-estree": "7.7.0", + "semver": "^7.6.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3854,13 +3848,13 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.5.0.tgz", - "integrity": "sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz", + "integrity": "sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.5.0", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/types": "7.7.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3896,9 +3890,9 @@ } }, "node_modules/@vitest/coverage-v8": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.4.0.tgz", - "integrity": "sha512-4hDGyH1SvKpgZnIByr9LhGgCEuF9DKM34IBLCC/fVfy24Z3+PZ+Ii9hsVBsHvY1umM1aGPEjceRkzxCfcQ10wg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.5.0.tgz", + "integrity": "sha512-1igVwlcqw1QUMdfcMlzzY4coikSIBN944pkueGi0pawrX5I5Z+9hxdTR+w3Sg6Q3eZhvdMAs8ZaF9JuTG1uYOQ==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.1", @@ -3913,24 +3907,23 @@ "picocolors": "^1.0.0", "std-env": "^3.5.0", "strip-literal": "^2.0.0", - "test-exclude": "^6.0.0", - "v8-to-istanbul": "^9.2.0" + "test-exclude": "^6.0.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "1.4.0" + "vitest": "1.5.0" } }, "node_modules/@vitest/expect": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.4.0.tgz", - "integrity": "sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.0.tgz", + "integrity": "sha512-0pzuCI6KYi2SIC3LQezmxujU9RK/vwC1U9R0rLuGlNGcOuDWxqWKu6nUdFsX9tH1WU0SXtAxToOsEjeUn1s3hA==", "dev": true, "dependencies": { - "@vitest/spy": "1.4.0", - "@vitest/utils": "1.4.0", + "@vitest/spy": "1.5.0", + "@vitest/utils": "1.5.0", "chai": "^4.3.10" }, "funding": { @@ -3938,12 +3931,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.4.0.tgz", - "integrity": "sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.0.tgz", + "integrity": "sha512-7HWwdxXP5yDoe7DTpbif9l6ZmDwCzcSIK38kTSIt6CFEpMjX4EpCgT6wUmS0xTXqMI6E/ONmfgRKmaujpabjZQ==", "dev": true, "dependencies": { - "@vitest/utils": "1.4.0", + "@vitest/utils": "1.5.0", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -3979,9 +3972,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.4.0.tgz", - "integrity": "sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.0.tgz", + "integrity": "sha512-qpv3fSEuNrhAO3FpH6YYRdaECnnRjg9VxbhdtPwPRnzSfHVXnNzzrpX4cJxqiwgRMo7uRMWDFBlsBq4Cr+rO3A==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -4025,9 +4018,9 @@ "dev": true }, "node_modules/@vitest/spy": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.4.0.tgz", - "integrity": "sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.0.tgz", + "integrity": "sha512-vu6vi6ew5N5MMHJjD5PoakMRKYdmIrNJmyfkhRpQt5d9Ewhw9nZ5Aqynbi3N61bvk9UvZ5UysMT6ayIrZ8GA9w==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -4037,9 +4030,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.4.0.tgz", - "integrity": "sha512-mx3Yd1/6e2Vt/PUC98DcqTirtfxUyAZ32uK82r8rZzbtBeBo+nqgnjx/LvqQdWsrvNtm14VmurNgcf4nqY5gJg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.0.tgz", + "integrity": "sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -8455,9 +8448,9 @@ } }, "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -10618,9 +10611,9 @@ } }, "node_modules/typescript": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", - "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -10839,20 +10832,6 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, - "node_modules/v8-to-istanbul": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", - "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, "node_modules/value-or-promise": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.12.tgz", @@ -10863,9 +10842,9 @@ } }, "node_modules/vite": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.7.tgz", - "integrity": "sha512-k14PWOKLI6pMaSzAuGtT+Cf0YmIx12z9YGon39onaJNy8DLBfBJrzg9FQEmkAM5lpHBZs9wksWAsyF/HkpEwJA==", + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz", + "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==", "dev": true, "dependencies": { "esbuild": "^0.20.1", @@ -10918,9 +10897,9 @@ } }, "node_modules/vite-node": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.4.0.tgz", - "integrity": "sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.0.tgz", + "integrity": "sha512-tV8h6gMj6vPzVCa7l+VGq9lwoJjW8Y79vst8QZZGiuRAfijU+EEWuc0kFpmndQrWhMMhet1jdSF+40KSZUqIIw==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -10940,16 +10919,16 @@ } }, "node_modules/vitest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.4.0.tgz", - "integrity": "sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.0.tgz", + "integrity": "sha512-d8UKgR0m2kjdxDWX6911uwxout6GHS0XaGH1cksSIVVG8kRlE7G7aBw7myKQCvDI5dT4j7ZMa+l706BIORMDLw==", "dev": true, "dependencies": { - "@vitest/expect": "1.4.0", - "@vitest/runner": "1.4.0", - "@vitest/snapshot": "1.4.0", - "@vitest/spy": "1.4.0", - "@vitest/utils": "1.4.0", + "@vitest/expect": "1.5.0", + "@vitest/runner": "1.5.0", + "@vitest/snapshot": "1.5.0", + "@vitest/spy": "1.5.0", + "@vitest/utils": "1.5.0", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -10961,9 +10940,9 @@ "std-env": "^3.5.0", "strip-literal": "^2.0.0", "tinybench": "^2.5.1", - "tinypool": "^0.8.2", + "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.4.0", + "vite-node": "1.5.0", "why-is-node-running": "^2.2.2" }, "bin": { @@ -10978,8 +10957,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.4.0", - "@vitest/ui": "1.4.0", + "@vitest/browser": "1.5.0", + "@vitest/ui": "1.5.0", "happy-dom": "*", "jsdom": "*" }, diff --git a/client-next/package.json b/client-next/package.json index e5019ecb088..643acd1c082 100644 --- a/client-next/package.json +++ b/client-next/package.json @@ -33,12 +33,12 @@ "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.4.1", "@testing-library/react": "15.0.2", - "@types/react": "18.2.73", - "@types/react-dom": "18.2.23", - "@typescript-eslint/eslint-plugin": "7.5.0", - "@typescript-eslint/parser": "7.5.0", + "@types/react": "18.2.79", + "@types/react-dom": "18.2.25", + "@typescript-eslint/eslint-plugin": "7.7.0", + "@typescript-eslint/parser": "7.7.0", "@vitejs/plugin-react": "4.2.1", - "@vitest/coverage-v8": "1.4.0", + "@vitest/coverage-v8": "1.5.0", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "2.29.1", @@ -48,8 +48,8 @@ "eslint-plugin-react-refresh": "0.4.6", "jsdom": "24.0.0", "prettier": "3.2.5", - "typescript": "5.4.3", - "vite": "5.2.7", - "vitest": "1.4.0" + "typescript": "5.4.5", + "vite": "5.2.8", + "vitest": "1.5.0" } } From f77cedee401e27d6d770acd7984a39bf9ffc0b8a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 21:19:06 +0000 Subject: [PATCH 087/121] Update slf4j monorepo to v2.0.13 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0dbec37943a..06d33adeecb 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ 5.5.3 1.5.3 9.10.0 - 2.0.12 + 2.0.13 2.0.15 1.26 4.0.5 From 89c20277965c20221c90ba661eff9e2c037433a1 Mon Sep 17 00:00:00 2001 From: OTP Bot Date: Tue, 16 Apr 2024 05:11:56 +0000 Subject: [PATCH 088/121] Upgrade debug client to version 2024/04/2024-04-16T05:11 --- src/client/debug-client-preview/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/debug-client-preview/index.html b/src/client/debug-client-preview/index.html index 317fbed5a11..1b561ffc656 100644 --- a/src/client/debug-client-preview/index.html +++ b/src/client/debug-client-preview/index.html @@ -5,8 +5,8 @@ OTP Debug Client - - + +
From ed40a51ebebe447c1b9f82dc58acad457b0a5754 Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Tue, 16 Apr 2024 09:09:34 +0000 Subject: [PATCH 089/121] Add changelog entry for #5794 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 704ce4787c0..25c8cb80594 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -13,6 +13,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Discourage instead of ban cycling on use_sidepath ways and do the same for walking on foot=use_sidepath [#5790](https://github.com/opentripplanner/OpenTripPlanner/pull/5790) - Prune islands with mode-less stop vertices [#5782](https://github.com/opentripplanner/OpenTripPlanner/pull/5782) - Overwrite default WALK directMode when it is not set in the request, but modes is set [#5779](https://github.com/opentripplanner/OpenTripPlanner/pull/5779) +- Fix trip duplication in Graph Builder DSJ mapping [#5794](https://github.com/opentripplanner/OpenTripPlanner/pull/5794) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.5.0 (2024-03-13) From bad0b729bb6e58b6e2ddb0c1f30715ee3d49f044 Mon Sep 17 00:00:00 2001 From: Henrik Abrahamsson Date: Wed, 17 Apr 2024 11:14:10 +0200 Subject: [PATCH 090/121] Fix DebugUi doc --- docs/Frontends.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Frontends.md b/docs/Frontends.md index e8b299a52ac..e7946102ea1 100644 --- a/docs/Frontends.md +++ b/docs/Frontends.md @@ -32,7 +32,7 @@ While the "classic" (i.e. old) debug frontend is enabled by default as of this w // otp-config.json { "otpFeatures": { - "DebugClient": true, + "DebugUi": true, "SandboxAPIGeocoder": true } } From a1f51daadcbdfca0a5fd654e3888ccc8eb47aa19 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 10 Apr 2024 14:29:38 +0200 Subject: [PATCH 091/121] Add Bikeep parking updater --- docs/sandbox/VehicleParking.md | 8 +- .../bikeep/BikeepUpdaterTest.java | 45 +++ .../ext/vehicleparking/bikeep/bikeep.json | 303 ++++++++++++++++++ .../vehicleparking/bikeep/BikeepUpdater.java | 73 +++++ .../bikeep/BikeepUpdaterParameters.java | 25 ++ .../parkapi/ParkAPIUpdater.java | 8 + .../updaters/VehicleParkingUpdaterConfig.java | 12 + .../VehicleParkingDataSourceFactory.java | 3 + .../VehicleParkingSourceType.java | 1 + 9 files changed, 474 insertions(+), 4 deletions(-) create mode 100644 src/ext-test/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdaterTest.java create mode 100644 src/ext-test/resources/org/opentripplanner/ext/vehicleparking/bikeep/bikeep.json create mode 100644 src/ext/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdater.java create mode 100644 src/ext/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdaterParameters.java diff --git a/docs/sandbox/VehicleParking.md b/docs/sandbox/VehicleParking.md index 2721fff9b0c..d8e05af8d25 100644 --- a/docs/sandbox/VehicleParking.md +++ b/docs/sandbox/VehicleParking.md @@ -61,7 +61,7 @@ This will end up in the API responses as the feed id of of the parking lot. **Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Required` **Path:** /updaters/[2] -**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub` +**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub` | `bikeep` The source of the vehicle updates. @@ -131,7 +131,7 @@ This will end up in the API responses as the feed id of of the parking lot. **Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Required` **Path:** /updaters/[3] -**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub` +**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub` | `bikeep` The source of the vehicle updates. @@ -216,7 +216,7 @@ This will end up in the API responses as the feed id of of the parking lot. **Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Required` **Path:** /updaters/[4] -**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub` +**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub` | `bikeep` The source of the vehicle updates. @@ -281,7 +281,7 @@ This will end up in the API responses as the feed id of of the parking lot. **Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Required` **Path:** /updaters/[5] -**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub` +**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub` | `bikeep` The source of the vehicle updates. diff --git a/src/ext-test/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdaterTest.java b/src/ext-test/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdaterTest.java new file mode 100644 index 00000000000..82099dfbd51 --- /dev/null +++ b/src/ext-test/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdaterTest.java @@ -0,0 +1,45 @@ +package org.opentripplanner.ext.vehicleparking.bikeep; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.time.Duration; +import org.junit.jupiter.api.Test; +import org.opentripplanner.test.support.ResourceLoader; +import org.opentripplanner.updater.spi.HttpHeaders; + +class BikeepUpdaterTest { + + @Test + void parse() { + var uri = ResourceLoader.of(this).uri("bikeep.json"); + var parameters = new BikeepUpdaterParameters( + "bikeep", + uri, + "bikeep", + Duration.ofSeconds(30), + HttpHeaders.empty() + ); + var updater = new BikeepUpdater(parameters); + updater.update(); + var lots = updater.getUpdates(); + + assertEquals(9, lots.size()); + + lots.forEach(l -> assertNotNull(l.getName())); + + var first = lots.getFirst(); + assertEquals("bikeep:224121", first.getId().toString()); + assertEquals("(60.40593, 4.99634)", first.getCoordinate().toString()); + assertEquals("Ågotnes Terminal", first.getName().toString()); + assertEquals(10, first.getAvailability().getBicycleSpaces()); + assertEquals(10, first.getCapacity().getBicycleSpaces()); + + var last = lots.getLast(); + assertEquals("bikeep:224111", last.getId().toString()); + assertEquals("(59.88741, 10.5205)", last.getCoordinate().toString()); + assertEquals("Sandvika Storsenter Nytorget", last.getName().toString()); + assertEquals(13, last.getAvailability().getBicycleSpaces()); + assertEquals(15, last.getCapacity().getBicycleSpaces()); + } +} diff --git a/src/ext-test/resources/org/opentripplanner/ext/vehicleparking/bikeep/bikeep.json b/src/ext-test/resources/org/opentripplanner/ext/vehicleparking/bikeep/bikeep.json new file mode 100644 index 00000000000..6f164077ee1 --- /dev/null +++ b/src/ext-test/resources/org/opentripplanner/ext/vehicleparking/bikeep/bikeep.json @@ -0,0 +1,303 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 4.996344, + 60.405932 + ] + }, + "properties": { + "code": "224121", + "label": "Ågotnes Terminal", + "name": "#224121 Ågotnes Terminal", + "address": "Ågotnes", + "tags": [ + "FREE", + "BIKE", + "PRIVATE", + "BOOKABLE" + ], + "icon": { + "png": "", + "png2x": "", + "svg": "" + }, + "parking": { + "available": 10, + "online": 10, + "total": 10 + }, + "renting": null + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 10.666802, + 59.436443 + ] + }, + "properties": { + "code": "226261", + "label": "Gågata Østre", + "name": "#226261 Gågata Østre", + "address": "Dronningens gate, Moss", + "tags": [ + "FREE", + "PRIVATE", + "BOOKABLE", + "BIKE" + ], + "icon": { + "png": "", + "png2x": "", + "svg": "" + }, + "parking": { + "available": 7, + "online": 10, + "total": 10 + }, + "renting": null + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 10.661444, + 59.435401 + ] + }, + "properties": { + "code": "226259", + "label": "Gågata Vestre", + "name": "#226259 Gågata Vestre", + "address": "Dronningens gate, Moss", + "tags": [ + "BIKE", + "FREE", + "PRIVATE", + "BOOKABLE" + ], + "icon": { + "png": "", + "png2x": "", + "svg": "" + }, + "parking": { + "available": 5, + "online": 5, + "total": 5 + }, + "renting": null + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 10.774958, + 59.946535 + ] + }, + "properties": { + "code": "223443", + "label": "Storo Storsenter", + "name": "#223443 Storo Storsenter", + "address": "Norway", + "tags": [ + "BIKE", + "PRIVATE", + "BOOKABLE", + "FREE" + ], + "icon": { + "png": "https://assets.bikeep.com/locations/icons/bikeep.png", + "png2x": "https://assets.bikeep.com/locations/icons/bikeep@2x.png", + "svg": "" + }, + "parking": { + "available": 17, + "online": 20, + "total": 20 + }, + "renting": null + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 10.501222, + 59.914578 + ] + }, + "properties": { + "code": "224519", + "label": "Kolsås Sykkelhotell", + "name": "#224519 Kolsås Sykkelhotell", + "address": "Norway", + "tags": [ + "PRIVATE", + "FREE", + "BOOKABLE", + "BIKE_HOUSE", + "BIKE" + ], + "icon": { + "png": "https://assets.bikeep.com/locations/icons/bikeep.png", + "png2x": "https://assets.bikeep.com/locations/icons/bikeep@2x.png", + "svg": "" + }, + "parking": { + "available": 13, + "online": 22, + "total": 22 + }, + "renting": null + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 10.663716, + 59.435539 + ] + }, + "properties": { + "code": "226260", + "label": "Gågata Midtre", + "name": "#226260 Gågata Midtre", + "address": "Dronningens gate, Moss", + "tags": [ + "FREE", + "BOOKABLE", + "PRIVATE", + "BIKE" + ], + "icon": { + "png": "", + "png2x": "", + "svg": "" + }, + "parking": { + "available": 5, + "online": 5, + "total": 5 + }, + "renting": null + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 5.320344, + 60.463246 + ] + }, + "properties": { + "code": "226266", + "label": "Åsane Sykkelhus", + "name": "#226266 Åsane Sykkelhus", + "address": "Åsane terminal", + "tags": [ + "BOOKABLE", + "BIKE", + "FREE", + "PRIVATE" + ], + "icon": { + "png": "", + "png2x": "", + "svg": "" + }, + "parking": { + "available": 11, + "online": 12, + "total": 12 + }, + "renting": null + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 10.521137, + 59.889181 + ] + }, + "properties": { + "code": "224112", + "label": "Sandvika Storsenter Kjørbokollen", + "name": "#224112 Sandvika Storsenter Kjørbokollen", + "address": "Brodtkorbsgate 7, Sandvika", + "tags": [ + "PRIVATE", + "FREE", + "BIKE", + "BOOKABLE" + ], + "icon": { + "png": "", + "png2x": "", + "svg": "" + }, + "parking": { + "available": 5, + "online": 5, + "total": 5 + }, + "renting": null + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 10.520496, + 59.887412 + ] + }, + "properties": { + "code": "224111", + "label": "Sandvika Storsenter Nytorget", + "name": "#224111 Sandvika Storsenter Nytorget", + "address": "Sandviksveien 176, Sandvika", + "tags": [ + "BIKE", + "BOOKABLE", + "PRIVATE", + "FREE" + ], + "icon": { + "png": "", + "png2x": "", + "svg": "" + }, + "parking": { + "available": 13, + "online": 15, + "total": 15 + }, + "renting": null + } + } + ] +} \ No newline at end of file diff --git a/src/ext/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdater.java b/src/ext/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdater.java new file mode 100644 index 00000000000..43ed99453b2 --- /dev/null +++ b/src/ext/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdater.java @@ -0,0 +1,73 @@ +package org.opentripplanner.ext.vehicleparking.bikeep; + +import com.fasterxml.jackson.databind.JsonNode; +import org.opentripplanner.framework.geometry.WgsCoordinate; +import org.opentripplanner.framework.i18n.NonLocalizedString; +import org.opentripplanner.framework.tostring.ToStringBuilder; +import org.opentripplanner.routing.vehicle_parking.VehicleParking; +import org.opentripplanner.routing.vehicle_parking.VehicleParkingSpaces; +import org.opentripplanner.routing.vehicle_parking.VehicleParkingState; +import org.opentripplanner.transit.model.framework.FeedScopedId; +import org.opentripplanner.updater.spi.GenericJsonDataSource; + +/** + * Vehicle parking updater for Bikeep's API. + */ +public class BikeepUpdater extends GenericJsonDataSource { + + private static final String JSON_PARSE_PATH = "features"; + private final BikeepUpdaterParameters params; + + public BikeepUpdater(BikeepUpdaterParameters parameters) { + super(parameters.url().toString(), JSON_PARSE_PATH, parameters.httpHeaders()); + this.params = parameters; + } + + @Override + protected VehicleParking parseElement(JsonNode jsonNode) { + var coords = jsonNode.path("geometry").path("coordinates"); + var coordinate = new WgsCoordinate(coords.get(1).asDouble(), coords.get(0).asDouble()); + + var props = jsonNode.path("properties"); + var vehicleParkId = new FeedScopedId(params.feedId(), props.path("code").asText()); + var name = new NonLocalizedString(props.path("label").asText()); + var parking = props.path("parking"); + + var availability = VehicleParkingSpaces + .builder() + .bicycleSpaces(parking.get("available").asInt()) + .build(); + var capacity = VehicleParkingSpaces + .builder() + .bicycleSpaces(parking.get("total").asInt()) + .build(); + + VehicleParking.VehicleParkingEntranceCreator entrance = builder -> + builder + .entranceId(new FeedScopedId(params.feedId(), vehicleParkId.getId() + "/entrance")) + .coordinate(coordinate) + .walkAccessible(true) + .carAccessible(true); + + return VehicleParking + .builder() + .id(vehicleParkId) + .name(name) + .state(VehicleParkingState.OPERATIONAL) + .coordinate(coordinate) + .bicyclePlaces(true) + .availability(availability) + .capacity(capacity) + .entrance(entrance) + .build(); + } + + @Override + public String toString() { + return ToStringBuilder + .of(this.getClass()) + .addStr("feedId", this.params.feedId()) + .addStr("url", this.params.url().toString()) + .toString(); + } +} diff --git a/src/ext/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdaterParameters.java b/src/ext/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdaterParameters.java new file mode 100644 index 00000000000..be937ecdd5e --- /dev/null +++ b/src/ext/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdaterParameters.java @@ -0,0 +1,25 @@ +package org.opentripplanner.ext.vehicleparking.bikeep; + +import java.net.URI; +import java.time.Duration; +import org.opentripplanner.updater.spi.HttpHeaders; +import org.opentripplanner.updater.vehicle_parking.VehicleParkingSourceType; +import org.opentripplanner.updater.vehicle_parking.VehicleParkingUpdaterParameters; + +/** + * Class that extends {@link VehicleParkingUpdaterParameters} with parameters required by {@link + * BikeepUpdater}. + */ +public record BikeepUpdaterParameters( + String configRef, + URI url, + String feedId, + Duration frequency, + HttpHeaders httpHeaders +) + implements VehicleParkingUpdaterParameters { + @Override + public VehicleParkingSourceType sourceType() { + return VehicleParkingSourceType.BIKEEP; + } +} diff --git a/src/ext/java/org/opentripplanner/ext/vehicleparking/parkapi/ParkAPIUpdater.java b/src/ext/java/org/opentripplanner/ext/vehicleparking/parkapi/ParkAPIUpdater.java index fd9389f8ee3..c6f775e588f 100644 --- a/src/ext/java/org/opentripplanner/ext/vehicleparking/parkapi/ParkAPIUpdater.java +++ b/src/ext/java/org/opentripplanner/ext/vehicleparking/parkapi/ParkAPIUpdater.java @@ -12,6 +12,7 @@ import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.framework.i18n.TranslatedString; +import org.opentripplanner.framework.tostring.ToStringBuilder; import org.opentripplanner.model.calendar.openinghours.OHCalendar; import org.opentripplanner.model.calendar.openinghours.OpeningHoursCalendarService; import org.opentripplanner.openstreetmap.OSMOpeningHoursParser; @@ -36,6 +37,7 @@ abstract class ParkAPIUpdater extends GenericJsonDataSource { private final Collection staticTags; private final OSMOpeningHoursParser osmOpeningHoursParser; + private final String url; public ParkAPIUpdater( ParkAPIUpdaterParameters parameters, @@ -46,6 +48,7 @@ public ParkAPIUpdater( this.staticTags = parameters.tags(); this.osmOpeningHoursParser = new OSMOpeningHoursParser(openingHoursCalendarService, parameters.timeZone()); + this.url = parameters.url(); } @Override @@ -196,4 +199,9 @@ private List parseTags(JsonNode node, String... tagNames) { } return tagList; } + + @Override + public String toString() { + return ToStringBuilder.of(getClass()).addStr("feedId", feedId).addObj("url", url).toString(); + } } diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/VehicleParkingUpdaterConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/VehicleParkingUpdaterConfig.java index f0306941547..d04e1900795 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/VehicleParkingUpdaterConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/VehicleParkingUpdaterConfig.java @@ -8,6 +8,7 @@ import java.time.ZoneId; import java.util.ArrayList; import java.util.Set; +import org.opentripplanner.ext.vehicleparking.bikeep.BikeepUpdaterParameters; import org.opentripplanner.ext.vehicleparking.bikely.BikelyUpdaterParameters; import org.opentripplanner.ext.vehicleparking.hslpark.HslParkUpdaterParameters; import org.opentripplanner.ext.vehicleparking.noi.NoiUpdaterParameters; @@ -88,6 +89,17 @@ public static VehicleParkingUpdaterParameters create(String updaterRef, NodeAdap .asDuration(Duration.ofMinutes(1)), HttpHeadersConfig.headers(c, V2_6) ); + case BIKEEP -> new BikeepUpdaterParameters( + updaterRef, + c.of("url").since(V2_6).summary("URL of the locations endpoint.").asUri(), + feedId, + c + .of("frequency") + .since(V2_6) + .summary("How often to update the source.") + .asDuration(Duration.ofMinutes(1)), + HttpHeadersConfig.headers(c, V2_6) + ); }; } diff --git a/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingDataSourceFactory.java b/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingDataSourceFactory.java index 3fe465a8cd5..a956fda0d87 100644 --- a/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingDataSourceFactory.java +++ b/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingDataSourceFactory.java @@ -1,5 +1,7 @@ package org.opentripplanner.updater.vehicle_parking; +import org.opentripplanner.ext.vehicleparking.bikeep.BikeepUpdater; +import org.opentripplanner.ext.vehicleparking.bikeep.BikeepUpdaterParameters; import org.opentripplanner.ext.vehicleparking.bikely.BikelyUpdater; import org.opentripplanner.ext.vehicleparking.bikely.BikelyUpdaterParameters; import org.opentripplanner.ext.vehicleparking.hslpark.HslParkUpdater; @@ -39,6 +41,7 @@ public static DataSource create( ); case BIKELY -> new BikelyUpdater((BikelyUpdaterParameters) parameters); case NOI_OPEN_DATA_HUB -> new NoiUpdater((NoiUpdaterParameters) parameters); + case BIKEEP -> new BikeepUpdater((BikeepUpdaterParameters) parameters); }; } } diff --git a/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingSourceType.java b/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingSourceType.java index 3a0cb7d31b3..f6a28177d8e 100644 --- a/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingSourceType.java +++ b/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingSourceType.java @@ -6,4 +6,5 @@ public enum VehicleParkingSourceType { HSL_PARK, BIKELY, NOI_OPEN_DATA_HUB, + BIKEEP, } From f2a76c27a070ddf3adb2e1c110ea7e095b922b09 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 10 Apr 2024 14:43:34 +0200 Subject: [PATCH 092/121] Add tag handling --- doc-templates/VehicleParking.md | 5 +- docs/RouterConfiguration.md | 6 ++ docs/sandbox/VehicleParking.md | 62 ++++++++++++++- .../bikeep/BikeepUpdaterTest.java | 2 + .../vehicleparking/bikeep/BikeepUpdater.java | 76 +++++++++++-------- .../standalone/config/router-config.json | 6 ++ 6 files changed, 124 insertions(+), 33 deletions(-) diff --git a/doc-templates/VehicleParking.md b/doc-templates/VehicleParking.md index 50bd8806267..5d149e40f9a 100644 --- a/doc-templates/VehicleParking.md +++ b/doc-templates/VehicleParking.md @@ -3,7 +3,7 @@ ## Contact Info - For HSL Park and Ride updater: Digitransit team, HSL, Helsinki, Finland -- For Bikely and NOI updater: Leonard Ehrenfried, [mail@leonard.io](mailto:mail@leonard.io) +- For Bikely, NOI and Bikeep updater: Leonard Ehrenfried, [mail@leonard.io](mailto:mail@leonard.io) ## Documentation @@ -44,6 +44,9 @@ All updaters have the following parameters in common: +## Bikeep + + ## Changelog diff --git a/docs/RouterConfiguration.md b/docs/RouterConfiguration.md index e0f1d81b590..918717d439f 100644 --- a/docs/RouterConfiguration.md +++ b/docs/RouterConfiguration.md @@ -844,6 +844,12 @@ Used to group requests when monitoring OTP. "fromDateTime" : "-P1D", "timeout" : 300000 } + }, + { + "type" : "vehicle-parking", + "feedId" : "bikeep", + "sourceType" : "bikeep", + "url" : "https://services.bikeep.com/location/v1/public-areas/no-baia-mobility/locations" } ], "rideHailingServices" : [ diff --git a/docs/sandbox/VehicleParking.md b/docs/sandbox/VehicleParking.md index d8e05af8d25..7599a762602 100644 --- a/docs/sandbox/VehicleParking.md +++ b/docs/sandbox/VehicleParking.md @@ -3,7 +3,7 @@ ## Contact Info - For HSL Park and Ride updater: Digitransit team, HSL, Helsinki, Finland -- For Bikely and NOI updater: Leonard Ehrenfried, [mail@leonard.io](mailto:mail@leonard.io) +- For Bikely, NOI and Bikeep updater: Leonard Ehrenfried, [mail@leonard.io](mailto:mail@leonard.io) ## Documentation @@ -312,6 +312,66 @@ HTTP headers to add to the request. Any header key, value can be inserted. +## Bikeep + + + + +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|----------------------------------|:---------------:|----------------------------------------------------------------------------|:----------:|---------------|:-----:| +| type = "vehicle-parking" | `enum` | The type of the updater. | *Required* | | 1.5 | +| [feedId](#u__13__feedId) | `string` | The name of the data source. | *Required* | | 2.2 | +| frequency | `duration` | How often to update the source. | *Optional* | `"PT1M"` | 2.6 | +| [sourceType](#u__13__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 | +| url | `uri` | URL of the locations endpoint. | *Required* | | 2.6 | +| [headers](#u__13__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.6 | + + +#### Details + +

feedId

+ +**Since version:** `2.2` ∙ **Type:** `string` ∙ **Cardinality:** `Required` +**Path:** /updaters/[13] + +The name of the data source. + +This will end up in the API responses as the feed id of of the parking lot. + +

sourceType

+ +**Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Required` +**Path:** /updaters/[13] +**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub` | `bikeep` + +The source of the vehicle updates. + +

headers

+ +**Since version:** `2.6` ∙ **Type:** `map of string` ∙ **Cardinality:** `Optional` +**Path:** /updaters/[13] + +HTTP headers to add to the request. Any header key, value can be inserted. + + + +##### Example configuration + +```JSON +// router-config.json +{ + "updaters" : [ + { + "type" : "vehicle-parking", + "feedId" : "bikeep", + "sourceType" : "bikeep", + "url" : "https://services.bikeep.com/location/v1/public-areas/no-baia-mobility/locations" + } + ] +} +``` + + ## Changelog diff --git a/src/ext-test/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdaterTest.java b/src/ext-test/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdaterTest.java index 82099dfbd51..679339f359b 100644 --- a/src/ext-test/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdaterTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdaterTest.java @@ -4,6 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import java.time.Duration; +import java.util.Set; import org.junit.jupiter.api.Test; import org.opentripplanner.test.support.ResourceLoader; import org.opentripplanner.updater.spi.HttpHeaders; @@ -34,6 +35,7 @@ void parse() { assertEquals("Ågotnes Terminal", first.getName().toString()); assertEquals(10, first.getAvailability().getBicycleSpaces()); assertEquals(10, first.getCapacity().getBicycleSpaces()); + assertEquals(Set.of("FREE", "PRIVATE", "BIKE", "BOOKABLE"), first.getTags()); var last = lots.getLast(); assertEquals("bikeep:224111", last.getId().toString()); diff --git a/src/ext/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdater.java b/src/ext/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdater.java index 43ed99453b2..9216eb79995 100644 --- a/src/ext/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdater.java +++ b/src/ext/java/org/opentripplanner/ext/vehicleparking/bikeep/BikeepUpdater.java @@ -1,8 +1,12 @@ package org.opentripplanner.ext.vehicleparking.bikeep; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectReader; +import java.io.IOException; +import java.util.List; import org.opentripplanner.framework.geometry.WgsCoordinate; import org.opentripplanner.framework.i18n.NonLocalizedString; +import org.opentripplanner.framework.json.ObjectMappers; import org.opentripplanner.framework.tostring.ToStringBuilder; import org.opentripplanner.routing.vehicle_parking.VehicleParking; import org.opentripplanner.routing.vehicle_parking.VehicleParkingSpaces; @@ -16,6 +20,9 @@ public class BikeepUpdater extends GenericJsonDataSource { private static final String JSON_PARSE_PATH = "features"; + private static final ObjectReader STRING_LIST_READER = ObjectMappers + .ignoringExtraFields() + .readerForListOf(String.class); private final BikeepUpdaterParameters params; public BikeepUpdater(BikeepUpdaterParameters parameters) { @@ -25,41 +32,48 @@ public BikeepUpdater(BikeepUpdaterParameters parameters) { @Override protected VehicleParking parseElement(JsonNode jsonNode) { - var coords = jsonNode.path("geometry").path("coordinates"); - var coordinate = new WgsCoordinate(coords.get(1).asDouble(), coords.get(0).asDouble()); + try { + var coords = jsonNode.path("geometry").path("coordinates"); + var coordinate = new WgsCoordinate(coords.get(1).asDouble(), coords.get(0).asDouble()); - var props = jsonNode.path("properties"); - var vehicleParkId = new FeedScopedId(params.feedId(), props.path("code").asText()); - var name = new NonLocalizedString(props.path("label").asText()); - var parking = props.path("parking"); + var props = jsonNode.path("properties"); + var vehicleParkId = new FeedScopedId(params.feedId(), props.path("code").asText()); + var name = new NonLocalizedString(props.path("label").asText()); + var parking = props.path("parking"); - var availability = VehicleParkingSpaces - .builder() - .bicycleSpaces(parking.get("available").asInt()) - .build(); - var capacity = VehicleParkingSpaces - .builder() - .bicycleSpaces(parking.get("total").asInt()) - .build(); + List tags = STRING_LIST_READER.readValue(props.path("tags")); - VehicleParking.VehicleParkingEntranceCreator entrance = builder -> - builder - .entranceId(new FeedScopedId(params.feedId(), vehicleParkId.getId() + "/entrance")) - .coordinate(coordinate) - .walkAccessible(true) - .carAccessible(true); + var availability = VehicleParkingSpaces + .builder() + .bicycleSpaces(parking.get("available").asInt()) + .build(); + var capacity = VehicleParkingSpaces + .builder() + .bicycleSpaces(parking.get("total").asInt()) + .build(); + + VehicleParking.VehicleParkingEntranceCreator entrance = builder -> + builder + .entranceId(new FeedScopedId(params.feedId(), vehicleParkId.getId() + "/entrance")) + .coordinate(coordinate) + .walkAccessible(true) + .carAccessible(true); - return VehicleParking - .builder() - .id(vehicleParkId) - .name(name) - .state(VehicleParkingState.OPERATIONAL) - .coordinate(coordinate) - .bicyclePlaces(true) - .availability(availability) - .capacity(capacity) - .entrance(entrance) - .build(); + return VehicleParking + .builder() + .id(vehicleParkId) + .name(name) + .state(VehicleParkingState.OPERATIONAL) + .coordinate(coordinate) + .bicyclePlaces(true) + .availability(availability) + .tags(tags) + .capacity(capacity) + .entrance(entrance) + .build(); + } catch (IOException e) { + throw new RuntimeException(e); + } } @Override diff --git a/src/test/resources/standalone/config/router-config.json b/src/test/resources/standalone/config/router-config.json index f5eaa1f942b..3b43ef1c5d2 100644 --- a/src/test/resources/standalone/config/router-config.json +++ b/src/test/resources/standalone/config/router-config.json @@ -420,6 +420,12 @@ "fromDateTime": "-P1D", "timeout": 300000 } + }, + { + "type": "vehicle-parking", + "feedId": "bikeep", + "sourceType": "bikeep", + "url": "https://services.bikeep.com/location/v1/public-areas/no-baia-mobility/locations" } ], "rideHailingServices": [ From 68f667e0403a85e940d0de8eb99cf3f6eddb097a Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 18 Apr 2024 14:58:54 +0200 Subject: [PATCH 093/121] Apply suggestions from code review Co-authored-by: Thomas Gran --- .../standalone/config/framework/json/NodeAdapterTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java b/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java index 8128a48a678..9d3719c2285 100644 --- a/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java +++ b/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java @@ -560,7 +560,7 @@ void unusedParams() { @Test void unknownParameters() { // Given: two parameters a and b - NodeAdapter subject = newNodeAdapterForTest("{ foo : { a: true, b: false } }"); + var subject = newNodeAdapterForTest("{ foo : { a: true, b: false } }"); // When: Access ONLY parameter 'a', but not 'b' subject.of("foo").asObject().of("a").asBoolean(); @@ -571,7 +571,7 @@ void unknownParameters() { @Test void allParametersAreKnown() { // Given: two parameters a and b - NodeAdapter subject = newNodeAdapterForTest("{ foo : { a: true, b: false } }"); + var subject = newNodeAdapterForTest("{ foo : { a: true, b: false } }"); var object = subject.of("foo").asObject(); object.of("a").asBoolean(); From 4b5b7d6bf59e51aed4f8fd7294486e9dbfb5e273 Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Thu, 18 Apr 2024 13:24:13 +0000 Subject: [PATCH 094/121] Add changelog entry for #5676 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 25c8cb80594..d12e9a100f0 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -14,6 +14,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Prune islands with mode-less stop vertices [#5782](https://github.com/opentripplanner/OpenTripPlanner/pull/5782) - Overwrite default WALK directMode when it is not set in the request, but modes is set [#5779](https://github.com/opentripplanner/OpenTripPlanner/pull/5779) - Fix trip duplication in Graph Builder DSJ mapping [#5794](https://github.com/opentripplanner/OpenTripPlanner/pull/5794) +- Optionally abort startup when unknown configuration parameters were detected [#5676](https://github.com/opentripplanner/OpenTripPlanner/pull/5676) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.5.0 (2024-03-13) From 6c7d95383a2fe297c4a2ca690dcc65b971b68a37 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 18 Apr 2024 16:32:04 +0200 Subject: [PATCH 095/121] Replace DurationModifier with TimePenalty --- .../DurationModifierCalculatorTest.java | 6 +-- .../flex/flexpathcalculator/FlexPathTest.java | 12 ++--- .../ext/flex/trip/DurationModifierTest.java | 20 ------- .../trip/UnscheduledDrivingDurationTest.java | 3 +- .../ext/flex/FlexTripsMapper.java | 4 +- .../DurationModifierCalculator.java | 8 +-- .../ext/flex/flexpathcalculator/FlexPath.java | 16 ++++-- .../ext/flex/trip/DurationModifier.java | 53 ------------------- .../ext/flex/trip/UnscheduledTrip.java | 5 +- .../ext/flex/trip/UnscheduledTripBuilder.java | 7 +-- .../gtfs/mapping/TripMapper.java | 10 ++-- .../model/impl/OtpTransitServiceBuilder.java | 6 +-- .../gtfs/mapping/TripMapperTest.java | 4 +- 13 files changed, 45 insertions(+), 109 deletions(-) delete mode 100644 src/ext-test/java/org/opentripplanner/ext/flex/trip/DurationModifierTest.java delete mode 100644 src/ext/java/org/opentripplanner/ext/flex/trip/DurationModifier.java diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculatorTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculatorTest.java index f610cbe09c4..a97460dda75 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculatorTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculatorTest.java @@ -6,7 +6,7 @@ import java.time.Duration; import org.junit.jupiter.api.Test; import org.opentripplanner._support.geometry.LineStrings; -import org.opentripplanner.ext.flex.trip.DurationModifier; +import org.opentripplanner.routing.api.request.framework.TimePenalty; import org.opentripplanner.street.model._data.StreetModelForTest; class DurationModifierCalculatorTest { @@ -18,7 +18,7 @@ void calculate() { FlexPathCalculator delegate = (fromv, tov, fromStopIndex, toStopIndex) -> new FlexPath(10_000, THIRTY_MINS_IN_SECONDS, () -> LineStrings.SIMPLE); - var mod = new DurationModifier(Duration.ofMinutes(10), 1.5f); + var mod = TimePenalty.of(Duration.ofMinutes(10), 1.5f); var calc = new DurationModifierCalculator(delegate, mod); var path = calc.calculateFlexPath(StreetModelForTest.V1, StreetModelForTest.V2, 0, 5); assertEquals(3300, path.durationSeconds); @@ -27,7 +27,7 @@ void calculate() { @Test void nullValue() { FlexPathCalculator delegate = (fromv, tov, fromStopIndex, toStopIndex) -> null; - var mod = new DurationModifier(Duration.ofMinutes(10), 1.5f); + var mod = TimePenalty.of(Duration.ofMinutes(10), 1.5f); var calc = new DurationModifierCalculator(delegate, mod); var path = calc.calculateFlexPath(StreetModelForTest.V1, StreetModelForTest.V2, 0, 5); assertNull(path); diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathTest.java index b79093e26c5..8bd3abee785 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathTest.java @@ -8,7 +8,7 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner._support.geometry.LineStrings; -import org.opentripplanner.ext.flex.trip.DurationModifier; +import org.opentripplanner.routing.api.request.framework.TimePenalty; class FlexPathTest { @@ -21,16 +21,16 @@ class FlexPathTest { static List cases() { return List.of( - Arguments.of(DurationModifier.NONE, THIRTY_MINS_IN_SECONDS), - Arguments.of(new DurationModifier(Duration.ofMinutes(10), 1), 2400), - Arguments.of(new DurationModifier(Duration.ofMinutes(10), 1.5f), 3300), - Arguments.of(new DurationModifier(Duration.ZERO, 3), 5400) + Arguments.of(TimePenalty.ZERO, THIRTY_MINS_IN_SECONDS), + Arguments.of(TimePenalty.of(Duration.ofMinutes(10), 1), 2400), + Arguments.of(TimePenalty.of(Duration.ofMinutes(10), 1.5f), 3300), + Arguments.of(TimePenalty.of(Duration.ZERO, 3), 5400) ); } @ParameterizedTest @MethodSource("cases") - void calculate(DurationModifier mod, int expectedSeconds) { + void calculate(TimePenalty mod, int expectedSeconds) { var modified = PATH.withDurationModifier(mod); assertEquals(expectedSeconds, modified.durationSeconds); assertEquals(LineStrings.SIMPLE, modified.getGeometry()); diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/trip/DurationModifierTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/trip/DurationModifierTest.java deleted file mode 100644 index 05fb9965935..00000000000 --- a/src/ext-test/java/org/opentripplanner/ext/flex/trip/DurationModifierTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.opentripplanner.ext.flex.trip; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.time.Duration; -import org.junit.jupiter.api.Test; - -class DurationModifierTest { - - @Test - void doesNotModify() { - assertFalse(DurationModifier.NONE.modifies()); - } - - @Test - void modifies() { - assertTrue(new DurationModifier(Duration.ofMinutes(1), 1.5f).modifies()); - } -} diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledDrivingDurationTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledDrivingDurationTest.java index 45d8c5be624..bd06a51960b 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledDrivingDurationTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledDrivingDurationTest.java @@ -13,6 +13,7 @@ import org.opentripplanner.ext.flex.flexpathcalculator.FlexPath; import org.opentripplanner.ext.flex.flexpathcalculator.FlexPathCalculator; import org.opentripplanner.model.StopTime; +import org.opentripplanner.routing.api.request.framework.TimePenalty; class UnscheduledDrivingDurationTest { @@ -34,7 +35,7 @@ void withModifier() { var trip = UnscheduledTrip .of(id("1")) .withStopTimes(List.of(STOP_TIME)) - .withDurationModifier(new DurationModifier(Duration.ofMinutes(2), 1.5f)) + .withDurationModifier(TimePenalty.of(Duration.ofMinutes(2), 1.5f)) .build(); var calculator = trip.flexPathCalculator(STATIC_CALCULATOR); diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java index bb2ed2764f6..76a13255b67 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.List; -import org.opentripplanner.ext.flex.trip.DurationModifier; import org.opentripplanner.ext.flex.trip.FlexTrip; import org.opentripplanner.ext.flex.trip.ScheduledDeviatedTrip; import org.opentripplanner.ext.flex.trip.UnscheduledTrip; @@ -13,6 +12,7 @@ import org.opentripplanner.model.StopTime; import org.opentripplanner.model.TripStopTimes; import org.opentripplanner.model.impl.OtpTransitServiceBuilder; +import org.opentripplanner.routing.api.request.framework.TimePenalty; import org.opentripplanner.transit.model.timetable.Trip; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,7 +36,7 @@ public class FlexTripsMapper { /* Fetch the stop times for this trip. Copy the list since it's immutable. */ List stopTimes = new ArrayList<>(stopTimesByTrip.get(trip)); if (UnscheduledTrip.isUnscheduledTrip(stopTimes)) { - var modifier = builder.getFlexDurationFactors().getOrDefault(trip, DurationModifier.NONE); + var modifier = builder.getFlexDurationFactors().getOrDefault(trip, TimePenalty.ZERO); result.add( UnscheduledTrip .of(trip.getId()) diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculator.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculator.java index 158e6a933c7..0f521b55b1f 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculator.java +++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculator.java @@ -1,7 +1,7 @@ package org.opentripplanner.ext.flex.flexpathcalculator; import javax.annotation.Nullable; -import org.opentripplanner.ext.flex.trip.DurationModifier; +import org.opentripplanner.routing.api.request.framework.TimePenalty; import org.opentripplanner.street.model.vertex.Vertex; /** @@ -11,11 +11,11 @@ public class DurationModifierCalculator implements FlexPathCalculator { private final FlexPathCalculator delegate; - private final DurationModifier factors; + private final TimePenalty factors; - public DurationModifierCalculator(FlexPathCalculator delegate, DurationModifier factors) { + public DurationModifierCalculator(FlexPathCalculator delegate, TimePenalty penalty) { this.delegate = delegate; - this.factors = factors; + this.factors = penalty; } @Nullable diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java index 54c11198b19..3a692dff40b 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java +++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPath.java @@ -1,9 +1,11 @@ package org.opentripplanner.ext.flex.flexpathcalculator; +import java.time.Duration; import java.util.function.Supplier; import javax.annotation.concurrent.Immutable; import org.locationtech.jts.geom.LineString; -import org.opentripplanner.ext.flex.trip.DurationModifier; +import org.opentripplanner.framework.lang.IntUtils; +import org.opentripplanner.routing.api.request.framework.TimePenalty; /** * This class contains the results from a FlexPathCalculator. @@ -25,7 +27,7 @@ public class FlexPath { */ public FlexPath(int distanceMeters, int durationSeconds, Supplier geometrySupplier) { this.distanceMeters = distanceMeters; - this.durationSeconds = durationSeconds; + this.durationSeconds = IntUtils.requireNotNegative(durationSeconds); this.geometrySupplier = geometrySupplier; } @@ -39,8 +41,12 @@ public LineString getGeometry() { /** * Returns an (immutable) copy of this path with the duration modified. */ - public FlexPath withDurationModifier(DurationModifier mod) { - int updatedDuration = (int) ((durationSeconds * mod.factor()) + mod.offsetInSeconds()); - return new FlexPath(distanceMeters, updatedDuration, geometrySupplier); + public FlexPath withDurationModifier(TimePenalty mod) { + if (mod.isZero()) { + return this; + } else { + int updatedDuration = (int) mod.calculate(Duration.ofSeconds(durationSeconds)).toSeconds(); + return new FlexPath(distanceMeters, updatedDuration, geometrySupplier); + } } } diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/DurationModifier.java b/src/ext/java/org/opentripplanner/ext/flex/trip/DurationModifier.java deleted file mode 100644 index 4832a7cc9bc..00000000000 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/DurationModifier.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.opentripplanner.ext.flex.trip; - -import java.io.Serializable; -import java.time.Duration; -import org.opentripplanner.framework.time.DurationUtils; -import org.opentripplanner.framework.tostring.ToStringBuilder; - -/** - * A modifier to influence the A*-calculated driving time of flex trips. - */ -public class DurationModifier implements Serializable { - - public static DurationModifier NONE = new DurationModifier(Duration.ZERO, 1); - private final int offset; - private final float factor; - - /** - * @param offset A fixed offset to add to the driving time. - * @param factor A factor to multiply the driving time with. - */ - public DurationModifier(Duration offset, float factor) { - if (factor < 0.1) { - throw new IllegalArgumentException("Flex duration factor must not be less than 0.1"); - } - this.offset = (int) DurationUtils.requireNonNegative(offset).toSeconds(); - this.factor = factor; - } - - public float factor() { - return factor; - } - - public int offsetInSeconds() { - return offset; - } - - /** - * Check if this instance actually modifies the duration or simply passes it back without - * change. - */ - boolean modifies() { - return offset != 0 && factor != 1.0; - } - - @Override - public String toString() { - return ToStringBuilder - .of(DurationModifier.class) - .addNum("factor", factor) - .addDurationSec("offset", offset) - .toString(); - } -} diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java index bc3bd52cc4c..db662a5fd45 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java @@ -23,6 +23,7 @@ import org.opentripplanner.model.BookingInfo; import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.StopTime; +import org.opentripplanner.routing.api.request.framework.TimePenalty; import org.opentripplanner.routing.graphfinder.NearbyStop; import org.opentripplanner.standalone.config.sandbox.FlexConfig; import org.opentripplanner.transit.model.framework.FeedScopedId; @@ -52,7 +53,7 @@ public class UnscheduledTrip extends FlexTrip getFlexAccessTemplates( * If the modifier doesn't actually modify, we don't */ protected FlexPathCalculator flexPathCalculator(FlexPathCalculator calculator) { - if (durationModifier.modifies()) { + if (!durationModifier.isZero()) { return new DurationModifierCalculator(calculator, durationModifier); } else { return calculator; diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java index 7b4617048a6..cfffebe4fa7 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java @@ -2,13 +2,14 @@ import java.util.List; import org.opentripplanner.model.StopTime; +import org.opentripplanner.routing.api.request.framework.TimePenalty; import org.opentripplanner.transit.model.framework.FeedScopedId; public class UnscheduledTripBuilder extends FlexTripBuilder { private List stopTimes; - private DurationModifier durationModifier = DurationModifier.NONE; + private TimePenalty durationModifier = TimePenalty.ZERO; UnscheduledTripBuilder(FeedScopedId id) { super(id); @@ -30,12 +31,12 @@ public List stopTimes() { return stopTimes; } - public UnscheduledTripBuilder withDurationModifier(DurationModifier factors) { + public UnscheduledTripBuilder withDurationModifier(TimePenalty factors) { this.durationModifier = factors; return this; } - public DurationModifier durationModifier() { + public TimePenalty durationModifier() { return durationModifier; } diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java index ec7d1379ca0..46160fa5daa 100644 --- a/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java +++ b/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java @@ -5,9 +5,9 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; -import org.opentripplanner.ext.flex.trip.DurationModifier; import org.opentripplanner.framework.collection.MapUtils; import org.opentripplanner.framework.i18n.I18NString; +import org.opentripplanner.routing.api.request.framework.TimePenalty; import org.opentripplanner.transit.model.timetable.Trip; /** Responsible for mapping GTFS TripMapper into the OTP model. */ @@ -18,7 +18,7 @@ class TripMapper { private final TranslationHelper translationHelper; private final Map mappedTrips = new HashMap<>(); - private final Map flexSafeDurationModifiers = new HashMap<>(); + private final Map flexSafeDurationModifiers = new HashMap<>(); TripMapper( RouteMapper routeMapper, @@ -45,7 +45,7 @@ Collection getMappedTrips() { /** * The map of flex duration factors per flex trip. */ - Map flexSafeDurationModifiers() { + Map flexSafeDurationModifiers() { return flexSafeDurationModifiers; } @@ -78,12 +78,12 @@ private Trip doMap(org.onebusaway.gtfs.model.Trip rhs) { return trip; } - private Optional mapSafeDurationModifier(org.onebusaway.gtfs.model.Trip rhs) { + private Optional mapSafeDurationModifier(org.onebusaway.gtfs.model.Trip rhs) { if (rhs.getSafeDurationFactor() == null && rhs.getSafeDurationOffset() == null) { return Optional.empty(); } else { var offset = Duration.ofSeconds(rhs.getSafeDurationOffset().longValue()); - return Optional.of(new DurationModifier(offset, rhs.getSafeDurationFactor().floatValue())); + return Optional.of(TimePenalty.of(offset, rhs.getSafeDurationFactor().doubleValue())); } } } diff --git a/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java b/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java index 16b7bf22388..756a1ccf2a8 100644 --- a/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java +++ b/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java @@ -8,7 +8,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.opentripplanner.ext.flex.trip.DurationModifier; import org.opentripplanner.ext.flex.trip.FlexTrip; import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.gtfs.mapping.StaySeatedNotAllowed; @@ -24,6 +23,7 @@ import org.opentripplanner.model.calendar.impl.CalendarServiceDataFactoryImpl; import org.opentripplanner.model.transfer.ConstrainedTransfer; import org.opentripplanner.model.transfer.TransferPoint; +import org.opentripplanner.routing.api.request.framework.TimePenalty; import org.opentripplanner.transit.model.basic.Notice; import org.opentripplanner.transit.model.framework.AbstractTransitEntity; import org.opentripplanner.transit.model.framework.DefaultEntityById; @@ -94,7 +94,7 @@ public class OtpTransitServiceBuilder { private final TripStopTimes stopTimesByTrip = new TripStopTimes(); - private final Map flexDurationFactors = new HashMap<>(); + private final Map flexDurationFactors = new HashMap<>(); private final EntityById fareZonesById = new DefaultEntityById<>(); @@ -213,7 +213,7 @@ public TripStopTimes getStopTimesSortedByTrip() { return stopTimesByTrip; } - public Map getFlexDurationFactors() { + public Map getFlexDurationFactors() { return flexDurationFactors; } diff --git a/src/test/java/org/opentripplanner/gtfs/mapping/TripMapperTest.java b/src/test/java/org/opentripplanner/gtfs/mapping/TripMapperTest.java index 141c1d5bf6b..9424e44364b 100644 --- a/src/test/java/org/opentripplanner/gtfs/mapping/TripMapperTest.java +++ b/src/test/java/org/opentripplanner/gtfs/mapping/TripMapperTest.java @@ -131,7 +131,7 @@ void flexDurationModifier() { var mapper = defaultTripMapper(); var mapped = mapper.map(flexTrip); var mod = mapper.flexSafeDurationModifiers().get(mapped); - assertEquals(1.5f, mod.factor()); - assertEquals(600, mod.offsetInSeconds()); + assertEquals(1.5f, mod.coefficient()); + assertEquals(600, mod.constant().toSeconds()); } } From 091e4ed5620630e3f70e4eb585a733a2e28d4d2d Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 18 Apr 2024 16:42:53 +0200 Subject: [PATCH 096/121] Update documentation --- docs/sandbox/VehicleParking.md | 100 +++++++++--------- .../updaters/VehicleParkingUpdaterConfig.java | 2 +- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/docs/sandbox/VehicleParking.md b/docs/sandbox/VehicleParking.md index 7599a762602..8d9e4942440 100644 --- a/docs/sandbox/VehicleParking.md +++ b/docs/sandbox/VehicleParking.md @@ -33,17 +33,17 @@ All updaters have the following parameters in common: -| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | -|---------------------------------|:-----------:|----------------------------------------------|:----------:|---------------|:-----:| -| type = "vehicle-parking" | `enum` | The type of the updater. | *Required* | | 1.5 | -| facilitiesFrequencySec | `integer` | How often the facilities should be updated. | *Optional* | `3600` | 2.2 | -| facilitiesUrl | `string` | URL of the facilities. | *Optional* | | 2.2 | -| [feedId](#u__2__feedId) | `string` | The name of the data source. | *Required* | | 2.2 | -| hubsUrl | `string` | Hubs URL | *Optional* | | 2.2 | -| [sourceType](#u__2__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 | -| [timeZone](#u__2__timeZone) | `time-zone` | The time zone of the feed. | *Optional* | | 2.2 | -| utilizationsFrequencySec | `integer` | How often the utilization should be updated. | *Optional* | `600` | 2.2 | -| utilizationsUrl | `string` | URL of the utilization data. | *Optional* | | 2.2 | +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|---------------------------------|:-----------:|------------------------------------------------------------------------------|:----------:|---------------|:-----:| +| type = "vehicle-parking" | `enum` | The type of the updater. | *Required* | | 1.5 | +| facilitiesFrequencySec | `integer` | How often the facilities should be updated. | *Optional* | `3600` | 2.2 | +| facilitiesUrl | `string` | URL of the facilities. | *Optional* | | 2.2 | +| [feedId](#u__2__feedId) | `string` | The id of the data source, which will be the prefix of the parking lot's id. | *Required* | | 2.2 | +| hubsUrl | `string` | Hubs URL | *Optional* | | 2.2 | +| [sourceType](#u__2__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 | +| [timeZone](#u__2__timeZone) | `time-zone` | The time zone of the feed. | *Optional* | | 2.2 | +| utilizationsFrequencySec | `integer` | How often the utilization should be updated. | *Optional* | `600` | 2.2 | +| utilizationsUrl | `string` | URL of the utilization data. | *Optional* | | 2.2 | #### Details @@ -53,7 +53,7 @@ All updaters have the following parameters in common: **Since version:** `2.2` ∙ **Type:** `string` ∙ **Cardinality:** `Required` **Path:** /updaters/[2] -The name of the data source. +The id of the data source, which will be the prefix of the parking lot's id. This will end up in the API responses as the feed id of of the parking lot. @@ -104,16 +104,16 @@ Used for converting abstract opening hours into concrete points in time. -| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | -|---------------------------------|:---------------:|----------------------------------------------------------------------------|:----------:|---------------|:-----:| -| type = "vehicle-parking" | `enum` | The type of the updater. | *Required* | | 1.5 | -| [feedId](#u__3__feedId) | `string` | The name of the data source. | *Required* | | 2.2 | -| frequency | `duration` | How often to update the source. | *Optional* | `"PT1M"` | 2.2 | -| [sourceType](#u__3__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 | -| [timeZone](#u__3__timeZone) | `time-zone` | The time zone of the feed. | *Optional* | | 2.2 | -| url | `string` | URL of the resource. | *Required* | | 2.2 | -| [headers](#u__3__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.2 | -| [tags](#u__3__tags) | `string[]` | Tags to add to the parking lots. | *Optional* | | 2.2 | +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|---------------------------------|:---------------:|------------------------------------------------------------------------------|:----------:|---------------|:-----:| +| type = "vehicle-parking" | `enum` | The type of the updater. | *Required* | | 1.5 | +| [feedId](#u__3__feedId) | `string` | The id of the data source, which will be the prefix of the parking lot's id. | *Required* | | 2.2 | +| frequency | `duration` | How often to update the source. | *Optional* | `"PT1M"` | 2.2 | +| [sourceType](#u__3__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 | +| [timeZone](#u__3__timeZone) | `time-zone` | The time zone of the feed. | *Optional* | | 2.2 | +| url | `string` | URL of the resource. | *Required* | | 2.2 | +| [headers](#u__3__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.2 | +| [tags](#u__3__tags) | `string[]` | Tags to add to the parking lots. | *Optional* | | 2.2 | #### Details @@ -123,7 +123,7 @@ Used for converting abstract opening hours into concrete points in time. **Since version:** `2.2` ∙ **Type:** `string` ∙ **Cardinality:** `Required` **Path:** /updaters/[3] -The name of the data source. +The id of the data source, which will be the prefix of the parking lot's id. This will end up in the API responses as the feed id of of the parking lot. @@ -191,14 +191,14 @@ Tags to add to the parking lots. -| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | -|---------------------------------|:---------------:|----------------------------------------------------------------------------|:----------:|---------------|:-----:| -| type = "vehicle-parking" | `enum` | The type of the updater. | *Required* | | 1.5 | -| [feedId](#u__4__feedId) | `string` | The name of the data source. | *Required* | | 2.2 | -| frequency | `duration` | How often to update the source. | *Optional* | `"PT1M"` | 2.3 | -| [sourceType](#u__4__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 | -| url | `uri` | URL of the locations endpoint. | *Required* | | 2.3 | -| [headers](#u__4__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 | +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|---------------------------------|:---------------:|------------------------------------------------------------------------------|:----------:|---------------|:-----:| +| type = "vehicle-parking" | `enum` | The type of the updater. | *Required* | | 1.5 | +| [feedId](#u__4__feedId) | `string` | The id of the data source, which will be the prefix of the parking lot's id. | *Required* | | 2.2 | +| frequency | `duration` | How often to update the source. | *Optional* | `"PT1M"` | 2.3 | +| [sourceType](#u__4__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 | +| url | `uri` | URL of the locations endpoint. | *Required* | | 2.3 | +| [headers](#u__4__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 | #### Details @@ -208,7 +208,7 @@ Tags to add to the parking lots. **Since version:** `2.2` ∙ **Type:** `string` ∙ **Cardinality:** `Required` **Path:** /updaters/[4] -The name of the data source. +The id of the data source, which will be the prefix of the parking lot's id. This will end up in the API responses as the feed id of of the parking lot. @@ -256,14 +256,14 @@ HTTP headers to add to the request. Any header key, value can be inserted. -| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | -|---------------------------------|:---------------:|----------------------------------------------------------------------------|:----------:|---------------|:-----:| -| type = "vehicle-parking" | `enum` | The type of the updater. | *Required* | | 1.5 | -| [feedId](#u__5__feedId) | `string` | The name of the data source. | *Required* | | 2.2 | -| frequency | `duration` | How often to update the source. | *Optional* | `"PT1M"` | 2.6 | -| [sourceType](#u__5__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 | -| url | `uri` | URL of the locations endpoint. | *Required* | | 2.6 | -| [headers](#u__5__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.6 | +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|---------------------------------|:---------------:|------------------------------------------------------------------------------|:----------:|---------------|:-----:| +| type = "vehicle-parking" | `enum` | The type of the updater. | *Required* | | 1.5 | +| [feedId](#u__5__feedId) | `string` | The id of the data source, which will be the prefix of the parking lot's id. | *Required* | | 2.2 | +| frequency | `duration` | How often to update the source. | *Optional* | `"PT1M"` | 2.6 | +| [sourceType](#u__5__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 | +| url | `uri` | URL of the locations endpoint. | *Required* | | 2.6 | +| [headers](#u__5__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.6 | #### Details @@ -273,7 +273,7 @@ HTTP headers to add to the request. Any header key, value can be inserted. **Since version:** `2.2` ∙ **Type:** `string` ∙ **Cardinality:** `Required` **Path:** /updaters/[5] -The name of the data source. +The id of the data source, which will be the prefix of the parking lot's id. This will end up in the API responses as the feed id of of the parking lot. @@ -317,14 +317,14 @@ HTTP headers to add to the request. Any header key, value can be inserted. -| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | -|----------------------------------|:---------------:|----------------------------------------------------------------------------|:----------:|---------------|:-----:| -| type = "vehicle-parking" | `enum` | The type of the updater. | *Required* | | 1.5 | -| [feedId](#u__13__feedId) | `string` | The name of the data source. | *Required* | | 2.2 | -| frequency | `duration` | How often to update the source. | *Optional* | `"PT1M"` | 2.6 | -| [sourceType](#u__13__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 | -| url | `uri` | URL of the locations endpoint. | *Required* | | 2.6 | -| [headers](#u__13__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.6 | +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|----------------------------------|:---------------:|------------------------------------------------------------------------------|:----------:|---------------|:-----:| +| type = "vehicle-parking" | `enum` | The type of the updater. | *Required* | | 1.5 | +| [feedId](#u__13__feedId) | `string` | The id of the data source, which will be the prefix of the parking lot's id. | *Required* | | 2.2 | +| frequency | `duration` | How often to update the source. | *Optional* | `"PT1M"` | 2.6 | +| [sourceType](#u__13__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 | +| url | `uri` | URL of the locations endpoint. | *Required* | | 2.6 | +| [headers](#u__13__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.6 | #### Details @@ -334,7 +334,7 @@ HTTP headers to add to the request. Any header key, value can be inserted. **Since version:** `2.2` ∙ **Type:** `string` ∙ **Cardinality:** `Required` **Path:** /updaters/[13] -The name of the data source. +The id of the data source, which will be the prefix of the parking lot's id. This will end up in the API responses as the feed id of of the parking lot. diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/VehicleParkingUpdaterConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/VehicleParkingUpdaterConfig.java index d04e1900795..c687899009f 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/VehicleParkingUpdaterConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/VehicleParkingUpdaterConfig.java @@ -28,7 +28,7 @@ public static VehicleParkingUpdaterParameters create(String updaterRef, NodeAdap var feedId = c .of("feedId") .since(V2_2) - .summary("The name of the data source.") + .summary("The id of the data source, which will be the prefix of the parking lot's id.") .description("This will end up in the API responses as the feed id of of the parking lot.") .asString(); return switch (sourceType) { From 355b287cb844464379c592ba94f8b6ecc850282e Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 18 Apr 2024 16:56:31 +0200 Subject: [PATCH 097/121] Update documentation --- .../org/opentripplanner/ext/flex/trip/UnscheduledTrip.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java index db662a5fd45..7fa31c78114 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java @@ -151,8 +151,8 @@ public Stream getFlexAccessTemplates( } /** - * Get the correct {@link FlexPathCalculator} depending on the {@code durationModified}. - * If the modifier doesn't actually modify, we don't + * Get the correct {@link FlexPathCalculator} depending on the {@code durationModifier}. + * If the modifier doesn't actually modify, we return the regular calculator. */ protected FlexPathCalculator flexPathCalculator(FlexPathCalculator calculator) { if (!durationModifier.isZero()) { From cd166d80abb4714227db585eb04fd0479bfb25ae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 19 Apr 2024 00:05:45 +0000 Subject: [PATCH 098/121] Update dependency ch.qos.logback:logback-classic to v1.5.6 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 66d2919b3c4..7aa9edec631 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ 5.10.2 1.12.3 5.5.3 - 1.5.3 + 1.5.6 9.10.0 2.0.13 2.0.15 From 7440b8aca2e613df9780e75e255c500d9d3266b4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 19 Apr 2024 00:05:51 +0000 Subject: [PATCH 099/121] Update dependency org.apache.maven.plugins:maven-gpg-plugin to v3.2.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7aa9edec631..01971b3804e 100644 --- a/pom.xml +++ b/pom.xml @@ -993,7 +993,7 @@ org.apache.maven.plugins maven-gpg-plugin - 3.2.2 + 3.2.3 sign-artifacts From c5d87a14f0c9e6aa9d692e7e795a32619d96072f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 19 Apr 2024 10:36:07 +0000 Subject: [PATCH 100/121] Update dependency org.apache.maven.plugins:maven-gpg-plugin to v3.2.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 01971b3804e..1dffab1348e 100644 --- a/pom.xml +++ b/pom.xml @@ -993,7 +993,7 @@ org.apache.maven.plugins maven-gpg-plugin - 3.2.3 + 3.2.4 sign-artifacts From aa92132cea37082140cf9aba55d6dcb46da7dab6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 21 Apr 2024 22:22:29 +0000 Subject: [PATCH 101/121] Update dependency org.apache.maven.plugins:maven-jar-plugin to v3.4.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1dffab1348e..adb529027d1 100644 --- a/pom.xml +++ b/pom.xml @@ -158,7 +158,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.4.0 + 3.4.1 From e2cc0e57a50eb68d563ef38e45c66b2ecb0a97de Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Apr 2024 01:04:50 +0000 Subject: [PATCH 102/121] Update dependency org.apache.maven.plugins:maven-shade-plugin to v3.5.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index adb529027d1..ce89fc467e6 100644 --- a/pom.xml +++ b/pom.xml @@ -363,7 +363,7 @@ properly if some input files are missing a terminating newline) --> org.apache.maven.plugins maven-shade-plugin - 3.5.2 + 3.5.3 package From 3572d3b7178d271a18077c29461172e053db67b3 Mon Sep 17 00:00:00 2001 From: Andrew Byrd Date: Thu, 25 Apr 2024 15:48:04 +0800 Subject: [PATCH 103/121] de-emphasize mailing list in landing page --- docs/index.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/docs/index.md b/docs/index.md index f1ddc791212..b10013af235 100644 --- a/docs/index.md +++ b/docs/index.md @@ -60,12 +60,7 @@ your own OTP instance, the best place to start is the [Basic Tutorial](Basic-Tut # Getting help -The fastest way to get help is to use our [Gitter chat room](https://gitter.im/opentripplanner/OpenTripPlanner) -where most of the core developers are. -You can also send questions and comments to the [mailing list](http://groups.google.com/group/opentripplanner-users) -or file bug reports via the Github [issue tracker](https://github.com/openplans/OpenTripPlanner/issues). -Note that the issue tracker is not intended for support questions or discussions. Please use the -chat or the mailing list instead. +The fastest way to get help is to use our [Gitter chat room](https://gitter.im/opentripplanner/OpenTripPlanner) where most of the core developers are. Bug reports may be filed via the Github [issue tracker](https://github.com/openplans/OpenTripPlanner/issues). The issue tracker is not intended for support questions or discussions. Please use the chat for this purpose. The OpenTripPlanner [mailing list](http://groups.google.com/group/opentripplanner-users) is treated as a legacy communications channel and used almost exclusively for project announcements. Again, please direct development and support discussions to the Gitter chat. # Financial and In-Kind Support From 965fe275a47d4e81244e86fb4dc5672caa3adbd9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 25 Apr 2024 12:26:55 +0000 Subject: [PATCH 104/121] Update Debug UI dependencies (non-major) --- client-next/package-lock.json | 188 +++++++++++++++++----------------- client-next/package.json | 14 +-- 2 files changed, 101 insertions(+), 101 deletions(-) diff --git a/client-next/package-lock.json b/client-next/package-lock.json index 08a9146ceb1..0eb34f02228 100644 --- a/client-next/package-lock.json +++ b/client-next/package-lock.json @@ -12,7 +12,7 @@ "bootstrap": "5.3.3", "graphql": "16.8.1", "graphql-request": "6.1.0", - "maplibre-gl": "4.1.2", + "maplibre-gl": "4.1.3", "react": "18.2.0", "react-bootstrap": "2.10.2", "react-dom": "18.2.0", @@ -23,13 +23,13 @@ "@graphql-codegen/client-preset": "4.2.5", "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.4.1", - "@testing-library/react": "15.0.2", + "@testing-library/react": "15.0.4", "@types/react": "18.2.79", "@types/react-dom": "18.2.25", - "@typescript-eslint/eslint-plugin": "7.7.0", - "@typescript-eslint/parser": "7.7.0", + "@typescript-eslint/eslint-plugin": "7.7.1", + "@typescript-eslint/parser": "7.7.1", "@vitejs/plugin-react": "4.2.1", - "@vitest/coverage-v8": "1.5.0", + "@vitest/coverage-v8": "1.5.2", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "2.29.1", @@ -40,8 +40,8 @@ "jsdom": "24.0.0", "prettier": "3.2.5", "typescript": "5.4.5", - "vite": "5.2.8", - "vitest": "1.5.0" + "vite": "5.2.10", + "vitest": "1.5.2" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -3372,9 +3372,9 @@ } }, "node_modules/@testing-library/react": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-15.0.2.tgz", - "integrity": "sha512-5mzIpuytB1ctpyywvyaY2TAAUQVCZIGqwiqFQf6u9lvj/SJQepGUzNV18Xpk+NLCaCE2j7CWrZE0tEf9xLZYiQ==", + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-15.0.4.tgz", + "integrity": "sha512-Fw/LM1emOHKfCxv5R0tz+25TOtiMt0o5Np1zJmb4LbSacOagXQX4ooAaHiJfGUMe+OjUk504BX11W+9Z8CvyZA==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", @@ -3576,16 +3576,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz", - "integrity": "sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz", + "integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.7.0", - "@typescript-eslint/type-utils": "7.7.0", - "@typescript-eslint/utils": "7.7.0", - "@typescript-eslint/visitor-keys": "7.7.0", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/type-utils": "7.7.1", + "@typescript-eslint/utils": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.3.1", @@ -3644,15 +3644,15 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.0.tgz", - "integrity": "sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.1.tgz", + "integrity": "sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.7.0", - "@typescript-eslint/types": "7.7.0", - "@typescript-eslint/typescript-estree": "7.7.0", - "@typescript-eslint/visitor-keys": "7.7.0", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/typescript-estree": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", "debug": "^4.3.4" }, "engines": { @@ -3672,13 +3672,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz", - "integrity": "sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz", + "integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.0", - "@typescript-eslint/visitor-keys": "7.7.0" + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3689,13 +3689,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz", - "integrity": "sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz", + "integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.7.0", - "@typescript-eslint/utils": "7.7.0", + "@typescript-eslint/typescript-estree": "7.7.1", + "@typescript-eslint/utils": "7.7.1", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -3716,9 +3716,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.0.tgz", - "integrity": "sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz", + "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3729,13 +3729,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz", - "integrity": "sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz", + "integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.0", - "@typescript-eslint/visitor-keys": "7.7.0", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3790,17 +3790,17 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.0.tgz", - "integrity": "sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz", + "integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.15", "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.7.0", - "@typescript-eslint/types": "7.7.0", - "@typescript-eslint/typescript-estree": "7.7.0", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/typescript-estree": "7.7.1", "semver": "^7.6.0" }, "engines": { @@ -3848,12 +3848,12 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz", - "integrity": "sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz", + "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/types": "7.7.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -3890,9 +3890,9 @@ } }, "node_modules/@vitest/coverage-v8": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.5.0.tgz", - "integrity": "sha512-1igVwlcqw1QUMdfcMlzzY4coikSIBN944pkueGi0pawrX5I5Z+9hxdTR+w3Sg6Q3eZhvdMAs8ZaF9JuTG1uYOQ==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.5.2.tgz", + "integrity": "sha512-QJqxRnbCwNtbbegK9E93rBmhN3dbfG1bC/o52Bqr0zGCYhQzwgwvrJBG7Q8vw3zilX6Ryy6oa/mkZku2lLJx1Q==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.1", @@ -3913,17 +3913,17 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "1.5.0" + "vitest": "1.5.2" } }, "node_modules/@vitest/expect": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.0.tgz", - "integrity": "sha512-0pzuCI6KYi2SIC3LQezmxujU9RK/vwC1U9R0rLuGlNGcOuDWxqWKu6nUdFsX9tH1WU0SXtAxToOsEjeUn1s3hA==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.2.tgz", + "integrity": "sha512-rf7MTD1WCoDlN3FfYJ9Llfp0PbdtOMZ3FIF0AVkDnKbp3oiMW1c8AmvRZBcqbAhDUAvF52e9zx4WQM1r3oraVA==", "dev": true, "dependencies": { - "@vitest/spy": "1.5.0", - "@vitest/utils": "1.5.0", + "@vitest/spy": "1.5.2", + "@vitest/utils": "1.5.2", "chai": "^4.3.10" }, "funding": { @@ -3931,12 +3931,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.0.tgz", - "integrity": "sha512-7HWwdxXP5yDoe7DTpbif9l6ZmDwCzcSIK38kTSIt6CFEpMjX4EpCgT6wUmS0xTXqMI6E/ONmfgRKmaujpabjZQ==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.2.tgz", + "integrity": "sha512-7IJ7sJhMZrqx7HIEpv3WrMYcq8ZNz9L6alo81Y6f8hV5mIE6yVZsFoivLZmr0D777klm1ReqonE9LyChdcmw6g==", "dev": true, "dependencies": { - "@vitest/utils": "1.5.0", + "@vitest/utils": "1.5.2", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -3972,9 +3972,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.0.tgz", - "integrity": "sha512-qpv3fSEuNrhAO3FpH6YYRdaECnnRjg9VxbhdtPwPRnzSfHVXnNzzrpX4cJxqiwgRMo7uRMWDFBlsBq4Cr+rO3A==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.2.tgz", + "integrity": "sha512-CTEp/lTYos8fuCc9+Z55Ga5NVPKUgExritjF5VY7heRFUfheoAqBneUlvXSUJHUZPjnPmyZA96yLRJDP1QATFQ==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -4018,9 +4018,9 @@ "dev": true }, "node_modules/@vitest/spy": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.0.tgz", - "integrity": "sha512-vu6vi6ew5N5MMHJjD5PoakMRKYdmIrNJmyfkhRpQt5d9Ewhw9nZ5Aqynbi3N61bvk9UvZ5UysMT6ayIrZ8GA9w==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.2.tgz", + "integrity": "sha512-xCcPvI8JpCtgikT9nLpHPL1/81AYqZy1GCy4+MCHBE7xi8jgsYkULpW5hrx5PGLgOQjUpb6fd15lqcriJ40tfQ==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -4030,9 +4030,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.0.tgz", - "integrity": "sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.2.tgz", + "integrity": "sha512-sWOmyofuXLJ85VvXNsroZur7mOJGiQeM0JN3/0D1uU8U9bGFM69X1iqHaRXl6R8BwaLY6yPCogP257zxTzkUdA==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -8333,9 +8333,9 @@ } }, "node_modules/maplibre-gl": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.1.2.tgz", - "integrity": "sha512-98T+3BesL4w/N39q/rgs9q6HzHLG6pgbS9UaTqg6fMISfzy2WGKokjK205ENFDDmEljj54/LTfdXgqg2XfYU4A==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.1.3.tgz", + "integrity": "sha512-nMy5h0kzq9Z66C6AIb3p2BvLIVHz75dGGQow22x+h9/VOihr0IPQI26ylAi6lHqvEy2VqjiRmKAMlFwt0xFKfQ==", "dependencies": { "@mapbox/geojson-rewind": "^0.5.2", "@mapbox/jsonlint-lines-primitives": "^2.0.2", @@ -10842,9 +10842,9 @@ } }, "node_modules/vite": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz", - "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==", + "version": "5.2.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.10.tgz", + "integrity": "sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==", "dev": true, "dependencies": { "esbuild": "^0.20.1", @@ -10897,9 +10897,9 @@ } }, "node_modules/vite-node": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.0.tgz", - "integrity": "sha512-tV8h6gMj6vPzVCa7l+VGq9lwoJjW8Y79vst8QZZGiuRAfijU+EEWuc0kFpmndQrWhMMhet1jdSF+40KSZUqIIw==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.2.tgz", + "integrity": "sha512-Y8p91kz9zU+bWtF7HGt6DVw2JbhyuB2RlZix3FPYAYmUyZ3n7iTp8eSyLyY6sxtPegvxQtmlTMhfPhUfCUF93A==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -10919,16 +10919,16 @@ } }, "node_modules/vitest": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.0.tgz", - "integrity": "sha512-d8UKgR0m2kjdxDWX6911uwxout6GHS0XaGH1cksSIVVG8kRlE7G7aBw7myKQCvDI5dT4j7ZMa+l706BIORMDLw==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.2.tgz", + "integrity": "sha512-l9gwIkq16ug3xY7BxHwcBQovLZG75zZL0PlsiYQbf76Rz6QGs54416UWMtC0jXeihvHvcHrf2ROEjkQRVpoZYw==", "dev": true, "dependencies": { - "@vitest/expect": "1.5.0", - "@vitest/runner": "1.5.0", - "@vitest/snapshot": "1.5.0", - "@vitest/spy": "1.5.0", - "@vitest/utils": "1.5.0", + "@vitest/expect": "1.5.2", + "@vitest/runner": "1.5.2", + "@vitest/snapshot": "1.5.2", + "@vitest/spy": "1.5.2", + "@vitest/utils": "1.5.2", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -10942,7 +10942,7 @@ "tinybench": "^2.5.1", "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.5.0", + "vite-node": "1.5.2", "why-is-node-running": "^2.2.2" }, "bin": { @@ -10957,8 +10957,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.5.0", - "@vitest/ui": "1.5.0", + "@vitest/browser": "1.5.2", + "@vitest/ui": "1.5.2", "happy-dom": "*", "jsdom": "*" }, diff --git a/client-next/package.json b/client-next/package.json index 643acd1c082..0fe51abdad8 100644 --- a/client-next/package.json +++ b/client-next/package.json @@ -21,7 +21,7 @@ "bootstrap": "5.3.3", "graphql": "16.8.1", "graphql-request": "6.1.0", - "maplibre-gl": "4.1.2", + "maplibre-gl": "4.1.3", "react": "18.2.0", "react-bootstrap": "2.10.2", "react-dom": "18.2.0", @@ -32,13 +32,13 @@ "@graphql-codegen/client-preset": "4.2.5", "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.4.1", - "@testing-library/react": "15.0.2", + "@testing-library/react": "15.0.4", "@types/react": "18.2.79", "@types/react-dom": "18.2.25", - "@typescript-eslint/eslint-plugin": "7.7.0", - "@typescript-eslint/parser": "7.7.0", + "@typescript-eslint/eslint-plugin": "7.7.1", + "@typescript-eslint/parser": "7.7.1", "@vitejs/plugin-react": "4.2.1", - "@vitest/coverage-v8": "1.5.0", + "@vitest/coverage-v8": "1.5.2", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "2.29.1", @@ -49,7 +49,7 @@ "jsdom": "24.0.0", "prettier": "3.2.5", "typescript": "5.4.5", - "vite": "5.2.8", - "vitest": "1.5.0" + "vite": "5.2.10", + "vitest": "1.5.2" } } From a5d91fb0e8cf12a8ba38dd76ed257e2b4ab732d1 Mon Sep 17 00:00:00 2001 From: Henrik Abrahamsson Date: Thu, 25 Apr 2024 14:59:04 +0200 Subject: [PATCH 105/121] Resolve review comments --- .../opentripplanner/raptor/spi/RaptorCostCalculator.java | 2 +- .../raptoradapter/transit/cost/CostCalculatorFactory.java | 4 ++-- .../raptoradapter/transit/cost/DefaultCostCalculator.java | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/opentripplanner/raptor/spi/RaptorCostCalculator.java b/src/main/java/org/opentripplanner/raptor/spi/RaptorCostCalculator.java index f69d5410fc4..7a9928e51aa 100644 --- a/src/main/java/org/opentripplanner/raptor/spi/RaptorCostCalculator.java +++ b/src/main/java/org/opentripplanner/raptor/spi/RaptorCostCalculator.java @@ -53,7 +53,7 @@ int boardingCost( /** * Used for estimating the remaining value for a criteria at a given stop arrival. The calculated * value should be an optimistic estimate for the heuristics to work properly. So, to calculate - * the generalized cost for given the {@code minTravelTime} and {@code minNumTransfers} retuning + * the generalized cost for given the {@code minTravelTime} and {@code minNumTransfers} returning * the greatest value, which is guaranteed to be less than the * real value would be correct and a good choice. */ diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/CostCalculatorFactory.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/CostCalculatorFactory.java index 3a79b25e678..fef7b3509e3 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/CostCalculatorFactory.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/CostCalculatorFactory.java @@ -6,11 +6,11 @@ public class CostCalculatorFactory { public static RaptorCostCalculator createCostCalculator( GeneralizedCostParameters generalizedCostParameters, - int[] stopTransferCosts + int[] stopBoardAlightCosts ) { RaptorCostCalculator calculator = new DefaultCostCalculator<>( generalizedCostParameters, - stopTransferCosts + stopBoardAlightCosts ); if (generalizedCostParameters.wheelchairEnabled()) { diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/DefaultCostCalculator.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/DefaultCostCalculator.java index d5951812612..ee2f1282625 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/DefaultCostCalculator.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/DefaultCostCalculator.java @@ -130,11 +130,11 @@ public int calculateRemainingMinCost(int minTravelTime, int minNumTransfers, int transitFactors.minFactor() * minTravelTime ); - } else if (stopTransferCost != null) { - // Remove cost that was added during alighting similar as we do in the costEgress() method - return (transitFactors.minFactor() * minTravelTime - stopTransferCost[fromStop]); } else { - return transitFactors.minFactor() * minTravelTime; + // Remove cost that was added during alighting similar as we do in the costEgress() method + int fixedCost = transitFactors.minFactor() * minTravelTime; + + return stopTransferCost == null ? fixedCost : fixedCost - stopTransferCost[fromStop]; } } From 329266c47897e2e883fb124fbd4f13b1fc3037f7 Mon Sep 17 00:00:00 2001 From: OTP Bot Date: Thu, 25 Apr 2024 13:08:12 +0000 Subject: [PATCH 106/121] Upgrade debug client to version 2024/04/2024-04-25T13:07 --- src/client/debug-client-preview/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/debug-client-preview/index.html b/src/client/debug-client-preview/index.html index 1b561ffc656..853fee5b440 100644 --- a/src/client/debug-client-preview/index.html +++ b/src/client/debug-client-preview/index.html @@ -5,8 +5,8 @@ OTP Debug Client - - + +
From 23cd12ef4fdc2f2d8311f1f0017a0c3624a15015 Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Thu, 25 Apr 2024 13:29:26 +0000 Subject: [PATCH 107/121] Add changelog entry for #5783 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index d12e9a100f0..cafc677ccc6 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -15,6 +15,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Overwrite default WALK directMode when it is not set in the request, but modes is set [#5779](https://github.com/opentripplanner/OpenTripPlanner/pull/5779) - Fix trip duplication in Graph Builder DSJ mapping [#5794](https://github.com/opentripplanner/OpenTripPlanner/pull/5794) - Optionally abort startup when unknown configuration parameters were detected [#5676](https://github.com/opentripplanner/OpenTripPlanner/pull/5676) +- Fix bug in heuristics cost calculation for egress legs [#5783](https://github.com/opentripplanner/OpenTripPlanner/pull/5783) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.5.0 (2024-03-13) From a6d8e41122ab4def799c4618995c267f02442c8d Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Thu, 25 Apr 2024 16:24:12 +0000 Subject: [PATCH 108/121] Add changelog entry for #5820 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index cafc677ccc6..2ba638c9ab1 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -16,6 +16,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Fix trip duplication in Graph Builder DSJ mapping [#5794](https://github.com/opentripplanner/OpenTripPlanner/pull/5794) - Optionally abort startup when unknown configuration parameters were detected [#5676](https://github.com/opentripplanner/OpenTripPlanner/pull/5676) - Fix bug in heuristics cost calculation for egress legs [#5783](https://github.com/opentripplanner/OpenTripPlanner/pull/5783) +- De-emphasize mailing list in landing page [#5820](https://github.com/opentripplanner/OpenTripPlanner/pull/5820) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.5.0 (2024-03-13) From 0a1abb2c502f5a1d87e4b482d9a8681138db7058 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 2 May 2024 09:23:32 +0000 Subject: [PATCH 109/121] Update Debug UI dependencies (non-major) --- client-next/package-lock.json | 242 +++++++++++++++++----------------- client-next/package.json | 22 ++-- 2 files changed, 135 insertions(+), 129 deletions(-) diff --git a/client-next/package-lock.json b/client-next/package-lock.json index 0eb34f02228..abe2c5d3ed6 100644 --- a/client-next/package-lock.json +++ b/client-next/package-lock.json @@ -13,9 +13,9 @@ "graphql": "16.8.1", "graphql-request": "6.1.0", "maplibre-gl": "4.1.3", - "react": "18.2.0", + "react": "18.3.1", "react-bootstrap": "2.10.2", - "react-dom": "18.2.0", + "react-dom": "18.3.1", "react-map-gl": "7.1.7" }, "devDependencies": { @@ -23,25 +23,25 @@ "@graphql-codegen/client-preset": "4.2.5", "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.4.1", - "@testing-library/react": "15.0.4", - "@types/react": "18.2.79", - "@types/react-dom": "18.2.25", - "@typescript-eslint/eslint-plugin": "7.7.1", - "@typescript-eslint/parser": "7.7.1", + "@testing-library/react": "15.0.6", + "@types/react": "18.3.1", + "@types/react-dom": "18.3.0", + "@typescript-eslint/eslint-plugin": "7.8.0", + "@typescript-eslint/parser": "7.8.0", "@vitejs/plugin-react": "4.2.1", - "@vitest/coverage-v8": "1.5.2", + "@vitest/coverage-v8": "1.5.3", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "2.29.1", "eslint-plugin-jsx-a11y": "6.8.0", "eslint-plugin-react": "7.34.1", - "eslint-plugin-react-hooks": "4.6.0", + "eslint-plugin-react-hooks": "4.6.2", "eslint-plugin-react-refresh": "0.4.6", "jsdom": "24.0.0", "prettier": "3.2.5", "typescript": "5.4.5", - "vite": "5.2.10", - "vitest": "1.5.2" + "vite": "5.2.11", + "vitest": "1.5.3" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -3372,9 +3372,9 @@ } }, "node_modules/@testing-library/react": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-15.0.4.tgz", - "integrity": "sha512-Fw/LM1emOHKfCxv5R0tz+25TOtiMt0o5Np1zJmb4LbSacOagXQX4ooAaHiJfGUMe+OjUk504BX11W+9Z8CvyZA==", + "version": "15.0.6", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-15.0.6.tgz", + "integrity": "sha512-UlbazRtEpQClFOiYp+1BapMT+xyqWMnE+hh9tn5DQ6gmlE7AIZWcGpzZukmDZuFk3By01oiqOf8lRedLS4k6xQ==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", @@ -3385,8 +3385,14 @@ "node": ">=18" }, "peerDependencies": { + "@types/react": "^18.0.0", "react": "^18.0.0", "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/@types/aria-query": { @@ -3522,18 +3528,18 @@ "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "node_modules/@types/react": { - "version": "18.2.79", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.79.tgz", - "integrity": "sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.1.tgz", + "integrity": "sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.2.25", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.25.tgz", - "integrity": "sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", "dev": true, "dependencies": { "@types/react": "*" @@ -3576,16 +3582,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz", - "integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz", + "integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/type-utils": "7.7.1", - "@typescript-eslint/utils": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/type-utils": "7.8.0", + "@typescript-eslint/utils": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.3.1", @@ -3644,15 +3650,15 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.1.tgz", - "integrity": "sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz", + "integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/typescript-estree": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4" }, "engines": { @@ -3672,13 +3678,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz", - "integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz", + "integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1" + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3689,13 +3695,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz", - "integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz", + "integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.7.1", - "@typescript-eslint/utils": "7.7.1", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/utils": "7.8.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -3716,9 +3722,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz", - "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz", + "integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3729,13 +3735,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz", - "integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", + "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3790,17 +3796,17 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz", - "integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz", + "integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.15", "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/typescript-estree": "7.7.1", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", "semver": "^7.6.0" }, "engines": { @@ -3848,12 +3854,12 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz", - "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz", + "integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/types": "7.8.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -3890,9 +3896,9 @@ } }, "node_modules/@vitest/coverage-v8": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.5.2.tgz", - "integrity": "sha512-QJqxRnbCwNtbbegK9E93rBmhN3dbfG1bC/o52Bqr0zGCYhQzwgwvrJBG7Q8vw3zilX6Ryy6oa/mkZku2lLJx1Q==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.5.3.tgz", + "integrity": "sha512-DPyGSu/fPHOJuPxzFSQoT4N/Fu/2aJfZRtEpEp8GI7NHsXBGE94CQ+pbEGBUMFjatsHPDJw/+TAF9r4ens2CNw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.1", @@ -3913,17 +3919,17 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "1.5.2" + "vitest": "1.5.3" } }, "node_modules/@vitest/expect": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.2.tgz", - "integrity": "sha512-rf7MTD1WCoDlN3FfYJ9Llfp0PbdtOMZ3FIF0AVkDnKbp3oiMW1c8AmvRZBcqbAhDUAvF52e9zx4WQM1r3oraVA==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.3.tgz", + "integrity": "sha512-y+waPz31pOFr3rD7vWTbwiLe5+MgsMm40jTZbQE8p8/qXyBX3CQsIXRx9XK12IbY7q/t5a5aM/ckt33b4PxK2g==", "dev": true, "dependencies": { - "@vitest/spy": "1.5.2", - "@vitest/utils": "1.5.2", + "@vitest/spy": "1.5.3", + "@vitest/utils": "1.5.3", "chai": "^4.3.10" }, "funding": { @@ -3931,12 +3937,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.2.tgz", - "integrity": "sha512-7IJ7sJhMZrqx7HIEpv3WrMYcq8ZNz9L6alo81Y6f8hV5mIE6yVZsFoivLZmr0D777klm1ReqonE9LyChdcmw6g==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.3.tgz", + "integrity": "sha512-7PlfuReN8692IKQIdCxwir1AOaP5THfNkp0Uc4BKr2na+9lALNit7ub9l3/R7MP8aV61+mHKRGiqEKRIwu6iiQ==", "dev": true, "dependencies": { - "@vitest/utils": "1.5.2", + "@vitest/utils": "1.5.3", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -3972,9 +3978,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.2.tgz", - "integrity": "sha512-CTEp/lTYos8fuCc9+Z55Ga5NVPKUgExritjF5VY7heRFUfheoAqBneUlvXSUJHUZPjnPmyZA96yLRJDP1QATFQ==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.3.tgz", + "integrity": "sha512-K3mvIsjyKYBhNIDujMD2gfQEzddLe51nNOAf45yKRt/QFJcUIeTQd2trRvv6M6oCBHNVnZwFWbQ4yj96ibiDsA==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -4018,9 +4024,9 @@ "dev": true }, "node_modules/@vitest/spy": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.2.tgz", - "integrity": "sha512-xCcPvI8JpCtgikT9nLpHPL1/81AYqZy1GCy4+MCHBE7xi8jgsYkULpW5hrx5PGLgOQjUpb6fd15lqcriJ40tfQ==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.3.tgz", + "integrity": "sha512-Llj7Jgs6lbnL55WoshJUUacdJfjU2honvGcAJBxhra5TPEzTJH8ZuhI3p/JwqqfnTr4PmP7nDmOXP53MS7GJlg==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -4030,9 +4036,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.2.tgz", - "integrity": "sha512-sWOmyofuXLJ85VvXNsroZur7mOJGiQeM0JN3/0D1uU8U9bGFM69X1iqHaRXl6R8BwaLY6yPCogP257zxTzkUdA==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.3.tgz", + "integrity": "sha512-rE9DTN1BRhzkzqNQO+kw8ZgfeEBCLXiHJwetk668shmNBpSagQxneT5eSqEBLP+cqSiAeecvQmbpFfdMyLcIQA==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -4071,9 +4077,9 @@ } }, "node_modules/@vitest/utils/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, "node_modules/@whatwg-node/events": { @@ -5982,9 +5988,9 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", "dev": true, "engines": { "node": ">=10" @@ -9299,9 +9305,9 @@ "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dependencies": { "loose-envify": "^1.1.0" }, @@ -9339,15 +9345,15 @@ } }, "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "dependencies": { "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.3.1" } }, "node_modules/react-is": { @@ -9778,9 +9784,9 @@ } }, "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "dependencies": { "loose-envify": "^1.1.0" } @@ -10842,9 +10848,9 @@ } }, "node_modules/vite": { - "version": "5.2.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.10.tgz", - "integrity": "sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==", + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz", + "integrity": "sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==", "dev": true, "dependencies": { "esbuild": "^0.20.1", @@ -10897,9 +10903,9 @@ } }, "node_modules/vite-node": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.2.tgz", - "integrity": "sha512-Y8p91kz9zU+bWtF7HGt6DVw2JbhyuB2RlZix3FPYAYmUyZ3n7iTp8eSyLyY6sxtPegvxQtmlTMhfPhUfCUF93A==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.3.tgz", + "integrity": "sha512-axFo00qiCpU/JLd8N1gu9iEYL3xTbMbMrbe5nDp9GL0nb6gurIdZLkkFogZXWnE8Oyy5kfSLwNVIcVsnhE7lgQ==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -10919,16 +10925,16 @@ } }, "node_modules/vitest": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.2.tgz", - "integrity": "sha512-l9gwIkq16ug3xY7BxHwcBQovLZG75zZL0PlsiYQbf76Rz6QGs54416UWMtC0jXeihvHvcHrf2ROEjkQRVpoZYw==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.3.tgz", + "integrity": "sha512-2oM7nLXylw3mQlW6GXnRriw+7YvZFk/YNV8AxIC3Z3MfFbuziLGWP9GPxxu/7nRlXhqyxBikpamr+lEEj1sUEw==", "dev": true, "dependencies": { - "@vitest/expect": "1.5.2", - "@vitest/runner": "1.5.2", - "@vitest/snapshot": "1.5.2", - "@vitest/spy": "1.5.2", - "@vitest/utils": "1.5.2", + "@vitest/expect": "1.5.3", + "@vitest/runner": "1.5.3", + "@vitest/snapshot": "1.5.3", + "@vitest/spy": "1.5.3", + "@vitest/utils": "1.5.3", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -10942,7 +10948,7 @@ "tinybench": "^2.5.1", "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.5.2", + "vite-node": "1.5.3", "why-is-node-running": "^2.2.2" }, "bin": { @@ -10957,8 +10963,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.5.2", - "@vitest/ui": "1.5.2", + "@vitest/browser": "1.5.3", + "@vitest/ui": "1.5.3", "happy-dom": "*", "jsdom": "*" }, diff --git a/client-next/package.json b/client-next/package.json index 0fe51abdad8..1677c6a3b1f 100644 --- a/client-next/package.json +++ b/client-next/package.json @@ -22,9 +22,9 @@ "graphql": "16.8.1", "graphql-request": "6.1.0", "maplibre-gl": "4.1.3", - "react": "18.2.0", + "react": "18.3.1", "react-bootstrap": "2.10.2", - "react-dom": "18.2.0", + "react-dom": "18.3.1", "react-map-gl": "7.1.7" }, "devDependencies": { @@ -32,24 +32,24 @@ "@graphql-codegen/client-preset": "4.2.5", "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.4.1", - "@testing-library/react": "15.0.4", - "@types/react": "18.2.79", - "@types/react-dom": "18.2.25", - "@typescript-eslint/eslint-plugin": "7.7.1", - "@typescript-eslint/parser": "7.7.1", + "@testing-library/react": "15.0.6", + "@types/react": "18.3.1", + "@types/react-dom": "18.3.0", + "@typescript-eslint/eslint-plugin": "7.8.0", + "@typescript-eslint/parser": "7.8.0", "@vitejs/plugin-react": "4.2.1", - "@vitest/coverage-v8": "1.5.2", + "@vitest/coverage-v8": "1.5.3", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "2.29.1", "eslint-plugin-jsx-a11y": "6.8.0", "eslint-plugin-react": "7.34.1", - "eslint-plugin-react-hooks": "4.6.0", + "eslint-plugin-react-hooks": "4.6.2", "eslint-plugin-react-refresh": "0.4.6", "jsdom": "24.0.0", "prettier": "3.2.5", "typescript": "5.4.5", - "vite": "5.2.10", - "vitest": "1.5.2" + "vite": "5.2.11", + "vitest": "1.5.3" } } From 5b3be61ac76eebbb04282643aa3d2d390730f20e Mon Sep 17 00:00:00 2001 From: OTP Bot Date: Thu, 2 May 2024 14:37:56 +0000 Subject: [PATCH 110/121] Upgrade debug client to version 2024/05/2024-05-02T14:37 --- src/client/debug-client-preview/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/debug-client-preview/index.html b/src/client/debug-client-preview/index.html index 853fee5b440..8968324b94d 100644 --- a/src/client/debug-client-preview/index.html +++ b/src/client/debug-client-preview/index.html @@ -5,8 +5,8 @@ OTP Debug Client - - + +
From ac85a45296ce257ba5247e71226da69b88f66cf5 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Thu, 2 May 2024 15:08:34 -0700 Subject: [PATCH 111/121] test: modify tests for Kitsap transit cash trasnfers --- .../ext/fares/impl/OrcaFareServiceTest.java | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java index 4d04281ebb6..7493c33bbb2 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java @@ -199,16 +199,11 @@ void calculateFareThatExceedsTwoHourFreeTransferWindow() { getLeg(KITSAP_TRANSIT_AGENCY_ID, 150) ); - var SIX_TIMES_DEFAULT = DEFAULT_TEST_RIDE_PRICE.times(6); - calculateFare(rides, regular, SIX_TIMES_DEFAULT); - calculateFare(rides, FareType.senior, SIX_TIMES_DEFAULT); + calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(2)); + calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(2)); calculateFare(rides, FareType.youth, ZERO_USD); calculateFare(rides, FareType.electronicSpecial, TWO_DOLLARS); - calculateFare( - rides, - FareType.electronicRegular, - DEFAULT_TEST_RIDE_PRICE.plus(DEFAULT_TEST_RIDE_PRICE) - ); + calculateFare(rides, FareType.electronicRegular, DEFAULT_TEST_RIDE_PRICE.times(2)); calculateFare(rides, FareType.electronicSenior, TWO_DOLLARS); calculateFare(rides, FareType.electronicYouth, ZERO_USD); } @@ -228,11 +223,11 @@ void calculateFareThatIncludesNoFreeTransfers() { getLeg(KITSAP_TRANSIT_AGENCY_ID, 121), getLeg(WASHINGTON_STATE_FERRIES_AGENCY_ID, 150, "Fauntleroy-VashonIsland") ); - calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(4).plus(FERRY_FARE)); + calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(3).plus(FERRY_FARE)); calculateFare( rides, FareType.senior, - DEFAULT_TEST_RIDE_PRICE.times(3).plus(usDollars(.50f)).plus(HALF_FERRY_FARE) + DEFAULT_TEST_RIDE_PRICE.times(2).plus(usDollars(.50f)).plus(HALF_FERRY_FARE) ); calculateFare(rides, FareType.youth, Money.ZERO_USD); // We don't get any fares for the skagit transit leg below here because they don't accept ORCA (electronic) @@ -267,8 +262,8 @@ void calculateFareThatExceedsTwoHourFreeTransferWindowTwice() { getLeg(KITSAP_TRANSIT_AGENCY_ID, 240), getLeg(KITSAP_TRANSIT_AGENCY_ID, 270) ); - calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(10)); - calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(10)); + calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(3)); + calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(3)); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare(rides, FareType.electronicSpecial, usDollars(3)); calculateFare(rides, FareType.electronicRegular, DEFAULT_TEST_RIDE_PRICE.times(3)); @@ -290,8 +285,8 @@ void calculateFareThatStartsWithACashFare() { getLeg(KITSAP_TRANSIT_AGENCY_ID, 120), getLeg(KITSAP_TRANSIT_AGENCY_ID, 149) ); - calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(6)); - calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(6)); + calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(2)); + calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(2)); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare(rides, FareType.electronicSpecial, DEFAULT_TEST_RIDE_PRICE.plus(ONE_DOLLAR)); calculateFare( @@ -424,16 +419,18 @@ void calculateSoundTransitBusFares() { } @Test - void calculateCashFreeTransferKCMetro() { + void calculateCashFreeTransferKCMetroAndKitsap() { List rides = List.of( getLeg(KC_METRO_AGENCY_ID, 0), getLeg(KC_METRO_AGENCY_ID, 20), getLeg(COMM_TRANS_AGENCY_ID, 45), getLeg(KC_METRO_AGENCY_ID, 60), - getLeg(KC_METRO_AGENCY_ID, 130) + getLeg(KC_METRO_AGENCY_ID, 130), + getLeg(KITSAP_TRANSIT_AGENCY_ID, 131), + getLeg(KITSAP_TRANSIT_AGENCY_ID, 132) ); - calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(3)); - calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(3)); + calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(4)); + calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(4)); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare(rides, FareType.electronicSpecial, usDollars(1.25f)); calculateFare(rides, FareType.electronicRegular, DEFAULT_TEST_RIDE_PRICE.times(2)); From b6a298207bfb004b98b7ba006dbe7ee86ec6c2ed Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Thu, 2 May 2024 15:09:58 -0700 Subject: [PATCH 112/121] implement new transfer logic for Kitsap transit --- .../ext/fares/impl/OrcaFareService.java | 148 ++++++++++-------- 1 file changed, 82 insertions(+), 66 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java b/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java index a02f37417ec..16e8791cd5f 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java @@ -7,6 +7,7 @@ import java.time.ZonedDateTime; import java.util.Collection; import java.util.Currency; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -23,6 +24,7 @@ import org.opentripplanner.transit.model.basic.Money; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.network.Route; +import org.opentripplanner.transit.model.organization.Agency; public class OrcaFareService extends DefaultFareService { @@ -50,6 +52,12 @@ public class OrcaFareService extends DefaultFareService { "cash" ); + protected enum TransferType { + ORCA_INTERAGENCY_TRANSFER, + SAME_AGENCY_TRANSFER, + NO_TRANSFER, + } + protected enum RideType { COMM_TRANS_LOCAL_SWIFT, COMM_TRANS_COMMUTER_EXPRESS, @@ -75,12 +83,25 @@ protected enum RideType { SKAGIT_CROSS_COUNTY, UNKNOWN; + public TransferType getTransferType(FareType fareType) { + if (usesOrca(fareType) && this.permitsFreeTransfers()) { + return TransferType.ORCA_INTERAGENCY_TRANSFER; + } else if (this == KC_METRO || this == KITSAP_TRANSIT) { + return TransferType.SAME_AGENCY_TRANSFER; + } + return TransferType.NO_TRANSFER; + } + /** * All transit agencies permit free transfers, apart from these. */ public boolean permitsFreeTransfers() { return switch (this) { - case WASHINGTON_STATE_FERRIES, SKAGIT_TRANSIT -> false; + case WASHINGTON_STATE_FERRIES, + SKAGIT_TRANSIT, + WHATCOM_LOCAL, + WHATCOM_CROSS_COUNTY, + SKAGIT_CROSS_COUNTY -> false; default -> true; }; } @@ -93,6 +114,46 @@ public boolean agencyAcceptsOrca() { } } + static class TransferData { + + Money transferDiscount; + ZonedDateTime transferStartTime; + + FareType fareType; + + public TransferData(FareType fareType) { + this.fareType = fareType; + } + + public Money getDiscountedLegPrice(Leg leg, Money legPrice) { + if (transferStartTime != null) { + var inFreeTransferWindow = inFreeTransferWindow(transferStartTime, leg.getStartTime()); + if (inFreeTransferWindow) { + if (legPrice.greaterThan(transferDiscount)) { + this.transferStartTime = leg.getStartTime(); + var discountedLegFare = legPrice.minus(this.transferDiscount); + this.transferDiscount = legPrice; + return discountedLegFare; + } + return Money.ZERO_USD; + } + } + // Start a new transfer + this.transferDiscount = legPrice; + this.transferStartTime = leg.getStartTime(); + return legPrice; + } + + public void update(Money transferDiscount, ZonedDateTime transferStartTime) { + this.transferDiscount = transferDiscount; + this.transferStartTime = transferStartTime; + } + + public void update(Money transferDiscount) { + this.transferDiscount = transferDiscount; + } + } + /** * Categorizes a leg based on various parameters. * The classifications determine the various rules and fares applied to the leg. @@ -403,17 +464,14 @@ public ItineraryFares calculateFaresForType( Collection fareRules ) { var fare = ItineraryFares.empty(); - ZonedDateTime freeTransferStartTime = null; Money cost = Money.ZERO_USD; - Money orcaFareDiscount = Money.ZERO_USD; + var orcaFareDiscount = new TransferData(fareType); + HashMap perAgencyTransferDiscount = new HashMap<>(); + for (Leg leg : legs) { RideType rideType = getRideType(leg); assert rideType != null; boolean ridePermitsFreeTransfers = rideType.permitsFreeTransfers(); - if (freeTransferStartTime == null && ridePermitsFreeTransfers) { - // The start of a free transfer must be with a transit agency that permits it! - freeTransferStartTime = leg.getStartTime(); - } Optional singleLegPrice = getRidePrice(leg, FareType.regular, fareRules); Optional optionalLegFare = singleLegPrice.flatMap(slp -> getLegFare(fareType, rideType, slp, leg) @@ -424,61 +482,30 @@ public ItineraryFares calculateFaresForType( } Money legFare = optionalLegFare.get(); - boolean inFreeTransferWindow = inFreeTransferWindow( - freeTransferStartTime, - leg.getStartTime() - ); - if (hasFreeTransfers(fareType, rideType) && inFreeTransferWindow) { - // If using Orca (free transfers), the total fare should be equivalent to the - // most expensive leg of the journey. - // If the new fare is more than the current ORCA amount, the transfer is extended. - if (legFare.greaterThan(orcaFareDiscount)) { - freeTransferStartTime = leg.getStartTime(); - // Note: on first leg, discount will be 0 meaning no transfer was applied. - addLegFareProduct(leg, fare, fareType, legFare.minus(orcaFareDiscount), orcaFareDiscount); - orcaFareDiscount = legFare; - } else { - // Ride is free, counts as a transfer if legFare is NOT free - addLegFareProduct( - leg, - fare, - fareType, - Money.ZERO_USD, - legFare.isPositive() ? orcaFareDiscount : Money.ZERO_USD - ); - } - } else if (usesOrca(fareType) && !inFreeTransferWindow) { - // If using Orca and outside of the free transfer window, add the cumulative Orca fare (the maximum leg - // fare encountered within the free transfer window). - cost = cost.plus(orcaFareDiscount); - - // Reset the free transfer start time and next Orca fare as needed. - if (ridePermitsFreeTransfers) { - // The leg is using a ride type that permits free transfers. - // The next free transfer window begins at the start time of this leg. - freeTransferStartTime = leg.getStartTime(); - // Reset the Orca fare to be the fare of this leg. - orcaFareDiscount = legFare; + var transferType = rideType.getTransferType(fareType); + if (transferType == TransferType.ORCA_INTERAGENCY_TRANSFER) { + var discountedFare = orcaFareDiscount.getDiscountedLegPrice(leg, legFare); + var transferDiscount = legFare.minus(discountedFare); + addLegFareProduct(leg, fare, fareType, discountedFare, transferDiscount); + cost = cost.plus(discountedFare); + } else if (transferType == TransferType.SAME_AGENCY_TRANSFER) { + TransferData transferData; + if (perAgencyTransferDiscount.containsKey(leg.getAgency().getName())) { + transferData = perAgencyTransferDiscount.get(leg.getAgency().getName()); } else { - // The leg is not using a ride type that permits free transfers. - // Since there are no free transfers for this leg, increase the total cost by the fare for this leg. - cost = cost.plus(legFare); - // The current free transfer window has expired and won't start again until another leg is - // encountered that does have free transfers. - freeTransferStartTime = null; - // The previous Orca fare has been applied to the total cost. Also, the non-free transfer cost has - // also been applied to the total cost. Therefore, the next Orca cost for the next free-transfer - // window needs to be reset to 0 so that it is not applied after looping through all rides. - orcaFareDiscount = Money.ZERO_USD; + transferData = new TransferData(fareType); + perAgencyTransferDiscount.put(leg.getAgency().getName(), transferData); } - addLegFareProduct(leg, fare, fareType, legFare, Money.ZERO_USD); + var discountedFare = transferData.getDiscountedLegPrice(leg, legFare); + var transferDiscount = legFare.minus(discountedFare); + addLegFareProduct(leg, fare, fareType, discountedFare, transferDiscount); + cost = cost.plus(discountedFare); } else { // If not using Orca, add the agency's default price for this leg. addLegFareProduct(leg, fare, fareType, legFare, Money.ZERO_USD); cost = cost.plus(legFare); } } - cost = cost.plus(orcaFareDiscount); if (cost.fractionalAmount().floatValue() < Float.MAX_VALUE) { var fp = FareProduct .of(new FeedScopedId(FEED_ID, fareType.name()), fareType.name(), cost) @@ -552,7 +579,7 @@ protected Map> fareLegsByFeed(List fareLegs) { /** * Check if trip falls within the transfer time window. */ - private boolean inFreeTransferWindow( + private static boolean inFreeTransferWindow( ZonedDateTime freeTransferStartTime, ZonedDateTime currentLegStartTime ) { @@ -562,17 +589,6 @@ private boolean inFreeTransferWindow( return duration.compareTo(MAX_TRANSFER_DISCOUNT_DURATION) < 0; } - /** - * A free transfer can be applied if using Orca and the transit agency permits free transfers. - */ - private boolean hasFreeTransfers(FareType fareType, RideType rideType) { - // King County Metro allows transfers on cash fare - return ( - (rideType.permitsFreeTransfers() && usesOrca(fareType)) || - (rideType == RideType.KC_METRO && !usesOrca(fareType)) - ); - } - /** * Define Orca fare types. */ From b5f6a708e1148ad1fdee0eee575748f5ee99cbd7 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Fri, 3 May 2024 13:23:03 -0700 Subject: [PATCH 113/121] orca fares: general cleanup and fix for xfer value --- .../ext/fares/impl/OrcaFareService.java | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java b/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java index 16e8791cd5f..8e2118c0800 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java @@ -1,5 +1,6 @@ package org.opentripplanner.ext.fares.impl; +import static org.opentripplanner.transit.model.basic.Money.ZERO_USD; import static org.opentripplanner.transit.model.basic.Money.usDollars; import com.google.common.collect.Lists; @@ -116,13 +117,14 @@ public boolean agencyAcceptsOrca() { static class TransferData { - Money transferDiscount; - ZonedDateTime transferStartTime; + private Money transferDiscount; + private ZonedDateTime transferStartTime; - FareType fareType; - - public TransferData(FareType fareType) { - this.fareType = fareType; + public Money getTransferDiscount() { + if (this.transferDiscount == null) { + return ZERO_USD; + } + return this.transferDiscount; } public Money getDiscountedLegPrice(Leg leg, Money legPrice) { @@ -143,15 +145,6 @@ public Money getDiscountedLegPrice(Leg leg, Money legPrice) { this.transferStartTime = leg.getStartTime(); return legPrice; } - - public void update(Money transferDiscount, ZonedDateTime transferStartTime) { - this.transferDiscount = transferDiscount; - this.transferStartTime = transferStartTime; - } - - public void update(Money transferDiscount) { - this.transferDiscount = transferDiscount; - } } /** @@ -465,13 +458,12 @@ public ItineraryFares calculateFaresForType( ) { var fare = ItineraryFares.empty(); Money cost = Money.ZERO_USD; - var orcaFareDiscount = new TransferData(fareType); + var orcaFareDiscount = new TransferData(); HashMap perAgencyTransferDiscount = new HashMap<>(); for (Leg leg : legs) { RideType rideType = getRideType(leg); assert rideType != null; - boolean ridePermitsFreeTransfers = rideType.permitsFreeTransfers(); Optional singleLegPrice = getRidePrice(leg, FareType.regular, fareRules); Optional optionalLegFare = singleLegPrice.flatMap(slp -> getLegFare(fareType, rideType, slp, leg) @@ -484,21 +476,34 @@ public ItineraryFares calculateFaresForType( var transferType = rideType.getTransferType(fareType); if (transferType == TransferType.ORCA_INTERAGENCY_TRANSFER) { + // Important to get transfer discount before calculating next leg price + var transferDiscount = orcaFareDiscount.getTransferDiscount(); var discountedFare = orcaFareDiscount.getDiscountedLegPrice(leg, legFare); - var transferDiscount = legFare.minus(discountedFare); - addLegFareProduct(leg, fare, fareType, discountedFare, transferDiscount); + addLegFareProduct( + leg, + fare, + fareType, + discountedFare, + legFare.greaterThan(ZERO_USD) ? transferDiscount : ZERO_USD + ); cost = cost.plus(discountedFare); } else if (transferType == TransferType.SAME_AGENCY_TRANSFER) { TransferData transferData; if (perAgencyTransferDiscount.containsKey(leg.getAgency().getName())) { transferData = perAgencyTransferDiscount.get(leg.getAgency().getName()); } else { - transferData = new TransferData(fareType); + transferData = new TransferData(); perAgencyTransferDiscount.put(leg.getAgency().getName(), transferData); } + var transferDiscount = transferData.transferDiscount; var discountedFare = transferData.getDiscountedLegPrice(leg, legFare); - var transferDiscount = legFare.minus(discountedFare); - addLegFareProduct(leg, fare, fareType, discountedFare, transferDiscount); + addLegFareProduct( + leg, + fare, + fareType, + discountedFare, + legFare.greaterThan(ZERO_USD) ? transferDiscount : ZERO_USD + ); cost = cost.plus(discountedFare); } else { // If not using Orca, add the agency's default price for this leg. From e33d710875a908c17d6cc0e06818290d1ba7b109 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Fri, 3 May 2024 13:30:58 -0700 Subject: [PATCH 114/121] fix(orca-fares): use getter for transfer discount --- .../org/opentripplanner/ext/fares/impl/OrcaFareService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java b/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java index 8e2118c0800..8f961b0b01b 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java @@ -495,7 +495,7 @@ public ItineraryFares calculateFaresForType( transferData = new TransferData(); perAgencyTransferDiscount.put(leg.getAgency().getName(), transferData); } - var transferDiscount = transferData.transferDiscount; + var transferDiscount = transferData.getTransferDiscount(); var discountedFare = transferData.getDiscountedLegPrice(leg, legFare); addLegFareProduct( leg, From b47dfe8e6eb09b71cb9d0b53ab2b8fd50fa7fd9b Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Mon, 6 May 2024 11:39:00 +0000 Subject: [PATCH 115/121] Add changelog entry for #5826 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 2ba638c9ab1..ff97b7c822b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -17,6 +17,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Optionally abort startup when unknown configuration parameters were detected [#5676](https://github.com/opentripplanner/OpenTripPlanner/pull/5676) - Fix bug in heuristics cost calculation for egress legs [#5783](https://github.com/opentripplanner/OpenTripPlanner/pull/5783) - De-emphasize mailing list in landing page [#5820](https://github.com/opentripplanner/OpenTripPlanner/pull/5820) +- ORCA Fares: Add free cash transfers for Kitsap transit [#5826](https://github.com/opentripplanner/OpenTripPlanner/pull/5826) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.5.0 (2024-03-13) From 51f466f88e944faf2eb6a3a84be84936c5d55bf6 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 6 May 2024 13:41:44 +0200 Subject: [PATCH 116/121] Clean up changelog [ci skip] --- README.md | 2 +- docs/Changelog.md | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 5e016c22bb2..4a5fa77c7ee 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Overview [![Join the chat at https://gitter.im/opentripplanner/OpenTripPLanner](https://badges.gitter.im/opentripplanner/OpenTripPlanner.svg)](https://gitter.im/opentripplanner/OpenTripPlanner) -[![Matrix](https://img.shields.io/matrix/opentripplanner%3Amatrix.org?label=Matrix%20chat)](https://matrix.to/#/#opentripplanner_OpenTripPlanner:gitter.im) +[![Matrix](https://img.shields.io/matrix/opentripplanner%3Amatrix.org?label=Matrix%20chat&?cacheSeconds=172800)](https://matrix.to/#/#opentripplanner_OpenTripPlanner:gitter.im) [![codecov](https://codecov.io/gh/opentripplanner/OpenTripPlanner/branch/dev-2.x/graph/badge.svg?token=ak4PbIKgZ1)](https://codecov.io/gh/opentripplanner/OpenTripPlanner) [![Commit activity](https://img.shields.io/github/commit-activity/y/opentripplanner/OpenTripPlanner)](https://github.com/opentripplanner/OpenTripPlanner/graphs/contributors) [![Docker Pulls](https://img.shields.io/docker/pulls/opentripplanner/opentripplanner)](https://hub.docker.com/r/opentripplanner/opentripplanner) diff --git a/docs/Changelog.md b/docs/Changelog.md index ff97b7c822b..cafc677ccc6 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -16,8 +16,6 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Fix trip duplication in Graph Builder DSJ mapping [#5794](https://github.com/opentripplanner/OpenTripPlanner/pull/5794) - Optionally abort startup when unknown configuration parameters were detected [#5676](https://github.com/opentripplanner/OpenTripPlanner/pull/5676) - Fix bug in heuristics cost calculation for egress legs [#5783](https://github.com/opentripplanner/OpenTripPlanner/pull/5783) -- De-emphasize mailing list in landing page [#5820](https://github.com/opentripplanner/OpenTripPlanner/pull/5820) -- ORCA Fares: Add free cash transfers for Kitsap transit [#5826](https://github.com/opentripplanner/OpenTripPlanner/pull/5826) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.5.0 (2024-03-13) From b1d36f902aaacd1ca4fbe46120155e119ba793e1 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 6 May 2024 17:22:46 +0200 Subject: [PATCH 117/121] Update accessibility score docs [ci skip] --- docs/sandbox/IBIAccessibilityScore.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/sandbox/IBIAccessibilityScore.md b/docs/sandbox/IBIAccessibilityScore.md index e3c6ef16bbd..5b944eaf73b 100644 --- a/docs/sandbox/IBIAccessibilityScore.md +++ b/docs/sandbox/IBIAccessibilityScore.md @@ -1,14 +1,9 @@ -# IBI Group Accessibility Score - OTP Sandbox Extension +# IBI Group Accessibility Score ## Contact Info - IBI Group ([transitrealtime@ibigroup.com](mailto:transitrealtime@ibigroup.com)) -## Changelog - -- Create initial - implementation [#4221](https://github.com/opentripplanner/OpenTripPlanner/pull/4221) - ## Documentation This extension computes a numeric accessibility score between 0 and 1 and adds it to the itinerary @@ -32,4 +27,8 @@ To enable the feature add the following to `router-config.json`: } ``` -The score is only computed when you search for wheelchair-accessible routes. \ No newline at end of file +The score is only computed when you search for wheelchair-accessible routes. + +## Changelog + +- Create initial implementation [#4221](https://github.com/opentripplanner/OpenTripPlanner/pull/4221) From 90148e089134c2289f1d6310bb50cf1645f0d000 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 6 May 2024 17:41:19 +0200 Subject: [PATCH 118/121] Update docs about experimental fields --- doc-templates/Flex.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc-templates/Flex.md b/doc-templates/Flex.md index 50512f66133..0e79ecdbffc 100644 --- a/doc-templates/Flex.md +++ b/doc-templates/Flex.md @@ -13,6 +13,17 @@ To enable this turn on `FlexRouting` as a feature in `otp-config.json`. The GTFS feeds must conform to the final, approved version of the draft which has been merged into the [mainline specification](https://gtfs.org/schedule/reference/) in March 2024. +### Experimental features + +This sandbox feature also has experimental support for the following fields: + +- `safe_duration_factor` +- `safe_duration_offset` + +These features are currently [undergoing specification](https://github.com/MobilityData/gtfs-flex/pull/79) +and their definition might change. OTP's implementation will be also be changed so be careful +when relying on this feature. + ## Configuration This feature allows a limited number of config options. To change the configuration, add the From a4dc25b7d635ec872e4843d23d7ab1533f662249 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 6 May 2024 17:46:16 +0200 Subject: [PATCH 119/121] Revert renaming --- docs/sandbox/Flex.md | 11 +++++++++++ .../ext/flex/trip/ScheduledDeviatedTrip.java | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/sandbox/Flex.md b/docs/sandbox/Flex.md index 277e4e617f2..7b08fd7d05f 100644 --- a/docs/sandbox/Flex.md +++ b/docs/sandbox/Flex.md @@ -13,6 +13,17 @@ To enable this turn on `FlexRouting` as a feature in `otp-config.json`. The GTFS feeds must conform to the final, approved version of the draft which has been merged into the [mainline specification](https://gtfs.org/schedule/reference/) in March 2024. +### Experimental features + +This sandbox feature also has experimental support for the following fields: + +- `safe_duration_factor` +- `safe_duration_offset` + +These features are currently [undergoing specification](https://github.com/MobilityData/gtfs-flex/pull/79) +and their definition might change. OTP's implementation will be also be changed so be careful +when relying on this feature. + ## Configuration This feature allows a limited number of config options. To change the configuration, add the diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java index 0026d98c964..e16e1e5e1f7 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java @@ -176,7 +176,7 @@ public int earliestDepartureTime(int stopIndex) { @Override public int latestArrivalTime( int arrivalTime, - int ignored, + int fromStopIndex, int toStopIndex, int flexTripDurationSeconds ) { From ea679755a77beb05536b5c163f174141f62fbd72 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 8 May 2024 13:02:43 +0200 Subject: [PATCH 120/121] Remove extra collection conversion --- src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java index 76a13255b67..5347e7504c5 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java @@ -33,8 +33,7 @@ public class FlexTripsMapper { ProgressTracker progress = ProgressTracker.track("Create flex trips", 500, tripSize); for (Trip trip : stopTimesByTrip.keys()) { - /* Fetch the stop times for this trip. Copy the list since it's immutable. */ - List stopTimes = new ArrayList<>(stopTimesByTrip.get(trip)); + var stopTimes = stopTimesByTrip.get(trip); if (UnscheduledTrip.isUnscheduledTrip(stopTimes)) { var modifier = builder.getFlexDurationFactors().getOrDefault(trip, TimePenalty.ZERO); result.add( From 695161a86c82dbbeed34140417d071df55823191 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 8 May 2024 13:25:53 +0200 Subject: [PATCH 121/121] Rename modifiers/factors to time penalty --- ...rTest.java => TimePenaltyCalculatorTest.java} | 6 +++--- .../trip/UnscheduledDrivingDurationTest.java | 6 +++--- .../ext/flex/FlexTripsMapper.java | 4 ++-- ...alculator.java => TimePenaltyCalculator.java} | 4 ++-- .../ext/flex/trip/UnscheduledTrip.java | 16 ++++++++++------ .../ext/flex/trip/UnscheduledTripBuilder.java | 10 +++++----- .../mapping/GTFSToOtpTransitServiceMapper.java | 2 +- .../model/impl/OtpTransitServiceBuilder.java | 2 +- .../api/request/framework/TimePenalty.java | 8 ++++++++ .../api/request/framework/TimePenaltyTest.java | 7 +++++++ 10 files changed, 42 insertions(+), 23 deletions(-) rename src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/{DurationModifierCalculatorTest.java => TimePenaltyCalculatorTest.java} (88%) rename src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/{DurationModifierCalculator.java => TimePenaltyCalculator.java} (83%) diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculatorTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/TimePenaltyCalculatorTest.java similarity index 88% rename from src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculatorTest.java rename to src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/TimePenaltyCalculatorTest.java index a97460dda75..e504f8ac762 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculatorTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/flexpathcalculator/TimePenaltyCalculatorTest.java @@ -9,7 +9,7 @@ import org.opentripplanner.routing.api.request.framework.TimePenalty; import org.opentripplanner.street.model._data.StreetModelForTest; -class DurationModifierCalculatorTest { +class TimePenaltyCalculatorTest { private static final int THIRTY_MINS_IN_SECONDS = (int) Duration.ofMinutes(30).toSeconds(); @@ -19,7 +19,7 @@ void calculate() { new FlexPath(10_000, THIRTY_MINS_IN_SECONDS, () -> LineStrings.SIMPLE); var mod = TimePenalty.of(Duration.ofMinutes(10), 1.5f); - var calc = new DurationModifierCalculator(delegate, mod); + var calc = new TimePenaltyCalculator(delegate, mod); var path = calc.calculateFlexPath(StreetModelForTest.V1, StreetModelForTest.V2, 0, 5); assertEquals(3300, path.durationSeconds); } @@ -28,7 +28,7 @@ void calculate() { void nullValue() { FlexPathCalculator delegate = (fromv, tov, fromStopIndex, toStopIndex) -> null; var mod = TimePenalty.of(Duration.ofMinutes(10), 1.5f); - var calc = new DurationModifierCalculator(delegate, mod); + var calc = new TimePenaltyCalculator(delegate, mod); var path = calc.calculateFlexPath(StreetModelForTest.V1, StreetModelForTest.V2, 0, 5); assertNull(path); } diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledDrivingDurationTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledDrivingDurationTest.java index bd06a51960b..a4b245b7de8 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledDrivingDurationTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/trip/UnscheduledDrivingDurationTest.java @@ -22,7 +22,7 @@ class UnscheduledDrivingDurationTest { private static final StopTime STOP_TIME = FlexStopTimesForTest.area("10:00", "18:00"); @Test - void noModifier() { + void noPenalty() { var trip = UnscheduledTrip.of(id("1")).withStopTimes(List.of(STOP_TIME)).build(); var calculator = trip.flexPathCalculator(STATIC_CALCULATOR); @@ -31,11 +31,11 @@ void noModifier() { } @Test - void withModifier() { + void withPenalty() { var trip = UnscheduledTrip .of(id("1")) .withStopTimes(List.of(STOP_TIME)) - .withDurationModifier(TimePenalty.of(Duration.ofMinutes(2), 1.5f)) + .withTimePenalty(TimePenalty.of(Duration.ofMinutes(2), 1.5f)) .build(); var calculator = trip.flexPathCalculator(STATIC_CALCULATOR); diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java index 5347e7504c5..c4167f2f9e1 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java @@ -35,13 +35,13 @@ public class FlexTripsMapper { for (Trip trip : stopTimesByTrip.keys()) { var stopTimes = stopTimesByTrip.get(trip); if (UnscheduledTrip.isUnscheduledTrip(stopTimes)) { - var modifier = builder.getFlexDurationFactors().getOrDefault(trip, TimePenalty.ZERO); + var timePenalty = builder.getFlexTimePenalty().getOrDefault(trip, TimePenalty.NONE); result.add( UnscheduledTrip .of(trip.getId()) .withTrip(trip) .withStopTimes(stopTimes) - .withDurationModifier(modifier) + .withTimePenalty(timePenalty) .build() ); } else if (ScheduledDeviatedTrip.isScheduledFlexTrip(stopTimes)) { diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculator.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/TimePenaltyCalculator.java similarity index 83% rename from src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculator.java rename to src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/TimePenaltyCalculator.java index 0f521b55b1f..63b661f0f9a 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DurationModifierCalculator.java +++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/TimePenaltyCalculator.java @@ -8,12 +8,12 @@ * A calculator to delegates the main computation to another instance and applies a duration * modifier afterward. */ -public class DurationModifierCalculator implements FlexPathCalculator { +public class TimePenaltyCalculator implements FlexPathCalculator { private final FlexPathCalculator delegate; private final TimePenalty factors; - public DurationModifierCalculator(FlexPathCalculator delegate, TimePenalty penalty) { + public TimePenaltyCalculator(FlexPathCalculator delegate, TimePenalty penalty) { this.delegate = delegate; this.factors = penalty; } diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java index 7fa31c78114..402d39e2aa7 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java @@ -15,11 +15,13 @@ import java.util.stream.Stream; import javax.annotation.Nonnull; import org.opentripplanner.ext.flex.FlexServiceDate; -import org.opentripplanner.ext.flex.flexpathcalculator.DurationModifierCalculator; import org.opentripplanner.ext.flex.flexpathcalculator.FlexPathCalculator; +import org.opentripplanner.ext.flex.flexpathcalculator.TimePenaltyCalculator; import org.opentripplanner.ext.flex.template.FlexAccessTemplate; import org.opentripplanner.ext.flex.template.FlexEgressTemplate; +import org.opentripplanner.framework.lang.DoubleUtils; import org.opentripplanner.framework.lang.IntRange; +import org.opentripplanner.framework.time.DurationUtils; import org.opentripplanner.model.BookingInfo; import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.StopTime; @@ -53,7 +55,7 @@ public class UnscheduledTrip extends FlexTrip getFlexAccessTemplates( } /** - * Get the correct {@link FlexPathCalculator} depending on the {@code durationModifier}. + * Get the correct {@link FlexPathCalculator} depending on the {@code timePenalty}. * If the modifier doesn't actually modify, we return the regular calculator. */ protected FlexPathCalculator flexPathCalculator(FlexPathCalculator calculator) { - if (!durationModifier.isZero()) { - return new DurationModifierCalculator(calculator, durationModifier); + if (timePenalty.modifies()) { + return new TimePenaltyCalculator(calculator, timePenalty); } else { return calculator; } diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java index cfffebe4fa7..1f8585f5ad0 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTripBuilder.java @@ -9,7 +9,7 @@ public class UnscheduledTripBuilder extends FlexTripBuilder { private List stopTimes; - private TimePenalty durationModifier = TimePenalty.ZERO; + private TimePenalty timePenalty = TimePenalty.NONE; UnscheduledTripBuilder(FeedScopedId id) { super(id); @@ -31,13 +31,13 @@ public List stopTimes() { return stopTimes; } - public UnscheduledTripBuilder withDurationModifier(TimePenalty factors) { - this.durationModifier = factors; + public UnscheduledTripBuilder withTimePenalty(TimePenalty factors) { + this.timePenalty = factors; return this; } - public TimePenalty durationModifier() { - return durationModifier; + public TimePenalty timePenalty() { + return timePenalty; } @Override diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java index 24db367f829..ce65d6b0820 100644 --- a/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java +++ b/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java @@ -171,7 +171,7 @@ public void mapStopTripAndRouteDataIntoBuilder() { builder.getPathways().addAll(pathwayMapper.map(data.getAllPathways())); builder.getStopTimesSortedByTrip().addAll(stopTimeMapper.map(data.getAllStopTimes())); - builder.getFlexDurationFactors().putAll(tripMapper.flexSafeDurationModifiers()); + builder.getFlexTimePenalty().putAll(tripMapper.flexSafeDurationModifiers()); builder.getTripsById().addAll(tripMapper.map(data.getAllTrips())); fareRulesBuilder.fareAttributes().addAll(fareAttributeMapper.map(data.getAllFareAttributes())); diff --git a/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java b/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java index 756a1ccf2a8..544ca29599d 100644 --- a/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java +++ b/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java @@ -213,7 +213,7 @@ public TripStopTimes getStopTimesSortedByTrip() { return stopTimesByTrip; } - public Map getFlexDurationFactors() { + public Map getFlexTimePenalty() { return flexDurationFactors; } diff --git a/src/main/java/org/opentripplanner/routing/api/request/framework/TimePenalty.java b/src/main/java/org/opentripplanner/routing/api/request/framework/TimePenalty.java index aaa81db5a09..0c6fdd96436 100644 --- a/src/main/java/org/opentripplanner/routing/api/request/framework/TimePenalty.java +++ b/src/main/java/org/opentripplanner/routing/api/request/framework/TimePenalty.java @@ -7,6 +7,7 @@ public final class TimePenalty extends AbstractLinearFunction { public static final TimePenalty ZERO = new TimePenalty(Duration.ZERO, 0.0); + public static final TimePenalty NONE = new TimePenalty(Duration.ZERO, 1.0); private TimePenalty(Duration constant, double coefficient) { super(DurationUtils.requireNonNegative(constant), coefficient); @@ -31,6 +32,13 @@ protected boolean isZero(Duration value) { return value.isZero(); } + /** + * Does this penalty actually modify a duration or would it be returned unchanged? + */ + public boolean modifies() { + return !constant().isZero() && coefficient() != 1.0; + } + @Override protected Duration constantAsDuration() { return constant(); diff --git a/src/test/java/org/opentripplanner/routing/api/request/framework/TimePenaltyTest.java b/src/test/java/org/opentripplanner/routing/api/request/framework/TimePenaltyTest.java index f5bffe1f415..087ffa1d637 100644 --- a/src/test/java/org/opentripplanner/routing/api/request/framework/TimePenaltyTest.java +++ b/src/test/java/org/opentripplanner/routing/api/request/framework/TimePenaltyTest.java @@ -64,4 +64,11 @@ void calculate() { var subject = TimePenalty.of(D2m, 0.5); assertEquals(120 + 150, subject.calculate(Duration.ofMinutes(5)).toSeconds()); } + + @Test + void modifies() { + var subject = TimePenalty.of(D2m, 0.5); + assertTrue(subject.modifies()); + assertFalse(TimePenalty.ZERO.modifies()); + } }